Contrib Helpers

View as Markdown

nemo.lens.contrib contains framework-specific integration helpers. Each is optional and isolated, so installing NeMo Lens without the corresponding extra raises a clear ImportError (with an install hint) when you call the helper, not when you import it.

FastAPI with contrib.fastapi

1from nemo.lens.contrib.fastapi import instrument_fastapi
2
3app = FastAPI()
4instrument_fastapi(app)

Wraps opentelemetry-instrumentation-fastapi. After this call, every incoming HTTP request gets a span covering its lifetime, with W3C trace context automatically extracted from request headers (so upstream traces flow through).

instrument_fastapi does accept a service_name parameter, but it is currently a no-op (the implementation ignores it). The service name is set through setup_telemetry or the OTEL_SERVICE_NAME environment variable, not here.

Install: pip install 'nemo-lens[fastapi]'

Typical Integration

Gate on a span group so FastAPI spans respect your telemetry toggles:

1from nemo.lens.state import is_span_group_enabled
2
3if is_span_group_enabled('server'):
4 instrument_fastapi(app)

aiohttp Client with contrib.aiohttp

1from nemo.lens.contrib.aiohttp import instrument_aiohttp_client
2
3instrument_aiohttp_client()
4# After this, every aiohttp ClientSession request has W3C context injected automatically.

Wraps opentelemetry-instrumentation-aiohttp-client. Eliminates the need to manually call inject_context(kwargs['headers']) on every outbound HTTP call.

Install: pip install 'nemo-lens[aiohttp]'

Choose When to Call the Helper

Call this helper once at startup, after setup_telemetry returns and confirms you are actively exporting:

1handle = setup_telemetry(config)
2if handle.is_exporting:
3 instrument_aiohttp_client()

Avoid running this helper on non-exporting ranks to prevent unnecessary overhead.

Ray with contrib.ray

Ray remote calls do not carry HTTP headers, so trace context must be passed explicitly. NeMo Lens exposes helpers that add a conventional _otel_carrier kwarg to remote calls.

Instrument Driver Side

1from nemo.lens.contrib.ray import inject_ray_context, ray_dispatch_with_context
2
3# Method 1: manual carrier
4carrier = inject_ray_context()
5future = my_actor.method.remote(arg1, arg2, _otel_carrier=carrier)
6
7# Method 2: dispatch helper
8future = ray_dispatch_with_context(my_actor.method, arg1, arg2)

Instrument Worker Side

Wrap remote methods with traced_remote_call to auto-extract context:

1from nemo.lens.contrib.ray import traced_remote_call
2
3@ray.remote
4class MyActor:
5 @traced_remote_call
6 def method(self, arg1, arg2):
7 # _otel_carrier kwarg is consumed by the decorator and used to set
8 # the current span context before method body runs
9 ...

Spans created inside method now appear as children of the driver’s span.

No extra install is needed, as this uses opentelemetry-api only.

NCCL with contrib.nccl

NCCL transfers use raw bytes and have no native header concept. For pipeline-parallel correlation, use the following pattern to piggyback trace context on a tensor transfer:

1from nemo.lens.contrib.nccl import serialize_context, extract_nccl_context
2
3# Sender
4data = serialize_context() # JSON-encoded W3C carrier as bytes
5# ... send `data` alongside your tensor via NCCL ...
6
7# Receiver
8ctx = extract_nccl_context(data)
9# attach ctx as parent context for new spans

If you need the intermediate carrier dict rather than a ready-to-use OTel Context, call deserialize_context(data: bytes) -> dict | None, which is the mid-layer that extract_nccl_context wraps. It returns the decoded carrier dict, or None if the bytes are malformed (it swallows JSONDecodeError and UnicodeDecodeError):

1from nemo.lens.contrib.nccl import deserialize_context
2
3carrier = deserialize_context(data) # dict, or None on bad input

In practice, most pipeline-parallel users do not need this; broadcast_trace_context is simpler and more idiomatic (see Distributed Tracing). NCCL helpers exist for advanced cases where you are already passing metadata alongside tensors, and trace context can piggyback for free.

No extra install is needed, as this uses opentelemetry-api only.

Design Notes

Contrib modules are thin; each wraps an existing OTel instrumentation package or provides a couple of helper functions. They do not implement tracing logic themselves.

If you need to add a contrib module:

  1. Check if an opentelemetry-instrumentation-<framework> package exists upstream. If yes, your module should be a single function that imports and calls it.
  2. Add the package as an optional extra in pyproject.toml (nemo-lens[<framework>]).
  3. Raise an ImportError with an actionable install hint if the instrumentation package is not present.

This keeps the contrib surface small and maintenance burden low.