How to Mock Service Resource Attributes in Python
Temporarily override service name, version, and other resource attributes with a context manager, then restore them automatically.
Python code
30 linesfrom contextlib import contextmanager
import random
_SERVICE_ATTRIBUTES = {
"service.name": "payment-api",
"service.version": "1.4.2",
"service.instance.id": str(random.randint(10000, 99999)),
"service.namespace": "production",
}
@contextmanager
def mock_service_attributes(**overrides):
"""Temporarily mock service resource attributes."""
original = dict(_SERVICE_ATTRIBUTES)
_SERVICE_ATTRIBUTES.update(overrides)
try:
yield _SERVICE_ATTRIBUTES
finally:
_SERVICE_ATTRIBUTES.clear()
_SERVICE_ATTRIBUTES.update(original)
def get_service_attributes():
"""Return a copy of the current service attributes."""
return dict(_SERVICE_ATTRIBUTES)
if __name__ == "__main__":
print("Default:", get_service_attributes())
with mock_service_attributes(service.name="checkout-api", service.version="2.0.0"):
print("Mocked: ", get_service_attributes())
print("Restored:", get_service_attributes())
Output
Default: {'service.name': 'payment-api', 'service.version': '1.4.2', 'service.instance.id': '53721', 'service.namespace': 'production'}
Mocked: {'service.name': 'checkout-api', 'service.version': '2.0.0', 'service.instance.id': '53721', 'service.namespace': 'production'}
Restored: {'service.name': 'payment-api', 'service.version': '1.4.2', 'service.instance.id': '53721', 'service.namespace': 'production'}
How it works
The @contextmanager decorator turns a generator function into a context manager. When you enter the with block, the code before yield runs, updating the shared _SERVICE_ATTRIBUTES dictionary with any overrides. The yield exposes the dictionary to the block. When the block exits — even on an exception — the finally clause restores the original attributes, ensuring no state leaks. Because the dictionary is module-level, all code that calls get_service_attributes() sees the mocked values during the block, making it easy to test or simulate different service identities.
Common mistakes
- Forgetting that overrides replace the entire key, so specify all attributes you want changed in the `with` statement.
- Modifying the dictionary returned by `get_service_attributes()` directly; it returns a copy, so changes don't affect the original.
- Not using `finally` in a custom context manager if you write one — you must restore state even when an exception is raised.
Variations
- Use `unittest.mock.patch.dict` to patch the dictionary instead of a custom context manager.
- Implement the context manager as a class with `__enter__` and `__exit__` methods if you need more control.
Real-world use cases
- Testing that telemetry exporters tag metrics and traces with the correct service name and version in staging vs production.
- Simulating multi-tenant scenarios where service attributes change per request to verify dashboards and alerts use the right resource labels.
- Switching a service's identity dynamically during feature flag testing without restarting the process.
Sponsored
More from Observability & SRE
- Adding a Correlation ID to Log Context in Python medium
- Calculate Error Rate from Log Stream in Python easy
- Check if a Timestamp Falls in a Daily Maintenance Window in Python easy
- Export Metrics with OTLP Mock in Python medium
- Generate Mock CPU and Memory Metrics in Python easy
- Generate Prometheus Text Exposition Format in Python easy
Keep learning
Related tutorials and quizzes for this topic.