---
title: "OpenTelemetry"
description: "Export Tilebox workflow logs and traces to any OTLP-compatible backend in addition to Tilebox Console."
image: "https://tilebox.com/images/tilebox-docs-social-preview.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://tilebox.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenTelemetry

import { CodeGroup } from "@docs/components/ui/code-group";

Tilebox uses OpenTelemetry data models for workflow telemetry. Built-in Tilebox observability works without any OpenTelemetry setup, but you can add OTLP export when you need the same logs and traces in another backend.

## Configure OTLP export

Call the configuration functions when the runner process starts, before creating the client or runner.

```python title="Python"
from tilebox.workflows import Client
from tilebox.workflows.observability.logging import configure_otel_logging
from tilebox.workflows.observability.tracing import configure_otel_tracing

from my_workflow import ProcessScene

configure_otel_tracing(
    service="sentinel-2-runner",
    endpoint="http://localhost:4318/v1/traces",
    headers={"Authorization": "Bearer <token>"},
)
configure_otel_logging(
    service="sentinel-2-runner",
    endpoint="http://localhost:4318/v1/logs",
    headers={"Authorization": "Bearer <token>"},
)

client = Client(name="sentinel-2-runner")
runner = client.runner(tasks=[ProcessScene])
runner.run_forever()
```

```go title="Go"
package main

import (
	"context"
	"log/slog"

	"github.com/tilebox/tilebox-go/observability"
	"github.com/tilebox/tilebox-go/observability/logger"
	"github.com/tilebox/tilebox-go/observability/tracer"
	"github.com/tilebox/tilebox-go/workflows/v1"
	"go.opentelemetry.io/otel"
)

type ProcessScene struct{}

func (t *ProcessScene) Execute(ctx context.Context) error {
	slog.InfoContext(ctx, "processing scene")
	return nil
}

func main() {
	ctx := context.Background()
	service := &observability.Service{Name: "sentinel-2-runner"}

	traceProvider, shutdownTracer, err := tracer.NewOtelProvider(ctx, service,
		tracer.WithEndpointURL("http://localhost:4318/v1/traces"),
		tracer.WithHeaders(map[string]string{"Authorization": "Bearer <token>"}),
	)
	if err != nil {
		slog.ErrorContext(ctx, "failed to configure tracing", slog.Any("error", err))
		return
	}
	defer shutdownTracer(ctx)
	otel.SetTracerProvider(traceProvider)

	logHandler, shutdownLogger, err := logger.NewOtelHandler(ctx, service,
		logger.WithEndpointURL("http://localhost:4318/v1/logs"),
		logger.WithHeaders(map[string]string{"Authorization": "Bearer <token>"}),
		logger.WithLevel(slog.LevelInfo),
	)
	if err != nil {
		slog.ErrorContext(ctx, "failed to configure logging", slog.Any("error", err))
		return
	}
	defer shutdownLogger(ctx)
	slog.SetDefault(logger.New(logHandler))

	client := workflows.NewClient()
	runner, err := client.NewTaskRunner(ctx)
	if err != nil {
		slog.ErrorContext(ctx, "failed to create runner", slog.Any("error", err))
		return
	}

	if err := runner.RegisterTasks(&ProcessScene{}); err != nil {
		slog.ErrorContext(ctx, "failed to register tasks", slog.Any("error", err))
		return
	}

	runner.Run(ctx)
}
```

If the endpoint does not include `/v1/traces` or `/v1/logs`, the Python SDK adds the correct path automatically.

## Environment variables

You can omit endpoint and interval arguments by setting environment variables:

| Variable | Used by |
| --- | --- |
| `OTEL_TRACES_ENDPOINT` | `configure_otel_tracing()` |
| `OTEL_LOGS_ENDPOINT` | `configure_otel_logging()` |
| `OTEL_EXPORT_INTERVAL` | tracing and logging exporters |

`OTEL_EXPORT_INTERVAL` accepts durations such as `5s`, `30s`, or `2m`.

## Local collector example

For local trace testing, run Jaeger with OTLP HTTP enabled:

```bash
docker run --rm --name jaeger \
  -p 16686:16686 \
  -p 4318:4318 \
  jaegertracing/jaeger:2.9.0
```

Then configure tracing with `endpoint="http://localhost:4318"` and open the Jaeger UI at [http://localhost:16686](http://localhost:16686).

Source: https://tilebox.com/docs/workflows/run-and-inspect/integrations/open-telemetry/index.mdx
