OpenTelemetry (OTEL)
Send OTLP traces from any application or collector to Muster, supporting Java, Go, .NET, and other languages beyond the native SDKs.
OpenTelemetry (OTEL) is a CNCF project providing specifications, APIs, and libraries that establish standardized methods for collecting distributed traces and metrics from applications.
Muster operates as an OpenTelemetry backend, accepting traces at the
/api/public/otel (OTLP) endpoint. This integration extends compatibility
beyond the native SDKs and integrations to frameworks, libraries, and
languages including Java and Go through tools like OpenLLMetry and
OpenLIT.
Muster maps the received OTel traces to its data model and supports additional attributes popular in the OTel GenAI ecosystem.
When to Use the OpenTelemetry Integration
- Prefer the native SDKs if: you are using Python or JavaScript/TypeScript.
- Use OTEL if: you have an existing OTEL setup, collector-based ingestion, or you are working in a language without a first-party SDK.
flowchart LR
subgraph App["Application"]
Logic["Operations, LLM calls, events"]
OTel["OpenTelemetry instrumentation (SDKs, libraries)"]
Logic --> OTel
end
OTel -->|"OTLP traces"| Endpoint["Muster OTLP endpoint /api/public/otel"]
subgraph Muster["Muster"]
Endpoint --> Map["OTel to data-model attribute mapping"]
Map --> UI["Muster traces"]
endImportant: Propagating Trace Attributes to All Spans
Certain trace-level attributes must propagate to all spans within a trace for proper aggregation and filtering:
userId(vialangfuse.user.idoruser.id)sessionId(vialangfuse.session.idorsession.id)metadata(vialangfuse.trace.metadata.*)version(vialangfuse.version)release(vialangfuse.release)tags(vialangfuse.trace.tags)trace_name(vialangfuse.trace.name)
Recommended: OpenTelemetry Baggage
Use OpenTelemetry Baggage with a BaggageSpanProcessor:
- Set the desired attributes as baggage entries at trace start.
- Set the attributes on the currently active span.
- Configure a
BaggageSpanProcessorto copy baggage entries to span attributes. - All downstream spans receive these attributes automatically.
Implementation guides are available for Python and JavaScript.
Security note: OpenTelemetry baggage is propagated across service boundaries and to third-party APIs. Do not include sensitive information in baggage when using this approach.
Alternative: SDK Helpers
If you are using the Muster (langfuse) SDKs, the convenience methods
propagate_attributes() (Python) or propagateAttributes() (TypeScript)
provide automatic attribute propagation.
Ingestion Options
OpenTelemetry-Native SDK v4
The quickest path is the OTEL-native langfuse SDK v4, a thin layer on the official OpenTelemetry client. It automatically converts spans into rich Muster observations and adds LLM-specific helpers for token usage, cost tracking, prompt linking, and scoring.
The SDK exports spans from other OTEL-instrumented libraries by default, focusing on LLM-relevant spans. Use custom filters in the advanced SDK configuration to export everything.
OpenTelemetry Endpoint
Muster receives traces at the /api/public/otel (OTLP) endpoint.
OTEL_EXPORTER_OTLP_ENDPOINT="https://app.getmuster.io/api/public/otel"
# Self-hosted: http(s)://<your-muster-host>/api/public/otel
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic ${AUTH_STRING},x-langfuse-ingestion-version=4"Authentication uses Basic Auth. Generate AUTH_STRING:
echo -n "pk-lf-1234567890:sk-lf-1234567890" | base64
# For GNU base64: base64 -w 0For real-time Fast Preview, include the x-langfuse-ingestion-version: 4
header. If you use signal-specific headers, add the same value to
OTEL_EXPORTER_OTLP_TRACES_HEADERS.
Signal-specific endpoint:
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://app.getmuster.io/api/public/otel/v1/traces"Muster supports OTLP over HTTP (JSON and protobuf). gRPC is not yet supported.
Custom OpenTelemetry SDKs
Use OpenTelemetry SDKs directly with the configuration above to export traces, extending language support beyond Python and JS/TS.
OpenTelemetry GenAI Instrumentation Libraries
Recommended libraries:
Export From an OpenTelemetry Collector
graph LR
A[Application with OTel Instrumentation] --> B[OpenTelemetry Collector]
B --> C[Muster]Use this configuration with the OpenTelemetry Collector:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
memory_limiter:
limit_mib: 1500
spike_limit_mib: 512
check_interval: 5s
exporters:
otlphttp/muster:
endpoint: "https://app.getmuster.io/api/public/otel"
headers:
Authorization: "Basic ${AUTH_STRING}"
x-langfuse-ingestion-version: "4"
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/muster]Filtering Spans Sent to Muster
Use the OTel Collector filterprocessor to selectively forward spans. Note that filtering at the span level risks creating incomplete traces — root spans must be sent to ensure correct trace creation.
Example filtering by gen_ai.system:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
filter/openaisystem:
error_mode: ignore
traces:
span:
- 'attributes["gen_ai.system"] != "openai"'
exporters:
otlphttp/muster:
endpoint: "https://app.getmuster.io/api/public/otel"
headers:
Authorization: "Basic ${AUTH_STRING}"
x-langfuse-ingestion-version: "4"
service:
pipelines:
traces:
receivers: [otlp]
processors: [filter/openaisystem]
exporters: [otlphttp/muster]Attribute Mapping
Muster follows the OpenTelemetry GenAI semantic conventions and uses attributes within the langfuse.* namespace to map OTel span attributes directly to its data model. These attributes take precedence over generic conventions and are recommended for manual instrumentation.
Attribute keys containing
__proto__,constructor, orprototypeas a path segment are silently dropped during ingestion as a security measure.
How Metadata Mapping Works
| Attribute Type | Location in Muster | Example |
|---|---|---|
| Explicit metadata mapping | First-level key in metadata (filterable) | langfuse.trace.metadata.customer_tier → metadata.customer_tier |
| Unmapped OTel attributes | Nested under metadata.attributes | http.method → metadata.attributes.http.method |
| Resource attributes | Nested under metadata.resourceAttributes | service.name → metadata.resourceAttributes.service.name |
SDK-emitted vs. standard OTel attributes:
- Muster (langfuse) SDKs: provide utility functions that automatically
set
langfuse.*.metadata.*prefixed attributes. Custom metadata appears at the first level and is filterable. - Standard OTel SDKs: set attributes directly on spans. Without an
explicit
langfuse.trace.metadata.*orlangfuse.observation.metadata.*prefix, attributes end up in themetadata.attributescatch-all and are not directly filterable.
Trace-Level Attributes
Applied to the trace record. May be set on any span in the trace.
| Field | Description | Mapped from OTel attribute |
|---|---|---|
name | Name of the trace | langfuse.trace.name, root span name |
userId | End-user unique identifier | langfuse.user.id, user.id |
sessionId | User session unique identifier | langfuse.session.id, session.id |
release | Application release version | langfuse.release |
public | Boolean to mark trace as shareable | langfuse.trace.public |
tags | String array categorizing the trace | langfuse.trace.tags |
metadata | Additional unstructured data | langfuse.trace.metadata.*, root span metadata |
input | Initial input for the trace | langfuse.trace.input, root span input |
output | Final output for the trace | langfuse.trace.output, root span output |
version | Version tracking changes to application logic | root span attributes mapped to version |
environment | Deployment environment | root span attributes mapped to environment |
Filtering by metadata key:
Muster supports filtering only on top-level metadata keys. Use the
langfuse.trace.metadata prefix to map attributes to the top-level
metadata object:
with tracer.start_as_current_span("Example") as span:
span.set_attribute("langfuse.trace.metadata.user_name", "user-123")Observation-Level Attributes
Applied to individual observations (spans) within a trace.
| Field | Description | Mapped from OTel attribute |
|---|---|---|
type | Type of observation. Spans with a model attribute are tracked as generation | langfuse.observation.type (default: "span") |
level | Severity level | langfuse.observation.level (default: "DEFAULT"); inferred from span.status.code |
statusMessage | Status description | langfuse.observation.status_message; inferred from span.status.message |
metadata | Additional unstructured data | langfuse.observation.metadata.* |
input | Input data | langfuse.observation.input, gen_ai.prompt, input.value, mlflow.spanInputs |
output | Output data | langfuse.observation.output, gen_ai.completion, output.value, mlflow.spanOutputs |
model | Generative model name (Generation only) | langfuse.observation.model.name, gen_ai.request.model, gen_ai.response.model, llm.model_name, model |
modelParameters | Model invocation settings (Generation only) | langfuse.observation.model.parameters, gen_ai.request.*, llm.invocation_parameters.* |
usage | Token counts (Generation only) | langfuse.observation.usage_details, gen_ai.usage.*, llm.token_count.* |
cost | Calculated cost in USD (Generation only) | langfuse.observation.cost_details, gen_ai.usage.cost |
prompt | Versioned prompt name (Generation only) | langfuse.observation.prompt.name, langfuse.observation.prompt.version |
completionStartTime | Timestamp model began generating (Generation only) | langfuse.observation.completion_start_time (ISO 8601) |
version | Version of the observation | langfuse.version |
environment | Deployment environment | langfuse.environment, deployment.environment, deployment.environment.name |
Filtering by metadata key:
with tracer.start_as_current_span("Example") as span:
span.set_attribute("langfuse.observation.metadata.user_name", "user-123")Troubleshooting
- For
4xxerrors on a self-hosted Muster, upgrade to the latest version. The OpenTelemetry endpoint was introduced in upstream Langfuse v3.22.0 with significant improvements since. - Muster supports OTLP over HTTP (JSON and protobuf). gRPC is not yet supported.