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
Section titled “Configure OTLP export”Call the configuration functions when the runner process starts, before creating the client or runner.
from tilebox.workflows import Clientfrom tilebox.workflows.observability.logging import configure_otel_loggingfrom 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()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
Section titled “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
Section titled “Local collector example”For local trace testing, run Jaeger with OTLP HTTP enabled:
docker run --rm --name jaeger \ -p 16686:16686 \ -p 4318:4318 \ jaegertracing/jaeger:2.9.0Then configure tracing with endpoint="http://localhost:4318" and open the Jaeger UI at http://localhost:16686.