Skip to Content
DocsObservabilityTracing | Kastrax Observability Documentation

Tracing ✅

Kastrax supports the OpenTelemetry Protocol (OTLP) for tracing and monitoring your application. When telemetry is enabled, Kastrax automatically traces all core primitives including agent operations, LLM interactions, tool executions, integration calls, workflow runs, and database operations. Your telemetry data can then be exported to any OTEL collector.

Core Components

Kastrax’s tracing system is built on OpenTelemetry and consists of several core components:

  1. TracingSystem: The central entry point for tracing operations
  2. Tracer: Interface defining core tracing functionality
  3. TraceSpan: Interface representing a single trace span
  4. TracingConfig: Configuration for the tracing system

Basic Usage

Here’s a simple example of using the tracing system in Kotlin:

// Create tracing configuration val config = TracingConfig().apply { serviceName = "my-service" samplingRate = 1.0 // Always sample exporters.otlp.enabled = true exporters.otlp.endpoint = "http://localhost:4318/v1/traces" } // Apply configuration and get tracer val tracer = config.apply() // Set global tracer TracingSystem.setTracer(tracer) // Create a span val span = TracingSystem.createSpan("my-operation") try { // Add attributes span.setAttribute("key", "value") // Perform operation // ... // Add event span.addEvent("operation-completed") // Set success status span.setSuccess() } catch (e: Exception) { // Record exception span.setError("Operation failed") span.recordException(e) throw e } finally { // End span span.end() }

You can also use the simplified withSpan method:

val result = TracingSystem.withSpan<String>("my-operation") { span -> span.setAttribute("key", "value") // Perform operation and return result "operation result" }

Configuration Options

The TracingConfig class provides numerous configuration options:

val config = TracingConfig().apply { // Service identification serviceName = "my-service" serviceVersion = "1.0.0" serviceNamespace = "kastrax" serviceInstanceId = "instance-1" // Sampling configuration samplingRate = 0.5 // Sample 50% of traces // Exporters configuration exporters.logging.enabled = true // Console logging exporters.otlp.enabled = true // OTLP exporter exporters.otlp.endpoint = "http://localhost:4318/v1/traces" exporters.otlp.headers = mapOf("x-api-key" to "your-api-key") // Context propagation propagation.w3c = true // W3C trace context propagation.b3 = false // B3 format propagation.jaeger = false // Jaeger format }

JavaScript/TypeScript Configuration

For JavaScript/TypeScript applications, you can configure tracing as follows:

kastrax.config.ts
export const kastrax = new Kastrax({ // ... other config telemetry: { serviceName: "my-app", enabled: true, sampling: { type: "always_on", }, export: { type: "otlp", endpoint: "http://localhost:4318", // SigNoz local endpoint }, }, });

The telemetry config accepts these properties:

type OtelConfig = { // Name to identify your service in traces (optional) serviceName?: string; // Enable/disable telemetry (defaults to true) enabled?: boolean; // Control how many traces are sampled sampling?: { type: "ratio" | "always_on" | "always_off" | "parent_based"; probability?: number; // For ratio sampling root?: { probability: number; // For parent_based sampling }; }; // Where to send telemetry data export?: { type: "otlp" | "console"; endpoint?: string; headers?: Record<string, string>; }; };

See the OtelConfig reference documentation for more details.

Environment Variables

You can configure the OTLP endpoint and headers through environment variables:

.env
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_EXPORTER_OTLP_HEADERS=x-api-key=your-api-key

Then in your config:

kastrax.config.ts
export const kastrax = new Kastrax({ // ... other config telemetry: { serviceName: "my-app", enabled: true, export: { type: "otlp", // endpoint and headers will be picked up from env vars }, }, });

Distributed Tracing

Kastrax supports distributed tracing across service boundaries:

// Extract context from incoming request val extractedContext = tracer.extractContext(headers) { carrier, key -> carrier[key] } // Create a span with the extracted context val span = tracer.createSpan("handle-request", parent = extractedContext) // When making outgoing requests, inject context val outgoingHeaders = mutableMapOf<String, String>() tracer.injectContext(span.getContext(), outgoingHeaders) { carrier, key, value -> carrier[key] = value }

Integration with Agents and Tools

Kastrax automatically integrates tracing with agents and tools:

// Create agent with tracing val agent = agent { name("TracedAgent") description("Agent with tracing enabled") model = deepSeek { apiKey("your-api-key") model(DeepSeekModel.DEEPSEEK_CHAT) } // Enable tracing tracing { enabled = true level = TracingLevel.DETAILED } } // Create tool with tracing val tool = tool("calculator") { description("Performs basic math calculations") // Enable tracing tracing { enabled = true } execute { params -> // Create span val span = TracingSystem.createSpan("calculator-execution") try { // Perform calculation // ... "Result: 42" } finally { span.end() } } }

Workflow Tracing

Kastrax provides specialized tracing for workflows:

// Create workflow tracer val tracer = DataFlowTracer() // Execute workflow val result = workflow.execute(input) // Trace workflow execution val traceResult = tracer.traceWorkflowExecution(workflow, context) // Analyze trace results traceResult.stepTraces.forEach { trace -> println("Step: ${trace.stepId}, Success: ${trace.success}") } // Trace specific variable val variableTrace = tracer.traceVariable(workflow, "value", context)

Exporters

Kastrax supports multiple trace exporters:

  1. Logging Exporter: Outputs traces to the console
  2. OTLP Exporter: Sends traces to any OpenTelemetry collector
  3. Custom Exporters: Implement your own exporters for specific backends

Example: SigNoz Integration

Here’s what a traced agent interaction looks like in SigNoz:

Agent interaction trace showing spans, LLM calls, and tool executions

Other Supported Providers

For a complete list of supported observability providers and their configuration details, see the Observability Providers reference.

Best Practices

  1. Naming Conventions: Use consistent naming for spans
  2. Attribute Management: Add key attributes that help with diagnostics
  3. Error Handling: Always record exceptions and error states
  4. Performance Considerations: Use appropriate sampling rates to reduce overhead
  5. Context Propagation: Properly propagate context in distributed systems
  6. Sensitive Data: Avoid including sensitive information in spans

Next.js-specific Tracing steps

If you’re using Next.js, you have three additional configuration steps:

  1. Enable the instrumentation hook in next.config.ts
  2. Configure Kastrax telemetry settings
  3. Set up an OpenTelemetry exporter

For implementation details, see the Next.js Tracing guide.

Last updated on