How to Set Up Observability with Zipkin and Langfuse in Embabel Agent
Embabel Agent uses OpenTelemetry as its observability backbone, automatically configuring Zipkin or Langfuse exporters when you add the dependency and expose a SpanExporter bean via Spring Boot properties.
The embabel/embabel-agent repository provides a comprehensive observability layer built on OpenTelemetry, allowing you to export distributed traces to any OpenTelemetry-compatible backend. Whether you need to monitor agent execution in Zipkin or analyze LLM interactions in Langfuse, the setup requires only dependency configuration and property files. This guide shows you exactly how to set up observability with Zipkin and Langfuse using the auto-configuration modules provided in the codebase.
How Observability Works in Embabel Agent
Embabel Agent delegates all tracing to an OpenTelemetry SdkTracerProvider configured in OpenTelemetrySdkAutoConfiguration.java. This auto-configuration activates only when it detects a SpanExporter bean on the classpath, ensuring zero overhead when observability is not needed.
The configuration lives in the embabel-agent-observability-autoconfigure module. When a valid exporter is present, the class builds the SdkTracerProvider and registers a global OpenTelemetry instance. If no exporter is found, tracing is disabled and a warning is logged to indicate that observability features are inactive.
Configuring the Zipkin Exporter
Zipkin integrates seamlessly through the standard OpenTelemetry Zipkin exporter library.
Add the Maven Dependency
Include the Zipkin exporter in your pom.xml:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
<version>1.35.0</version>
</dependency>
This dependency automatically registers a SpanExporter bean that OpenTelemetrySdkAutoConfiguration detects.
Configure Application Properties
Add the following to your application.yml:
embabel:
agent:
platform:
observability:
enabled: true
tracingEnabled: true
serviceName: embabel-agent
disabledTraces:
- "http.server.requests"
otel:
exporter:
zipkin:
endpoint: http://localhost:9411/api/v2/spans
The disabledTraces list suppresses noisy spans such as internal HTTP requests, while otel.exporter.zipkin.endpoint directs traces to your Zipkin collector.
Configuring the Langfuse Exporter
Langfuse provides specialized visualization for LLM agent traces and requires similar but distinct configuration.
Add the Maven Dependency
Add the community-provided Langfuse exporter:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-langfuse</artifactId>
<version>1.35.0</version>
</dependency>
Configure Application Properties
Configure your application.yml with the Langfuse-specific endpoint and API key:
embabel:
agent:
platform:
observability:
enabled: true
tracingEnabled: true
serviceName: embabel-agent
otel:
exporter:
langfuse:
endpoint: https://api.langfuse.com
api-key: ${LANGFUSE_API_KEY}
Store the LANGFUSE_API_KEY in environment variables or your secret management system—never commit this value to version control.
Fine-Tuning Observability Settings
The ObservabilityProperties.java class defines the complete configuration surface for tracing behavior. Key properties include:
embabel.agent.platform.observability.enabled: Master switch for all observability features.embabel.agent.platform.observability.tracingEnabled: Specifically controls span creation and export.embabel.agent.platform.observability.serviceName: Identifies your service in the trace backend.embabel.agent.platform.observability.disabledTraces: Array of observation names to suppress (e.g.,["http.server.requests"]).embabel.agent.platform.observability.captureMessageContent: Toggles capture of LLM chat payloads; disable in production to avoid PII exposure.
These properties are mapped in ObservabilityProperties.java and consumed by both OpenTelemetrySdkAutoConfiguration and EmbabelSpanEventListener.java to determine which events are recorded.
Implementing Custom Traces in Code
Once the exporter is configured, you can inject the OpenTelemetry Tracer bean to create custom spans. The Tracer is provided by the OpenTelemetrySdk bean created in OpenTelemetrySdkAutoConfiguration.
import io.opentelemetry.api.trace.Tracer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyService {
private final Tracer tracer;
@Autowired
public MyService(Tracer tracer) {
this.tracer = tracer;
}
public void doWork() {
var span = tracer.spanBuilder("my.work")
.setAttribute("component", "service")
.startSpan();
try (var ignored = span.makeCurrent()) {
// business logic...
} finally {
span.end();
}
}
}
For declarative tracing, use the @Tracked annotation processed by TrackedAspect.java, which automatically emits spans around annotated methods.
Summary
- Embabel Agent uses OpenTelemetry as its core observability framework through the
embabel-agent-observability-autoconfiguremodule. - Activation requires only a
SpanExporterbean on the classpath; no exporter means tracing is automatically disabled. - Zipkin integration uses
opentelemetry-exporter-zipkinconfigured viaotel.exporter.zipkin.endpoint. - Langfuse integration uses
opentelemetry-exporter-langfusewithotel.exporter.langfuse.endpointandotel.exporter.langfuse.api-key. - Configuration is centralized in
ObservabilityProperties.java, allowing control over service names, span filtering, and content capture. - Custom instrumentation is available via the injected
Tracerbean or the@Trackedaspect-oriented approach.
Frequently Asked Questions
What happens if I don't add any exporter dependency?
If no SpanExporter bean is detected on the classpath, OpenTelemetrySdkAutoConfiguration skips tracer provider initialization and logs a warning. The application runs without exporting traces, effectively disabling observability features without throwing errors.
Can I use both Zipkin and Langfuse simultaneously?
Yes. OpenTelemetry supports multiple exporters. If you include both dependencies in your build, both beans will be registered and traces will be exported to both backends simultaneously. Configure each exporter's endpoint independently in application.yml.
How do I prevent sensitive data from appearing in my traces?
Set embabel.agent.platform.observability.captureMessageContent to false in your properties. This prevents EmbabelSpanEventListener.java from attaching LLM chat payloads or RAG query content to spans, ensuring PII and proprietary data remain out of your observability backend.
Where is the observability configuration logic located?
The auto-configuration logic resides in embabel-agent-autoconfigure/embabel-agent-observability-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/observability/OpenTelemetrySdkAutoConfiguration.java, while the property definitions are in embabel-agent-observability/src/main/java/com/embabel/agent/observability/ObservabilityProperties.java.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →