Keep your existing observability tool
Add Judgment as a second destination alongside Logfire, LangSmith, Braintrust or Langfuse.
All four tools build on OpenTelemetry, so Judgment can be one more span processor on the same tracer provider, and both tools get the same spans. This doesn’t import traces you already stored in another tool; if you need history moved over, contact support.
What Judgment reads from each tool
| Tool | How you add Judgment | What Judgment’s ingest maps from the tool’s own attributes |
|---|---|---|
| Logfire | additional_span_processors in logfire.configure() |
logfire.msg becomes the span name |
| LangSmith | LangSmith OpenTelemetry mode on a shared provider | langsmith.span.kind becomes the span kind |
| Braintrust | BraintrustSpanProcessor next to Judgment’s on a shared provider |
model, provider, prompt and completion tokens, cost |
| Langfuse | A shared provider passed to Langfuse(tracer_provider=...) |
Nothing. Judgment has no Langfuse mapper, so Langfuse is documented here as a destination only |
Standard OpenTelemetry GenAI attributes (gen_ai.*) and OpenInference attributes map the same way no matter which tool created the span. If a field you need isn’t mapped, add a mapper: see Attribute keys and mappers.
Build the Judgment span processor
Each example below adds this processor. It’s a standard OTLP exporter, so it needs the project ID rather than the name; see Send OTLP directly for where to find it.
pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
import os
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
def create_judgment_processor() -> BatchSpanProcessor:
return BatchSpanProcessor(
OTLPSpanExporter(
endpoint="https://api.judgmentlabs.ai/otel/v1/traces",
headers={
"Authorization": f"Bearer {os.environ['JUDGMENT_API_KEY']}",
"X-Organization-Id": os.environ["JUDGMENT_ORG_ID"],
"X-Project-Id": os.environ["JUDGMENT_PROJECT_ID"],
},
)
)
Both tools now receive the same data, so apply the same scrubbing and sampling policy you already use.
Logfire
import logfire
from judgment_otlp import create_judgment_processor
logfire.configure(
service_name="lunch-order-agent",
additional_span_processors=[create_judgment_processor()],
)
logfire.instrument_openai()
If logfire.configure() rejects additional_span_processors, upgrade logfire.
LangSmith
LangSmith’s OpenTelemetry mode uses the global provider when one is set. Set one that includes Judgment, and leave LANGSMITH_OTEL_ONLY unset so runs still go to LangSmith too. This needs langsmith[otel].
import os
from judgment_otlp import create_judgment_processor
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
os.environ["LANGSMITH_OTEL_ENABLED"] = "true"
os.environ["LANGSMITH_TRACING"] = "true"
provider = TracerProvider()
provider.add_span_processor(create_judgment_processor())
trace.set_tracer_provider(provider)
Run this before your first chain or graph runs.
Braintrust
Install braintrust[otel].
from braintrust.otel import BraintrustSpanProcessor
from judgment_otlp import create_judgment_processor
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
provider = TracerProvider()
provider.add_span_processor(BraintrustSpanProcessor(parent="project_name:lunch-order-agent"))
provider.add_span_processor(create_judgment_processor())
trace.set_tracer_provider(provider)
Langfuse
Langfuse’s Python SDK v3 and later accepts a tracer provider. Add Judgment to it and keep your Langfuse instrumentation as it is.
import os
from judgment_otlp import create_judgment_processor
from langfuse import Langfuse
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
provider = TracerProvider()
provider.add_span_processor(create_judgment_processor())
trace.set_tracer_provider(provider)
langfuse = Langfuse(
public_key=os.environ["LANGFUSE_PUBLIC_KEY"],
secret_key=os.environ["LANGFUSE_SECRET_KEY"],
tracer_provider=provider,
)