Skip to content

Logs

LeanSignal applies the same demand-driven model to logs that it applies to metrics. This page follows a log record through the whole pipeline: how it gets into the agent, how the agent buffers it, how demand decides which streams reach central storage, and how you search them in the app.

your workloads the agent gateway central
───────────────── ──────────────────────────────── ──────────────────
OTLP / Loki push → local Loki (all streams, ~1 hour) → demanded streams
filelog / journald log-stream index available to the (tenant Loki,
app; demand filter forwards only 30 days)
streams a dashboard / rule demands

Everything is collected at full fidelity at the edge. Only the demanded log streams are ever forwarded to central storage — so central cost tracks the logs you actually query, not everything your systems write. See Demand-driven observability for the why.

The agent gateway accepts logs two ways — both land in the same edge store:

PathEndpoint on the gatewayUse it for
OTLP4317 (gRPC) / 4318 (HTTP)Apps instrumented with an OpenTelemetry SDK, or any OpenTelemetry Collector pipeline
Loki push API3500 (HTTP) / 3600 (gRPC)Existing Promtail / Grafana Alloy-style shippers — repoint them, no re-instrumentation

From applications — the OTLP endpoint your app already uses for metrics carries logs too. With OpenTelemetry zero-code instrumentation this is often a single environment variable:

Terminal window
export OTEL_EXPORTER_OTLP_ENDPOINT="http://<gateway-host>:4317"
export OTEL_LOGS_EXPORTER="otlp" # Java and .NET agents export logs by default

From files, journald, or Kubernetes — run a collector close to the source (an OpenTelemetry Collector with the filelog / journald receivers, or the shipper you already operate) and point its output at the gateway: OTLP to 4317/4318, or the Loki push endpoint on 3500. The gateway itself is an OpenTelemetry Collector distribution, so if it can reach the files directly you can add those receivers straight to its own config instead.

Inside the gateway, every log record flows through a logs/all pipeline before any filtering:

  • Local store. Every record is written to a co-located, single-node Loki — a short ~1-hour full-fidelity window (max_query_lookback: 1h). This is the edge buffer: every stream the gateway sees, whether or not anything demands it.
  • Queryable live. That buffer is searchable from the Logs page in the app (source: Available) over the agent’s gRPC control channel — so you can read logs nobody is storing centrally yet.

The logs/all pipeline fans into a logs/filtered pipeline. The filter is the set of demanded log-stream selectors. Only records whose stream matches a demanded selector are forwarded to the per-tenant Loki; everything else stays at the edge and ages out within the hour. The filter is fail-closed: an empty demand set forwards nothing.

Two things create log demand:

  • Dashboards. Saving a dashboard whose panels query logs demands their stream selectors. LeanSignal extracts the LogQL selectors from the Loki panels server-side and folds them into the demand set — for example {service_name="checkout"}. See Build dashboards.
  • Ingestion rules. A LogQL stream selector you add directly on the Logs page’s Ingestion rules tab, attached to a demand — forward a stream without building a dashboard for it.

A selector demands the whole stream. Filter stages after the selector (|= "error", | json) refine what you see on a query, not what is shipped. The demanded subset is recomputed and pushed to every connected agent in near real time, and central storage keeps demanded streams for 30 days — the same retention as metrics and traces.

The Logs page in the LeanSignal app is where you search log streams. It has two tabs and a source switch:

  • Explore tab — a LogQL query editor, a log-volume histogram over the results, and the matching log lines below.
  • Ingestion rules tab — create and manage the LogQL stream selectors this signal forwards on demand.

Search with LogQL — a label selector plus optional filter stages:

{service_name="checkout"} |= "error"

The source switch selects where the query runs:

SourceWhat it readsWhat’s there
StoredThe per-tenant LokiOnly demanded streams, kept 30 days, from the moment each demand was saved
AvailableThe agent’s edge Loki, live over the agent’s gRPC control channelEvery stream collected, for the last ~1 hour

Available requires the agent to be Connected — the query is tunnelled down the agent’s own control stream, so the edge store is never exposed to the network. If no agent is connected, Available returns an error.

  1. Send some traffic through an instrumented app (or a shipper).
  2. In the app, open Logs, switch the source to Available, and query {service_name="<your service>"}. This reads the edge store live, so it works before any demand exists.
  3. Save a dashboard panel with that query (or add an Ingestion rule), then switch back to Stored: new data appears from the moment the demand was saved. Nothing is backfilled.
Was this page helpful?