skip to content

In Grafana, you want a log line shown from a Loki data source to become a clickable link that opens the matching trace in Tempo. How is that link configured, where does the configuration live, and what has to be true of the log line itself?

level: middleimportance: must knowfreq 32%

answer

  1. Derived field = matcher + internal link (target UID)
  2. Regex capture group vs label / structured metadata
  3. ${__value.raw} interpolated into the Tempo query
  4. Configured on the Loki datasource, not the panel
  5. App must log the trace id first

basics

~20 s

On the Loki data source you define a derived field: a name, a matcher that pulls the trace id out of the log (a regex capture group, or a label / structured-metadata key), and an internal link naming the Tempo data source by UID. The log itself must carry the trace id.

solid answer

~60 s

Log-to-trace linking is a **data source** setting in Grafana, not a panel setting. On the Loki data source you add a *derived field* with three parts: a **name** (the text on the button under the log line), a **matcher** — either a regex with exactly one capture group run against the raw log line, or, in newer Grafana versions, a label / structured-metadata key so nothing has to be parsed — and a **link**. For correlation you choose an *internal* link and pick the target data source, which is stored as a **UID**; the captured value is interpolated as `${__value.raw}` into the query sent to Tempo. Two preconditions sit outside Grafana. The application must emit the trace id into its logs, ideally as a structured field rather than free text. And the Tempo UID must be identical in every environment, which is why this belongs in provisioned datasource YAML (`jsonData.derivedFields`) rather than being clicked into one instance's UI. Regex matchers are the fragile rung: a log-format change kills every link silently, with no error anywhere.

code

text · 8 lines
text
loki datasource
  jsonData.derivedFields:
    - name: TraceID
      matcherType: label          # or regex
      matcherRegex: trace_id      # label key, or a regex with 1 capture group
      datasourceUid: tempo-main   # must be identical in every environment
      url: "${__value.raw}"       # query sent to Tempo
      urlDisplayLabel: "View trace"

go deeper

for a junior

Know that it is called a derived field, that it lives on the Loki data source, and that the application has to log the trace id for any of it to work.

for a middle

Be able to name the three parts — matcher, target data source UID, interpolated value — and explain why label/structured-metadata matching beats a regex.

for a senior

Discuss provisioning it as code with pinned UIDs, permissions on the target data source, and the sampling/retention reasons links dead-end.

for a principal

Frame it as a platform contract: Grafana renders correlations the telemetry already carries, so the investment is in a fleet-wide logging convention, not in per-instance UI configuration.

## The problem In an LGTM-shaped stack the three signals live in three different stores: logs in Loki, traces in Tempo, metrics in Mimir/Prometheus. Nothing joins them automatically. The only thing that can join a log line to a trace is a **shared identifier that the application itself emitted** — the trace id. Grafana's job is only to notice that identifier in the query result and render it as a link into another data source. ## Derived fields A *derived field* is configured on the **Loki data source**, in its settings (or, as code, under `jsonData.derivedFields` in the datasource provisioning file). It has: - **Name** — the field name Grafana creates and the caption of the button rendered under the expanded log line. - **Type / matcher** — historically a **regex** evaluated against the whole raw log line, where the *first capture group* is the extracted value. Newer Grafana versions also allow matching on a **label** or on **structured metadata**, which is far more robust because no parsing happens. - **Query / URL** — either an external URL (any system, `${__value.raw}` substituted in) or an **internal link**, which is what you want here: you select the target data source, and Grafana stores its **UID**. The query field then holds whatever that data source needs — for Tempo, usually just `${__value.raw}`, since a bare trace id is a valid lookup. - **URL label** — optional display text. At query time Grafana runs the matcher over each log line, and if it matches, attaches the derived field to that row. In the Logs panel and in Explore the value appears as a link; clicking it opens a split pane (Explore) or navigates (dashboards) with the trace loaded. ## What must be true of the log The trace id has to be *in* the log. Getting it there is the application's job, not Grafana's: a logging layer that copies the active trace and span id from the ambient tracing context into every log record — typically via the logging framework's contextual map, or automatically by an auto-instrumentation agent's log-correlation feature. If the service logs unstructured text with no ids, no amount of Grafana configuration produces a link. Three quality rungs, best first: 1. **A label or structured metadata key** carrying the trace id — matched exactly, no parsing, survives format changes. Note that promoting a trace id to a *label* in Loki would be catastrophic for cardinality; structured metadata exists precisely so high-cardinality ids can be attached without becoming index labels. 2. **Structured (JSON/logfmt) log lines** — parse in the query, match on the extracted field. 3. **A regex over free text** — works, but it is a heuristic. A framework upgrade that reorders the line breaks every link, and nothing in the UI reports the failure: the button simply stops appearing. ## Operational notes - The setting is **per data source**, so every Loki data source needs it. If you have one per environment, provision it once in YAML and template it. - Internal links are stored as a **UID**, so the Tempo data source must have the same UID in dev, staging and prod, which means pinning `uid:` in the datasource provisioning file. A UI-configured link exported to another instance points at nothing. - The user clicking the link needs **query permission on the target data source**, otherwise the link resolves to an error. - The link only proves the id existed in the log. Whether a *span* exists for it depends on sampling and on Tempo's retention — a head-sampled request logs a trace id that was never exported, and the link dead-ends. - Grafana also offers **Correlations**, a data-source-agnostic generalisation of the same idea: source data source + field → target data source + query, with variables. Derived fields remain the Loki-native form and the one most often asked about. ## How to talk about it The crisp framing: *Grafana does not correlate signals; it renders correlations that the telemetry already contains.* Derived fields are a projection of an existing identifier into a link. The engineering work is upstream — making sure the trace id is present, structured, and matched by an exact key rather than a regex.

  • Why is matching a label or structured-metadata key better than a regex over the log line?
    A regex is a heuristic over a format the application owns and can change at any time; when it changes the link silently disappears, with no error surfaced to anyone. A label or structured-metadata key is an exact lookup on a field the pipeline guarantees, so it survives reformatting. Structured metadata specifically exists so a high-cardinality value like a trace id can ride along without becoming an index label, which would wreck Loki's stream cardinality.
  • The derived field renders, but clicking it lands on an empty trace view. Where do you look?
    The link only proves the id was in the log, not that a trace was stored. Check sampling first — a head-sampled request still logs its trace id even though the spans were never exported. Then check Tempo retention versus log retention: if traces are kept three days and logs seven, every link older than three days dead-ends. Finally check that the id encoding matches (hex, no dashes, correct length) and that the user has query permission on the Tempo data source.

saying these in an interview costs you the question

  • Thinking the link is configured on the panel or the dashboard rather than on the data source
  • Assuming Grafana can correlate logs and traces without the application emitting a trace id
  • Adding the trace id as a Loki index label to make matching easy, exploding stream cardinality
  • Configuring the link in the UI and expecting it to work after export, when the target data source UID differs per environment
  • Believing a rendered link guarantees the trace exists, ignoring sampling and retention

context