Observability Stack: metrics, logs, traces with correlation

When metrics, logs, and traces live in different systems, finding the cause of a failure stretches into hours. We set up a unified observability stack turnkey: we connect data streams, build dashboards, and hand over ready runbooks to the team. Diagnostic time is reduced several times over.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Observability stack: why metrics, logs, and traces diverge

An assembled observability stack often looks like this: metrics in one system, logs in a second, traces in a third, and each is configured on its own. Graphs are built, records are written, requests are traced — individually, everything looks healthy.

The gap shows up during an incident: there is no way to assemble a single picture from three sources because there is no common key between them.

The typical correlation gap between metrics and logs starts with time. A metric stores the measurement moment, a log record stores the processing moment on a specific node, and a trace stores the start and end of an operation.

With time zone differences and event delivery delay, events of the same request diverge on the timeline by minutes.

The request identifier in tracing and in the log are generated by different libraries, so matching is done by service and interval coincidence — that is, approximately.

Then manual search for the cause of the failure begins. The on-call engineer sees latency growth on a summary graph, opens logs and filters them by service, then goes to tracing and looks for a similar request.

The search takes tens of minutes per service: until the cause is found, some requests fail, and similar incidents repeat — conclusions remain in chat rather than in alerting rules.

Disparate observability systems are addressed by integration, not by replacing tools. An end-to-end identifier passes through all levels, timestamps are brought to a single scale, and an alerting rule references the graph, records, and trace of a specific request at once. We explain how this is arranged and what changes in the work of the on-call shift.

What a unified observability stack delivers: the effect in numbers

When metrics, logs, and distributed tracing live in different systems, the on-call engineer matches them manually by timestamps. Localizing the cause of a failure takes tens of minutes, and most of the downtime is spent not on remediation but on searching.

We bring three signals together into a unified observability stack: we instrument services via OpenTelemetry so that the request identifier passes end-to-end through the metric, log, and trace.

Next, correlation by request identifier comes into play. A single incident card is assembled from three sources: you can see which service first returned an error, what was happening nearby at the same moment, and how the metrics of neighboring services changed a minute before. Investigation stops being window switching and turns into reading a single document.

What changes measurably:

  • Time to localize the cause of a failure — from 40–60 minutes of manual matching to 5–10 minutes using a ready incident card.
  • Share of failures investigated without switching between systems — from 30 to 85%: the context is already collected in one place.
  • Repeat visits to the same incident are cut by a factor of three — questions like “show the logs” disappear.
  • Downtime in the “unclear where to look” phase stops being its main part, and diagnostics becomes a short investigation step.

Deployment options: self-hosted, managed, hybrid

The deployment mode is chosen not by the set of tools but by where metrics, logs, and traces physically reside and who is responsible for their availability.

Self-hosted deployment gives full control: data sovereignty, arbitrary retention periods, your own compression and aggregation rules, and the ability to ingest non-standard sources.

The cost is a team that maintains the storage, component updates, and on-call duty; as label cardinality grows, the cluster hits disk limits before CPU limits.

A managed observability service shifts operations to the provider, but data leaves the perimeter, and storage requirements become a variable: the retention period and cardinality volume directly affect the bill.

A hybrid data collection scheme keeps sensitive logs inside the perimeter and sends aggregates, metrics, and alerts outside — this addresses both data sovereignty and the need for ready-made dashboards.

Option When it fits Limitations
Self-hosted deployment Data sovereignty requirements, non-standard sources, predictable load Engineers on call are required; storage scaling and updates are on you
Managed observability service Rapid correlated metrics, logs, and traces without running your own operations Data outside the perimeter; costs grow with volume and retention period; little room for custom processing
Hybrid data collection scheme Some data cannot be exported, but ready-made dashboards and alerting are needed More complex routing; you need to monitor label consistency and time accuracy

In practice, modes are often combined: the alerting core and long-term storage go where retention requirements make it advantageous, and streaming data stays closer to sources. We draw the boundary by data, not by tools.

Implementation stages: flow audit, design, configuration, handover

Implementation of the observability loop goes from inventory to handover: each stage relies on data from the previous one.

Below is the sequence we use to run the project; it protects against the typical mistake when tools are already deployed but correlation of metrics, logs, and traces has still not appeared.

  1. Telemetry source audit. We compile a list of services, databases, brokers, and external dependencies: who already emits metrics, where logs are stored as files, and who is not instrumented at all. Here we also record flow volume — it determines storage capacity.
  2. Collection and storage design. We decide where data is buffered during peaks, what goes to hot storage and what goes to archive, and which retention periods cover incident investigation. We calculate volume growth in advance so storage does not run out in the third month.
  3. Service and request labeling. We introduce unified labels: service, environment, build version, request identifier. These are what later glue the metric, log, and trace into a single incident picture.
  4. Configuration of collection, dashboards, and alerts. We connect agents, downsample high-frequency metrics, assemble dashboards for key paths and create alerting rules for meaningful indicators rather than every spike.
  5. Validation with a training incident. We break a service in an agreed window: did the alert arrive, was the entire chain found by request identifier, and did detection fit within the target time.
  6. Handover of the operations loop. To the on-call team — procedures, checklists, a training incident review, and training; we stay in touch until on-call rotations reach normal mode.

What remains with you: configurations, dashboards, procedures

The observability loop lives longer than the project, so we hand it over in a way that your engineers can change the set of metrics, edit thresholds, and connect new services without us.

Everything resides in your repository: configurations, dashboards, and procedures are versioned, reviewed, and rolled back like regular code.

  • Configuration package for collecting metrics, logs, and traces: declarative agent descriptions, parsing and downsampling rules — the environment can be brought up from scratch using the same files.
  • Monitoring dashboards as versioned files: each graph specifies which signal it shows, which values are considered normal, and what to do when they go beyond them.
  • Alerting rules with on-call bindings, escalation, and repeat suppression — the on-call engineer receives one meaningful signal instead of a stream of identical ones.
  • Response procedure: from alert trigger to rollback, with actions distributed between the on-call engineer and the service owner and mandatory documentation of the incident investigation.
  • Access roles and policies: separation of read and change permissions, data retention periods, masking of sensitive fields in logs.
  • Operations documentation: data flow diagram, list of failure points, launch checklists, scheduled updates, and post-failure recovery.

We separately provide a set of checks that validate configurations before application: a change that breaks the correlation of metrics, logs, and traces does not reach the production environment.

Handover is not a folder of files but a working loop — we go through typical tasks with your engineers: connect a service, reduce noise, find the cause by a single request identifier.

Case study: we cut the time to find the cause of a failure severalfold

The customer's platform handled an order flow, and observability was split across three loops: metrics lived in one window, logs in a second, and traces were collected by a separate agent.

The request identifier did not match anywhere, so the on-call engineer reconstructed the request path manually — by time and by matching error text. Investigating one complaint took up to forty minutes, and in about half of cases the cause was never confirmed by data.

We brought the three loops into a unified observability layer on Grafana: a single entry point for the on-call engineer, an end-to-end request identifier in metrics, logs, and traces, and common service and environment labels.

We moved alerts from individual spikes to rules based on error rate over a window — a class of false positives on short spikes that woke the on-call engineer at night disappeared.

Metrics before and after

Metric Before After
Time to localize the cause of a failure 20-40 minutes 3-7 minutes
Share of failures with fast localization about 40% more than 90%
Entry points for the on-call engineer three loops one screen
False positives per week tens single digits

The load on the operations team shifted: incident investigation no longer requires three engineers and a call — the on-call engineer finds the source and passes the task to the service owner.

A separate class of “silent” degradations was also addressed: an increase in response time without errors in logs is now visible in traces rather than discovered through a customer complaint.

What to do if some services already write to another storage system

There is no need to rewrite services: the ingestion address changes, the code does not. There are three working schemes, and they combine with each other — an intermediate collection layer, enrichment at read time, and phased data migration.

An intermediate layer sits between services and storage: on the host or in the container environment, the ingestion address changes, and the application does not know about it.

The collector accepts both formats, brings label names, log fields, and trace attributes to a single dictionary, and assigns a common identifier — by which the metric, log, and trace are linked into one chain.

Dual-write of telemetry provides a transition without downtime: events go to both the old and the new storage, and existing dashboards and alerting rules continue to work. We switch over only after counter values and the number of events per service match.

We migrate historical data partially: usually the window that is actually viewed during incident investigation is sufficient, and older records are served by storage in read-only mode. Report continuity is preserved, and the new loop does not grow to the entire archive at once.

If some services already write to Elasticsearch, we enable read-time enrichment: the query layer combines the output of both loops and joins it by trace identifier. This way the new loop fills gradually, and access to previous data is not lost at any stage.

Technical concerns: storage, load, access

The volume of telemetry and its retention period is the first question at the assessment stage. Below are answers to what customer engineers most often clarify: how much data to keep, how collection affects production services, and how access to logs is separated.

How long should metrics, logs, and traces be stored?

Data classes follow different policies. We keep metrics at full resolution for several weeks, then downsample to minute and hour aggregates with storage up to a year. Logs are rotated by level and source, and traces are written selectively — errors and slow requests with context. Outdated data goes to archive and is retrieved on request, so the main loop remains fast.

Will collection start slowing down production services?

The collection agent buffers records locally and sends them in batches, not one by one. CPU and memory consumption is capped, and if the collection node is unavailable, data is written to disk and sent later. On critical services, we enable selective collection — overhead remains within a few percent.

How should access to logs be separated?

We grant access by roles across sources, services, and environments, not “to the entire storage.” Sensitive fields are masked at ingestion, and even someone with access to the log itself does not see them. Data access is recorded in an audit log.

What happens if a collection node goes down?

Collection nodes run in several replicas behind a load balancer: one going down does not interrupt the flow, and traffic is redistributed. Agents continue writing to the local buffer and send the accumulated data after recovery, so the data gap is measured in minutes, not hours.

Let's discuss your task: where we start and what we clarify

To come back with a staged plan and timeline estimate rather than general considerations, we need a snapshot of your loop: what is already being collected, where the connection between metrics, logs, and traces of a single incident is lost, and what decisions are made based on this data today.

The list of inputs that is usually sufficient for the estimate:

  • services and environments: list of components, number of environments, their owners, and rollout order;
  • current collection: agents and exporters, metric and log formats, what traces are captured with, and where everything is written;
  • volumes: how many time series and log records per day, label cardinality, required retention depth;
  • correlation: whether an end-to-end request identifier is propagated between services, and whether the metric, log, and trace of a single failure are linked;
  • signals: which events are on call, who receives them and where, and how many false positives occur per shift;
  • constraints: data placement requirements, network segments, access, and environments without external egress;
  • acceptance criteria: what we consider the result — time from error to signal, share of requests with a complete trace, and incident investigation time.

Then we break the work into stages: source inventory, collection and storage design, correlation configuration, alerts, and the on-call shift procedure. For each, we will give a timeline and an area of responsibility.

Describe the task in your own words — an engineer who will lead the project will respond, and we will come back with an estimate and plan.