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-autoconfigure module.
  • Activation requires only a SpanExporter bean on the classpath; no exporter means tracing is automatically disabled.
  • Zipkin integration uses opentelemetry-exporter-zipkin configured via otel.exporter.zipkin.endpoint.
  • Langfuse integration uses opentelemetry-exporter-langfuse with otel.exporter.langfuse.endpoint and otel.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 Tracer bean or the @Tracked aspect-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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →