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.

Easy Python 3.9+ Aug 9, 2026 Observability & SRE 14 views 0 copies

Python code

30 lines
Python 3.9+
from 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

stdout
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

  1. Use `unittest.mock.patch.dict` to patch the dictionary instead of a custom context manager.
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Observability & SRE

Related tutorials and quizzes for this topic.