Instrumenting Your App

Tael ingests standard OTLP, so instrumenting an app is just standard OpenTelemetry pointed at Tael's endpoint. There is no Tael SDK to adopt and no vendor lock-in — if you ever switch backends, you change one environment variable.

Point your exporter at Tael

Set the standard OTel environment variables before your app starts:

export OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_SERVICE_NAME=my-agent

Most SDKs default OTEL_EXPORTER_OTLP_PROTOCOL to grpc and the endpoint to http://localhost:4317, so in practice OTEL_SERVICE_NAME is often the only one you must set. The service name is what shows up in tael services.

Emit wide-event spans

The payoff in Tael comes from wide events: one span per unit of work, with every useful fact attached as an attribute.

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

def handle_request(user_id, flags):
    with tracer.start_as_current_span("http.request") as span:
        span.set_attribute("user.id", user_id)
        span.set_attribute("flag.dark_mode", flags.get("dark_mode"))
        try:
            count = retrieve_items(user_id)
            span.set_attribute("result.count", count)
        except Exception as e:
            span.set_attribute("error.type", "timeout")
            span.record_exception(e)
            span.set_status(trace.Status(trace.StatusCode.ERROR))
            raise

Other languages (Go, Rust, Java, Ruby) work the same way — set the env vars and use that language's OTel SDK. See opentelemetry.io for SDK setup.

Instrumenting LLM calls

For model calls, set the span kind to LLM and attach the OpenTelemetry gen_ai.* attributes. Tael flattens these into typed columns (model, tokens, cost, TTFT) — see LLM spans.

The conventions Tael reads include:

  • gen_ai.request.modelmodel
  • gen_ai.usage.input_tokensinput_tokens
  • gen_ai.usage.output_tokensoutput_tokens
  • gen_ai.response.finish_reasonfinish_reason

Prompt and completion text attached to the span are stored as content-addressed blobs and become full-text searchable via tael query traces --text.

Verify it's flowing

Start the server (tael serve), run your app, then in another terminal:

tael services --format table
tael query traces --service my-agent --last 5m --format table

If your service doesn't appear, check the usual suspects:

  • Wrong endpoint — the exporter isn't pointed at http://127.0.0.1:4317.
  • Wrong protocol — sending HTTP/protobuf when the SDK is set to gRPC, or vice versa.
  • Missing OTEL_SERVICE_NAME — the app reports under a default name.
  • Not flushing on exit — a short-lived process exits before the batch exporter flushes. Make sure your SDK's shutdown/flush runs before the process ends.

Metrics via Prometheus

If you already emit Prometheus metrics, Tael accepts remote-write at POST /api/v1/write. Note that remote-write v1 loses metric type information, so those points are stored with type unknown.

Was this page helpful?