Skip to Content
Tares

How can an AI SRE see who was affected by the errors in OpenTelemetry log records using Postgres tables?

Tares puts Postgres rows on the same timeline as your OpenTelemetry log records when both sources carry the same primary label value, such as the service name. An AI SRE then reads the error lines and the table rows around them together. The Postgres rows show the state of your data around the errors.

How it works

Tares joins sources by label value. Each source marks one label as primary, and events whose primary label has the same value share one timeline.

  • The OpenTelemetry source receives OTLP logs, traces and metrics. Resource attributes such as service.name become labels, so the service label is the natural key.
  • The Postgres source polls a table incrementally and stores one event per new or changed row. A cursor tracks a column that only grows, such as id or updated_at.
  • To join the two, give the Postgres source a primary label named service, read from a table column that holds the same service name the log records carry. Rows and log lines with the same service value then appear on the same timeline.
  • Other columns, such as tenant_id or status, stay plain labels. They are stored on each row event, so they sit next to the error lines on that timeline.

The AI SRE guide describes how an agent works from these timelines. If your data lives behind a JSON endpoint instead of a table, the HTTP API (poll) connector stores one event per item the same way, and it joins by the same label rule.

Set it up

  1. Start Tares locally.

    tares up
  2. Create an OpenTelemetry source with service as the primary label. In the UI, go to Sources, Add source, otlp. There is no required config.

    - name: otel connector: otlp config: labels: - { name: service, field: service, primary: true }
  3. Point your exporter at the daemon. Use the gRPC endpoint if you installed the otlp-grpc extra.

    OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8787 # OTLP/HTTP → /v1/{logs,traces,metrics} # or gRPC (otlp-grpc extra): OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317

    On a secured instance, the exporter sends a Bearer Authorization header holding an ingest-scoped API key. Tares needs it only when auth is on.

  4. Create the Postgres source. In the UI, go to Sources, Add source, Postgres, enter the connection URL and press Discover. Add the column that holds the service name to columns, and mark a label named service as primary. This example assumes your orders table has a service column. Keep tenant_id as a plain label.

    - name: orders connector: postgres poll: 10s config: dsn: postgresql://user:pass@host:5432/appdb table: orders cursor_column: updated_at columns: id,service,tenant_id,status,amount,updated_at # empty = every column labels: - { name: service, field: service, primary: true } - { name: tenant_id, field: tenant_id } - { name: status, field: status }
  5. Verify each source. On the Postgres source, Recent events shows rows on the next poll, and Fields reports each column’s coverage, so you can confirm the service column is reliably present. On the OpenTelemetry source, Recent events shows log records as they arrive, and Explore lists services under the service key.

The dsn is stored as a secret, redacted in the API and left out of catalog exports. The cursor column must only ever grow. Pick updated_at if you want updated rows as well as inserts.

What you get

  • Log records and table rows on one timeline for each service, so an agent reads the errors and the data state around them in one place.
  • Row events that carry the columns you pulled. With status and tenant_id as labels, they sit beside the error lines.
  • Incremental reads. Only new or changed rows become events, so the timeline does not fill with repeats of unchanged data.
  • One OpenTelemetry source for every service, with no per-service setup. Resource attributes become labels.

The join depends on the label value. Rows appear on the same timeline as the log records only when the service value in the table matches the one the logs carry. If the values differ in spelling, the two sources stay on separate timelines.

When something else fits

  • If the data you want next to the errors comes from an API and not a table, use HTTP API (poll), which polls a JSON endpoint and stores one event per item.
  • If you only need the error lines and their traces, the OpenTelemetry source alone is enough, and you can skip the Postgres source.

Still stuck? Get help

Last updated on