Skip to main content

Documentation Index

Fetch the complete documentation index at: https://braintrust.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

Temporal is a durable execution platform for building reliable distributed applications. Braintrust integrates with Temporal to automatically trace workflows and activities, providing full observability across your workflow executions. The integration captures:
  • Workflow execution spans
  • Activity execution spans with metadata
  • Distributed traces across workers
  • Parent-child relationships between workflows and activities

Setup

Install the required packages:
# pnpm
pnpm add @braintrust/temporal braintrust @temporalio/client @temporalio/worker @temporalio/workflow @temporalio/activity @temporalio/common
# npm
npm install @braintrust/temporal braintrust @temporalio/client @temporalio/worker @temporalio/workflow @temporalio/activity @temporalio/common
Temporal integration requires TypeScript SDK v2.1.0+.

Trace with Temporal

Braintrust provides automatic tracing for Temporal workflows and activities. The integration uses a plugin pattern for TypeScript and Python, and OpenTelemetry interceptors for Go.

TypeScript

Use the BraintrustTemporalPlugin with both your Temporal Client and Worker. The plugin automatically instruments your workflows and activities, creating spans that capture execution details and propagate trace context across process boundaries.
import { Client, Connection } from "@temporalio/client";
import { Worker } from "@temporalio/worker";
import * as braintrust from "braintrust";
import { BraintrustTemporalPlugin } from "@braintrust/temporal";

// Initialize Braintrust
braintrust.initLogger({ projectName: "my-project" });

// Create a single plugin instance
const plugin = new BraintrustTemporalPlugin();

// Use the plugin with your Client
const client = new Client({
  connection: await Connection.connect(),
  plugins: [plugin],
});

// Use the same plugin with your Worker
const worker = await Worker.create({
  taskQueue: "my-task-queue",
  workflowsPath: require.resolve("./workflows"),
  activities,
  plugins: [plugin],
});
The plugin automatically:
  • Creates parent spans for workflow executions
  • Creates child spans for activity executions
  • Propagates trace context across workers via headers
  • Handles concurrent workflow execution safely

Python

To trace Temporal workflows and activities automatically, call braintrust.auto_instrument() (Python SDK v0.19.0 or later). It adds BraintrustPlugin to any Temporal client or worker you create, so you don’t need to configure anything manually.
import braintrust

braintrust.auto_instrument()
To instrument manually, import BraintrustPlugin from braintrust.integrations.temporal, instantiate it, and pass it to both your Temporal client and worker via plugins=[plugin]. The plugin intercepts workflow and activity executions to create spans with full context, including workflow IDs, activity types, and execution metadata.
from braintrust.integrations.temporal import BraintrustPlugin
from temporalio.client import Client
from temporalio.worker import Worker

# Create a single plugin instance
plugin = BraintrustPlugin()

# Use the plugin with your Client
client = await Client.connect(
    "localhost:7233",
    plugins=[plugin],
)

# Use the same plugin with your Worker
worker = Worker(
    client,
    task_queue="my-task-queue",
    workflows=[MyWorkflow],
    activities=[my_activity],
    plugins=[plugin],
)

await worker.run()
The plugin handles:
  • Workflow execution spans via BraintrustWorkflowInboundInterceptor
  • Activity execution spans with workflow metadata
  • Span context serialization/deserialization via Temporal headers
  • Temporal sandbox compatibility for braintrust imports
The braintrust.contrib.temporal module is deprecated in Python SDK v0.19.0. Imports from braintrust.contrib.temporal still work but emit a DeprecationWarning. Update imports to braintrust.integrations.temporal.

Go

Go uses OpenTelemetry interceptors to integrate Braintrust with Temporal. This approach leverages Temporal’s native OpenTelemetry support, routing spans through the Braintrust SDK’s trace provider for unified observability.
package main

import (
	"context"
	"log"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/trace"
	"go.temporal.io/sdk/activity"
	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/contrib/opentelemetry"
	"go.temporal.io/sdk/interceptor"
	"go.temporal.io/sdk/worker"
	"go.temporal.io/sdk/workflow"

	"github.com/braintrustdata/braintrust-sdk-go"
)

// MyWorkflow is a minimal workflow that executes an activity
func MyWorkflow(ctx workflow.Context, input string) (string, error) {
	var result string
	err := workflow.ExecuteActivity(ctx, MyActivity, input).Get(ctx, &result)
	return result, err
}

// MyActivity is a minimal activity
func MyActivity(ctx context.Context, input string) (string, error) {
	logger := activity.GetLogger(ctx)
	logger.Info("Processing input", "input", input)
	return "processed: " + input, nil
}

func main() {
	ctx := context.Background()

	// Set up OpenTelemetry TracerProvider
	tp := trace.NewTracerProvider()
	defer tp.Shutdown(ctx)
	otel.SetTracerProvider(tp)

	// Configure propagators for distributed tracing
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
		propagation.TraceContext{},
		propagation.Baggage{},
	))

	// Initialize Braintrust
	_, err := braintrust.New(tp,
		braintrust.WithProject("My Project"),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Create OpenTelemetry interceptor for Temporal
	tracer := otel.Tracer("temporal-example")
	tracingInterceptor, err := opentelemetry.NewTracingInterceptor(
		opentelemetry.TracerOptions{Tracer: tracer},
	)
	if err != nil {
		log.Fatal(err)
	}

	// Create Temporal client with tracing
	c, err := client.Dial(client.Options{
		Interceptors: []interceptor.ClientInterceptor{tracingInterceptor},
	})
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	// Create worker with the same client
	w := worker.New(c, "my-task-queue", worker.Options{})
	w.RegisterWorkflow(MyWorkflow)
	w.RegisterActivity(MyActivity)

	if err := w.Run(worker.InterruptCh()); err != nil {
		log.Fatal(err)
	}
}

Resources