Custom Exporters
setup_telemetry supports injecting custom SpanExporter and MetricReader instances, which bypasses the configuration-based construction. This is the extension point for the following use cases:
- In-memory exporters for testing
- Custom exporters for proprietary backends
- Exporters that require fine-grained configuration that NeMo Lens does not expose
Signature
When provided, these override the config’s exporter field for that signal. You can mix these options by passing a custom span_exporter and letting metrics use the config’s exporter.
Custom Span Exporter
This is how the NeMo Lens test suite captures spans for assertions.
Custom Metric Reader
Write a Custom Exporter
To route telemetry to a backend not supported by OTLP, subclass SpanExporter:
Use the same pattern for MetricReader (refer to the OpenTelemetry documentation).
Custom Exporters and Sampling
Custom exporters plug into the BatchSpanProcessor that NeMo Lens installs. By default (sampler_enabled=False), no span-level sampling occurs, and a custom exporter receives every span produced on an exporting rank. When sampler_enabled=True, NeMo Lens’s RankAwareSampler makes a single per-rank decision at construction time (sampling.py), where all spans on a rank are either kept or dropped together, meaning it is not a per-span sample. If you want a parallel processor regardless of sampling, install your own SpanProcessor as shown below:
This approach only works on an exporting rank with traces enabled, which occurs when handle.is_exporting is True. On disabled or non-exporting ranks, setup_telemetry installs a NoOpTracerProvider, so trace.get_tracer_provider() returns a no-op provider that has no add_span_processor method, and this call raises an AttributeError. Guard this call with if handle.is_exporting::
NeMo Lens does not expose an extension point for custom processors, so if you need one, add it to the provider directly after setup_telemetry returns. This is a lower-level interface, but it is stable within the OpenTelemetry SDK.
Why This API
Before this extension point, connecting NeMo Lens to a non-OTLP backend required subclassing build_providers or monkey-patching internals. Now it is a supported extension point: pass your exporter, and NeMo Lens does the rest.
The design goal is to keep NeMo Lens’s core surface small (OTLP and console are plenty for most users) while letting power users plug in whatever they need without forking NeMo Lens.