Distributed Tracing Basics in Kubernetes

Distributed Tracing Basics in Kubernetes

Learn how to follow a single request as it travels through many services in your cluster, how traces, spans, and context fit together, and how to collect, store, and read them safely, from first principles to production habits.

Imagine sending a parcel across the country. It leaves your house, reaches a local depot, travels on a truck to a sorting centre, moves onto a plane, lands in another city, and finally a courier knocks on the door. If the parcel arrives three days late, you want to know where it waited. The tracking page helps, because every stop scans the parcel and adds a line with a time. From those lines you can see that the plane was quick but the parcel sat for two days in the sorting centre.

Distributed tracing is a tracking page for requests inside your software. When a customer clicks a button, that one click may pass through a dozen small programs before an answer returns. Tracing records each stop, how long it took, and how the stops connect. This tutorial explains the idea from the ground up, shows how it works inside Kubernetes, and gives you the patterns, dangers, and habits that real teams rely on.

1Why We Need Tracing

When one request touches many programs, finding the slow or broken part becomes a detective story. Tracing gives the detective a map.

From one big program to many small ones

Years ago, most applications were one large program. A request came in, the program did all the work, and an answer went out. If something was slow, you looked inside that one program. Today, many teams split their software into microservices. A microservice is a small program that does one job, such as handling logins, calculating prices, or sending emails. Each one runs in its own container, and Kubernetes keeps them all running.

This split has real benefits. Teams can change one small part without touching the others, and parts can grow independently. But it also creates a new problem. A single click by a customer may cause the website to call the login service, which calls the user database, then the price service, then the stock service, then the payment service. Any one of these could be slow or broken.

Simple Analogy

Think of ordering a meal at a busy restaurant with many kitchen stations. One station chops, one grills, one plates, and one adds sauce. If your meal takes forty minutes, the waiter cannot tell you why by looking at the finished plate. You need a slip that every station stamps with the time it received and finished the order. The stamped slip is a trace.

What the other tools cannot tell you

You may already have metrics, which are numbers over time such as requests per second. You may also have logs, which are lines of text that programs write about what they did. Both are valuable. But metrics tell you that the checkout is slow on average, without saying which step is slow. Logs from twelve different programs are written in twelve different places, and it is hard to tell which lines belong to the same customer click.

Tracing fills this gap. It ties together everything that happened for one request, across all the programs, in order, with times. With a trace open, you can say, “this request spent eight hundred milliseconds waiting for the stock service, and the stock service spent most of that time waiting for its database.”

1 request
followed from the first program to the last
Many services
each adds its own step to the same story
Time
every step shows when it started and how long it took

Questions a trace answers

Question 1

Where is the time going?

A trace shows which step in a long chain is slow, so you fix the right thing.

Question 2

Where did it fail?

When a request returns an error, the trace shows which program first went wrong and which ones only passed the error along.

Question 3

Who calls whom?

Traces reveal the real paths between services, which are often different from what the diagrams on the wall say.

Question 4

Did the release help?

Comparing traces before and after a change shows whether a step became faster or slower.

i
Tracing does not replace metrics and logs

The three work as a team. Metrics tell you that something is wrong, traces show where, and logs explain why. Later in this tutorial you will see how to connect all three.

2The Core Idea: Traces, Spans, and Context

Three simple words carry the whole idea. A trace is the story, a span is one step of the story, and context is the thread that ties the steps together.

The trace

A trace is the complete record of one request as it moves through your system. It starts when the request first enters, for example when a customer clicks a button, and ends when the last program has finished its part. Every trace has a unique identifier, called the trace ID, which is a long random number. All the steps that belong to the same request carry the same trace ID.

The span

A span is one unit of work inside a trace. It has a name, a start time, and an end time, so it knows how long it took. A span might be “handle the checkout request,” “ask the stock service,” or “run a database query.” Each span has its own span ID. It also remembers the ID of the span that caused it, which is called its parent. The first span in a trace has no parent and is called the root span.

Because each span knows its parent, spans form a tree. The root is the whole request, its children are the steps it took, and their children are the smaller steps inside those.

flowchart TD
    ROOT["Root span: checkout request, 900 ms"] --> A["Span: check login, 60 ms"]
    ROOT --> B["Span: get prices, 120 ms"]
    ROOT --> C["Span: reserve stock, 650 ms"]
    ROOT --> D["Span: take payment, 40 ms"]
    C --> C1["Span: database query, 600 ms"]
    B --> B1["Span: cache lookup, 5 ms"]
        
FIG 1 — One trace shown as a tree of spans, with time spent at each step

Look at the figure. The whole checkout took 900 milliseconds. Login, prices, and payment were quick. Reserving stock took 650 milliseconds, and nearly all of that was a single database query. Without the tree, you would only know that checkout was slow. With it, you know the database query inside the stock service is the place to look.

Simple Analogy

A trace is like a family tree drawn for one event. The root is the grandparent, who starts things off. Each child is someone who was asked to do a part, and each grandchild is someone that child asked for help. Everyone carries the same family name, which is the trace ID, and everyone knows who their parent is.

Context

Here is the tricky part. The programs are separate and do not share memory. How does the stock service know that its work belongs to a checkout that began in a different program? The answer is context. Context is a small package of identifiers, mainly the trace ID and the ID of the calling span, that travels along with the request. When one program calls another, it attaches this package to the call. The receiving program reads it, and creates its own span as a child of the sender’s span.

Passing this package along is called context propagation. It is the heart of distributed tracing. If any program in the chain forgets to pass it on, the trace breaks into two separate pieces.

WordPlain meaningEveryday comparison
TraceThe full journey of one requestThe whole tracking page of a parcel
SpanOne step in the journey, with start and end timesOne scan at a depot
Trace IDThe number shared by every step of one requestThe parcel number
Span IDThe number of one particular stepThe scan number
ParentThe step that caused this stepThe depot that sent the parcel on
ContextThe identifiers that travel with the requestThe label stuck on the parcel
!
A broken chain gives a broken story

If one service does not pass the context on, everything after it starts a new trace. You then see many short traces instead of one long one, and the connection between them is lost. Most tracing problems in real systems are missing context.

3Kubernetes Building Blocks You Need First

Before tracing inside a cluster, here is a short guide to the Kubernetes words that will appear again and again.

Containers, pods, and nodes

A container is a small box that holds a program and everything it needs to run. A pod is the smallest thing Kubernetes runs, and it holds one or more containers that work closely together. A node is a computer, real or virtual, that runs pods. A cluster is a group of nodes managed together.

Deployments and services

A Deployment tells Kubernetes to keep a chosen number of identical pods running. If one crashes, a new one is started. A Service gives a group of pods a single stable name and address, so other programs can find them even when the pods behind the name change. When the checkout program wants the stock program, it calls the stock Service by name, and Kubernetes sends the call to one of the healthy stock pods.

Simple Analogy

A Service is like the phone number of a shop. The shop may have several people behind the counter, and staff may change during the day, but customers always dial the same number, and someone answers.

Namespaces, ConfigMaps, and environment variables

A namespace is a named area inside the cluster that keeps related things together. A ConfigMap holds settings as text, and pods can read them when they start. An environment variable is a named setting handed to a program when it starts. These matter for tracing, because a program usually learns where to send its trace data, and what to call itself, through environment variables and settings supplied by Kubernetes.

DaemonSets and sidecars

A DaemonSet makes sure that one copy of a pod runs on every node. It is often used for helper programs that must be near everything else, such as collectors of data. A sidecar is a helper container that runs in the same pod as the main container, sharing its network. Sidecars are used to add features, such as traffic handling or data collection, without changing the main program.

Word 1

Pod

The smallest running unit. Each service in a trace usually runs in one or more pods.

Word 2

Service

A stable name and address for a group of pods. Calls between programs go through Services.

Word 3

DaemonSet

Runs one helper pod on every node, a common home for trace collectors.

Word 4

Sidecar

A helper container living beside the main one in the same pod.

Word 5

Namespace

A named area of the cluster, often used to separate teams or tools.

Word 6

Environment variable

A named setting passed to a program at start, often used to say where to send traces.

Why Kubernetes makes tracing both harder and easier

It makes tracing harder because pods appear and disappear, so traces must be sent out quickly before a pod vanishes, and pod names change constantly. It makes tracing easier because Kubernetes gives every program a standard way to find its neighbours, to receive settings, and to run helper pods on every node. Those standard features are exactly what a tracing system needs.

4What Is Inside a Span

A span is more than a name and two times. It carries extra details that make a trace useful when you are searching for a problem at three in the morning.

The parts of a span

PartWhat it holdsWhy it helps
NameA short label for the work, such as “reserve stock”Lets you read the trace like a sentence
Start time and durationWhen it began and how long it lastedShows where time is spent
Trace ID and span IDThe identifiers linking it to the restLets tools rebuild the tree
Parent span IDThe step that caused this oneGives the tree its shape
KindWhether it is a server, client, producer, consumer, or internal stepTells tools which side of a call it is
AttributesKey and value pairs, such as the method used or the status code returnedLets you search and filter
EventsTime-stamped notes inside the span, such as “retrying”Records important moments
StatusWhether the work succeeded or failedLets you find failing requests fast
LinksReferences to other traces or spansConnects work that is related but not a parent and child

Span kinds

When one program calls another, two spans are usually created. The caller makes a client span that measures how long it waited. The receiver makes a server span that measures how long it worked. The difference between the two is the time spent travelling over the network and waiting in queues. That gap can be surprisingly large and is often the clue to a hidden problem.

When work is passed through a message queue, the sender makes a producer span and the receiver makes a consumer span. Steps that stay inside one program are called internal spans.

Simple Analogy

Suppose you phone a plumber. You time how long the whole call felt from your side, and the plumber times how long they actually spent working. If you waited ten minutes but the plumber worked for two, eight minutes went missing on hold. Client and server spans measure both sides so the missing time shows up.

Attributes: the labels you can search by

Attributes are pairs of a name and a value attached to a span. Examples are the web address called, the method used, the response code, the name of the database, or the name of the customer tier. They are what let you ask questions like “show me all slow requests to the payment service that failed for the premium tier.”

The tracing community has agreed on common names for many attributes, known as semantic conventions. Using the standard names means that tools from different makers understand your data, and your teams do not each invent their own words for the same idea.

Resource attributes: who made the span

Some details describe the program that made the span rather than the work itself. These are called resource attributes. They include the service name, the version, the pod name, the namespace, and the node. Kubernetes supplies most of them. They let you say, “this slow span came from version 2.3 of the stock service, running in pod number four, on this node.”

i
Always name your services clearly

A trace with services called “app”, “server”, and “backend” is hard to read. Give each service a clear, unique name, and keep it the same across environments, so that searches and diagrams make sense.

!
Do not stuff secrets into attributes

Attributes are stored and often shown to many people. Never put passwords, tokens, full card numbers, or private personal details into them. We return to this in the security chapter.

5Context Propagation: Passing the Baton

Everything in tracing depends on the trace ID reaching the next program. Here is how that happens, and why a standard matters.

How context travels

Programs usually talk to each other over the web, using a protocol called HTTP, or through a faster protocol called gRPC. Both allow small extra pieces of information, called headers, to be added to each call. Tracing uses a header to carry the context. The calling program adds it. The receiving program reads it, and creates its own span linked to the caller’s span. It then adds the header again on every call it makes to others.

Simple Analogy

Think of a relay race. Each runner carries a baton and hands it to the next. The baton is the context. If a runner drops it, the next runner cannot continue the race as a team. They can only run alone, and the record of the race is split in two.

A shared standard

In the past, different tracing tools used different header names and formats. A program using one tool could not pass context to a program using another. Today, most systems follow a standard from the World Wide Web Consortium, called W3C Trace Context. It defines a header named traceparent, which carries the trace ID, the parent span ID, and a flag telling whether this trace is being recorded. A second header can carry extra vendor-specific details.

Older formats still exist, such as the B3 headers from the Zipkin project. Modern tools can usually read and write several formats at once, which helps when a system is halfway through a move.

FormatWhere it comes fromNotes
W3C Trace ContextWeb standards bodyThe modern default, widely supported
B3Zipkin projectCommon in older systems
Vendor formatsIndividual product makersAvoid for new work unless needed

Baggage

Besides the identifiers, context can carry small extra facts called baggage, such as the customer tier or the region. Baggage travels to every program down the chain, so each can use it in its own spans. It is powerful, but it is also sent on every call, and it may leave your system when you call outside services. Use it sparingly and never for anything private.

Where context gets lost

Context is most often lost in a few predictable places. Message queues and background jobs are common, because the work does not run inside the original call. Programs that start their own worker threads may forget to carry context across. Proxies, gateways, and load balancers may drop unknown headers. And any program that has no tracing at all simply does not pass the header on.

Leak 1

Message queues

The context must be stored in the message itself and read back by the consumer.

Leak 2

Background threads

Code that hands work to another thread must also hand over the context.

Leak 3

Gateways and proxies

Some strip headers they do not know. Configure them to pass trace headers through.

Leak 4

Untraced services

A single old service without tracing can cut the chain in two.

i
Agree on one format across the company

Choose the standard format, and make sure every gateway, mesh, and library is set to use it. Mixed formats are a common cause of traces that break in the middle.

6Instrumentation and OpenTelemetry

Programs do not create spans by themselves. Someone, or something, must add the tracing. This is called instrumentation.

What instrumentation means

Instrumenting a program means adding the pieces that create spans, pass context, and send the results out. Think of it as fitting a program with sensors. There are two broad ways to do it.

Way 1

Automatic instrumentation

A tool attaches to the program when it starts and creates spans for common actions, such as web calls and database queries, without changing the code. It is quick to adopt and gives instant coverage.

Way 2

Manual instrumentation

Developers add spans in their own code around important business steps, such as “apply discount.” It takes more work but adds meaning that no tool can guess.

Most teams begin with automatic instrumentation to get broad coverage, then add manual spans in the few places where the business logic matters most.

Simple Analogy

Automatic instrumentation is like fitting a car with a standard tracker that records speed and location. Manual instrumentation is like the driver noting in a diary, “stopped here to pick up the client.” The tracker gives coverage, and the diary gives meaning.

OpenTelemetry

OpenTelemetry, often written OTel, is the open standard and set of tools for collecting traces, metrics, and logs. It is a project of the Cloud Native Computing Foundation, and it is now the common way to instrument programs. It offers three main things. First, a specification that defines what spans, attributes, and context look like. Second, libraries called SDKs and APIs for many programming languages. Third, a program called the Collector that receives, processes, and forwards telemetry data.

The great benefit is freedom. If your programs speak OpenTelemetry, you can send the data to almost any tracing backend, and change the backend later without touching your applications. It replaced older projects called OpenTracing and OpenCensus, which were merged into it.

flowchart LR
    APP["Application with OpenTelemetry SDK"] -->|"OTLP"| COL["OpenTelemetry Collector"]
    COL --> BE1["Tracing backend, such as Jaeger or Tempo"]
    COL --> BE2["Another tool or vendor service"]
    BE1 --> UI["Trace viewer for people"]
        
FIG 2 — Programs send trace data in a standard format, and the Collector forwards it to any backend

Read the figure from left to right. The application uses the OpenTelemetry SDK to create spans. It sends them, using a standard protocol called OTLP, to the Collector. The Collector can process the data and forward it to one or several backends. People then use a trace viewer to read the results.

Instrumenting in Kubernetes

Kubernetes adds a helpful option here. An OpenTelemetry Operator can be installed in the cluster. An operator is a helper program that manages other programs by watching special Kubernetes objects. With it, you can add a simple note, called an annotation, to a Deployment, saying that its pods should be automatically instrumented. The operator then injects the instrumentation into new pods when they start, and sets the settings that tell them where to send data. This lets a platform team turn on tracing for many services without asking every developer to change code.

!
Automatic does not mean free

Automatic instrumentation adds a small amount of work to every request, and it may create more spans than you want. Test it on one service first, check the added delay and memory, and make sure it supports the language and libraries you use.

Real-World Use Case

A team runs twenty services written in three languages. Instead of asking each team to add tracing code, the platform team installs the OpenTelemetry Operator and labels each Deployment for automatic instrumentation. Within a day, traces from all twenty services appear in one viewer. Later, the payments team adds a few manual spans around “fraud check” and “apply discount,” because those steps matter most to the business.

7Architecture of a Tracing Stack in Kubernetes

A working tracing setup has a handful of parts. Each has one clear job, and knowing them makes the whole picture simple.

The main parts

Part 1

Instrumented applications

Your own programs, fitted with an SDK or automatic instrumentation. They create spans and pass context.

Part 2

Agent collector

A Collector running close to the applications, often one per node as a DaemonSet, or beside each pod as a sidecar. It receives spans quickly and adds Kubernetes details.

Part 3

Gateway collector

A central group of Collectors, run as a Deployment, that receives data from all the agents, applies rules such as sampling, and forwards to storage.

Part 4

Storage backend

A database designed for traces. Well-known open source choices include Jaeger and Grafana Tempo, and there are many hosted services.

Part 5

Query service and viewer

The part that searches stored traces and draws them for people, often with a timeline of spans.

Part 6

Service mesh or gateway (optional)

Network helpers that can create spans for traffic between services, filling gaps in programs that are not instrumented.

Simple Analogy

Picture a postal system for tracking data. Each depot scans parcels, which are your applications. A local post office collects scans from the depots nearby, which is the agent. A regional sorting centre gathers from many post offices and decides which to keep, which is the gateway. A central archive stores the records, and a public website lets you look them up.

Why two layers of collectors

You could send spans straight from every application to storage. That works for a tiny system, but it has problems. Every application would need the storage address and any secret needed to reach it. Any slowdown in storage would slow the applications. And there would be nowhere to apply shared rules.

Adding a Collector in the middle solves these. Applications send to a nearby agent and move on quickly. The agent adds details such as the pod name and namespace, batches spans together, and forwards them. A central gateway can then make decisions that need a wider view, such as keeping all traces that contain an error. Only the gateway needs the credentials for storage.

LayerTypical way to run itMain jobs
AgentDaemonSet, one per node, or a sidecarReceive quickly, add Kubernetes details, batch, forward
GatewayDeployment with several replicas behind a ServiceSample, filter, remove private data, route to storage
BackendStatefulSet or managed serviceStore, index, and answer searches

The Collector’s own pieces

Inside every Collector are three kinds of building blocks that are joined into pipelines. Receivers accept data, for example in the OTLP format. Processors change data on the way through, for example by batching, adding labels, or dropping items. Exporters send data out to another system. A pipeline is simply a chosen list of receivers, processors, and exporters for one type of data.

i
Start simple

Begin with one agent per node and one small gateway. Add more layers only when volume or rules demand them. A simple pipeline is easier to understand and to fix.

Choosing a backend

OptionCharacterGood when
JaegerMature open source tracing system with its own viewerYou want a classic, well-known choice with flexible storage
Grafana TempoStores traces cheaply in object storage, and works closely with GrafanaYou already use Grafana and want low storage cost at high volume
ZipkinThe older open source tracing systemYou have existing Zipkin tools
Hosted serviceA vendor runs storage and viewingYou prefer to pay rather than operate it
Real-World Use Case

A company with about eighty services runs an OpenTelemetry Collector on every node. Those agents forward to a gateway of three Collectors that keep every failed trace and a small share of the successful ones, then send the result to Tempo backed by object storage. Developers open traces from Grafana. When they change to a different backend a year later, only the gateway settings change, and no application is touched.

8Internal Working: One Request, Step by Step

Let us follow one customer click through three services and see exactly where each span and each header comes from.

The journey

A customer clicks “buy.” The click reaches the front door of the cluster, a gateway program. It has no trace yet, so it starts one and creates the root span with a new trace ID. It then calls the checkout service and adds the context header. The checkout service reads the header, creates its own server span as a child, and calls the stock service, again adding the header. The stock service creates its span, asks its database, and replies. Each program finishes its span when its work is done, and hands the finished span to the nearby agent.

sequenceDiagram
    participant U as Customer
    participant G as Gateway
    participant C as Checkout service
    participant S as Stock service
    participant A as Agent collector
    U->>G: Click buy
    G->>G: Start trace and root span
    G->>C: Call with context header
    C->>C: Create child span
    C->>S: Call with context header
    S->>S: Create child span and query database
    S-->>C: Reply
    C-->>G: Reply
    G-->>U: Answer
    S->>A: Send finished span
    C->>A: Send finished span
    G->>A: Send finished span
        
FIG 3 — A request travels forward, and finished spans flow to the collector on the side

Notice two separate flows. The request itself moves along the chain, carrying the context. Meanwhile, each program sends its finished spans, quietly and separately, to the agent. The spans are not returned in the reply. This keeps tracing away from the customer’s response path, so a problem in the tracing system does not have to slow the customer.

Simple Analogy

Think of a courier chain again. The parcel moves from courier to courier with a label. Meanwhile, each courier phones the head office with their own note, “I received it at two, and passed it on at three.” The head office pieces the notes together later using the number on the label.

What happens inside one program

Inside a program, the SDK keeps track of the current span, usually in a small holder that follows the running work. When the program starts a new piece of work, the SDK creates a new span whose parent is the current one. When that work ends, the SDK closes the span, records the end time, and places it in a queue. A background helper takes spans from the queue, groups them into batches, and sends them to the collector. Batching keeps the cost per span low.

What the collector does

When spans arrive at an agent, a processor adds Kubernetes details. It looks at the source of the connection, asks the Kubernetes API which pod that is, and attaches the pod name, namespace, node, and labels to the spans. Another processor batches them. The agent then forwards them to the gateway. The gateway may hold spans in memory for a short time, because it must wait for all the spans of a trace to arrive before it can decide whether to keep the trace.

How a trace is assembled

Spans reach the backend at different times and from different places. The backend groups them by trace ID and uses the parent IDs to rebuild the tree. A span whose parent has not yet arrived is temporarily an orphan, and it joins the tree when the parent shows up. If a parent never arrives, because a service was not instrumented or a span was lost, the viewer shows a gap or a missing parent. This is a useful clue that something upstream is not reporting.

Async
spans are sent after the work, off the customer’s path
Batch
spans are grouped to save effort per span
By ID
the backend joins spans using trace and parent IDs
!
Clocks matter

Each span’s times come from the clock of the machine that made it. If two machines disagree about the time, a child may appear to start before its parent. Keep node clocks synchronised using standard time services, and remember that small differences are normal.

The role of a service mesh

A service mesh is a layer of small network helpers, often sidecars, that handle traffic between services. Because they see every call, they can create spans for the network part of each hop, even for programs with no instrumentation. This gives a rough picture of who calls whom and how long each call took. However, a mesh cannot see inside a program, and it cannot pass context from an incoming call to an outgoing one unless the program itself copies the headers. So a mesh helps, but does not replace instrumentation.

9Sampling: Keeping the Traces That Matter

A busy system produces far more traces than anyone can store or read. Sampling means deciding which ones to keep.

Why not keep everything

Imagine a service that handles ten thousand requests each second. Each request creates a trace with maybe twenty spans. That is two hundred thousand spans every second, around the clock. Storing and searching all of it would be very costly, and most of it would be nearly identical successful requests that nobody will ever look at. Sampling reduces the volume while keeping enough to learn from.

Simple Analogy

A bakery does not keep a photo of every loaf. It keeps a few photos for quality checks, and it always keeps a photo of any loaf that came out burnt. Sampling is the same: keep a small share of the ordinary ones, and keep every unusual one.

Head sampling

In head sampling, the decision is made at the very start of the trace, when the root span is created. For example, the system might decide to keep one trace in every hundred. The decision is written into the context flags, so every later program follows it. This is cheap and simple, because unwanted traces are never recorded. The weakness is that the decision is made before anyone knows how the trace will turn out. An interesting failure has only a one in a hundred chance of being kept.

Tail sampling

In tail sampling, the decision is made at the end, after the whole trace has been collected. The system can then keep traces that had errors, or that took longer than a chosen time, and keep only a small share of the rest. This keeps the most useful traces. The price is complexity. All the spans of a trace must reach the same collector, so it can see the whole trace, and that collector must hold spans in memory while it waits. This is usually done in the gateway layer.

flowchart TD
    START["Request arrives"] --> H{"Head sampling: keep this one?"}
    H -->|"No"| DROP1["Not recorded"]
    H -->|"Yes"| REC["Spans recorded and sent"]
    REC --> T{"Tail sampling at gateway"}
    T -->|"Trace has an error"| KEEP1["Keep"]
    T -->|"Trace is very slow"| KEEP2["Keep"]
    T -->|"Ordinary and fast"| PROB{"Random small share?"}
    PROB -->|"Chosen"| KEEP3["Keep"]
    PROB -->|"Not chosen"| DROP2["Discard"]
        
FIG 4 — Head sampling decides early and cheaply, tail sampling decides late and wisely

The figure shows both methods working together. Head sampling can cheaply throw away a large share at the start. Tail sampling then inspects what remains and always keeps the errors and the slow ones, while keeping only a small random share of ordinary traces.

MethodWhen it decidesStrengthWeakness
Head, fixed shareAt the startSimple, cheap, low overheadMay miss rare failures
Tail, rule basedAfter the trace endsKeeps errors and slow tracesNeeds memory and careful routing
Always onNever dropsComplete dataCostly at high volume
Always offNever recordsNo costNo tracing at all

Practical rules of thumb

Keep all traces in small systems and in test environments, because volume is low and the detail is valuable. In larger systems, use a low fixed share at the head, and add tail rules at the gateway that keep every trace with an error and every trace slower than a threshold. Always record the sampling rate, so that when you count traces in the viewer you know that each one stands for many.

i
Do not use traces for counting

Because of sampling, the number of stored traces is not the number of requests. Use metrics for counts and rates, and use traces for the detail of individual requests.

!
Tail sampling needs all spans in one place

If spans of the same trace are spread across several gateway pods, none of them can judge the whole trace. Route spans by trace ID so that all spans of a trace reach the same gateway pod, or use a two-layer design built for this.

10Data Flow and Lifecycle of a Trace

Follow one trace from the first click to its final deletion.

1

Start

A request enters the system. The first program creates a trace ID and a root span, and makes the head sampling decision.

2

Propagation

The request moves from program to program. Each one reads the context header, creates a child span, and passes the header on.

3

Finish and queue

Each span closes when its work ends and waits in a small queue inside the program.

4

Export to the agent

A background helper sends batches of spans to the nearby agent using the standard protocol.

5

Enrich and forward

The agent adds pod, node, and namespace details, batches again, and forwards to the gateway.

6

Decide

The gateway waits until the trace looks complete, then applies tail sampling and privacy rules.

7

Store and index

The backend writes the spans, and indexes chosen fields, such as the service name and the status, so they can be searched.

8

Search and read

A person finds the trace by its ID, or by searching for slow or failed requests, and reads the timeline of spans.

9

Retire

After the retention period, often days or a few weeks, the trace is deleted to save space and reduce risk.

Simple Analogy

A trace’s life is like a letter in a busy office. It is written, carried from desk to desk with notes added, copied by the mailroom, filed in the archive by a clerk who decides what is worth keeping, looked up when a question arises, and shredded after the retention period passes.

What happens when things fail

If the agent is down, the SDK’s queue fills up. Well-built SDKs drop the oldest spans rather than block the application, because tracing must never break the thing it observes. If the gateway is overloaded, agents may buffer briefly and then drop data. If the backend is down, the gateway may keep data in a limited queue. In every case, the goal is the same: protect the customer’s request first, and accept that some trace data may be lost.

i
Losing a little is acceptable, blocking is not

Tracing is diagnostic information. It is fine to lose a few spans during trouble. It is never fine for tracing problems to make customer requests slow or fail. Check that your queues have limits and that timeouts are short.

Choosing retention

Kind of traceSuggested keeping timeReason
Ordinary sampled tracesA few days to two weeksMost investigations happen soon after an event
Error and slow tracesTwo to four weeksUseful for reviews after an incident
Traces linked to an incidentCopy out and keep with the reportPreserve evidence for learning

11Connecting Traces, Metrics, and Logs

Each signal answers a different question. The magic happens when you can jump between them in a single click.

Three signals, three roles

SignalWhat it isBest at
MetricsNumbers over timeNoticing that something is wrong, and how big it is
TracesThe path and timing of single requestsFinding where in the chain the problem is
LogsText written by programsExplaining exactly what happened and why
Simple Analogy

Consider a doctor’s visit. The thermometer reading is a metric: it says you have a fever. The scan showing which organ is inflamed is like a trace: it says where. The doctor’s notes about symptoms and history are the logs: they say why. A good doctor uses all three together.

Logs that carry the trace ID

The simplest and most valuable link is to write the trace ID and span ID into every log line. Most logging libraries can do this automatically when tracing is set up. Then, from a slow trace, you can search your logs for that trace ID and see every log line from every service for that one request. Conversely, from an error log, you can copy the trace ID and open the whole trace.

Exemplars: from a number to a trace

Metrics are averages and totals, so they hide individual requests. An exemplar is a small link stored alongside a metric value that points to one example trace. A chart of slow requests can then show dots, and clicking a dot opens a real trace that contributed to that point. This is one of the fastest ways to move from noticing a spike to seeing its cause.

Metrics made from traces

Because spans record durations and outcomes, they can be turned into metrics, such as the rate, error count, and duration of each service and each call between services. Some backends and collectors do this for you. It gives a complete map of requests, errors, and latency between services, with no extra instrumentation.

flowchart LR
    M["Metric chart shows a spike"] -->|"exemplar link"| T["Trace shows the slow step"]
    T -->|"trace ID search"| L["Logs show the exact error"]
    L -->|"trace ID in log line"| T
    T -->|"span durations become"| M2["Service level metrics"]
        
FIG 5 — Moving between metrics, traces, and logs in a few clicks

The figure shows a typical investigation. A person sees a spike on a chart, clicks an example dot to open a trace, sees which span is slow, and follows the trace ID into the logs to read the exact error message. The same trace also feeds summary metrics for services.

i
Use one viewer if you can

When metrics, traces, and logs all appear in one tool, moving between them is easy. Tools such as Grafana can connect to several backends and offer links between them, which saves precious minutes during an incident.

Real-World Use Case

At two in the morning, an alert shows that checkout is slow. The on-call engineer opens the latency chart and clicks an example dot. The trace shows a delay in one call to a pricing service. The pricing service span carries an event saying it retried three times. Searching logs by the trace ID reveals a message about a full connection pool. The engineer restarts the pricing pods, then files a fix to increase the pool. The whole diagnosis takes ten minutes.

12Security and Privacy of Traces

Traces describe exactly how your system works and what your users do. Treat them as sensitive data.

What traces might reveal

Traces can contain web addresses with private values inside, database statements, error messages, customer identifiers, and internal service names. Attackers could use this to learn how your system is built. Careless attributes might also expose private data such as emails, names, or tokens. In many countries, laws about personal data apply to traces just as they apply to databases.

Simple Analogy

A trace is like a detailed diary of everything a customer did in your shop, with times. Handy for improving service, but you would not leave the diary on the counter, and you would not write down their card number in it.

Controls to put in place

Control 1

Redact at the source and the gateway

Never record secrets. Use collector processors to delete or hash risky attributes, such as tokens, cookies, and email addresses, before storage.

Control 2

Limit query text

Record database statements with values replaced by placeholders, so private values never appear.

Control 3

Encrypt the path

Use encrypted connections between applications, collectors, and storage, and require proof of identity where possible.

Control 4

Control who can read

Put the viewer behind single sign-on, and give access by team. Some traces should be restricted to fewer people.

Control 5

Restrict the network

Use NetworkPolicies so that only applications may send to collectors, and only collectors may reach storage.

Control 6

Limit retention

Keep data only as long as it is useful. Deleting old traces reduces both cost and risk.

Danger from outside headers

The public can send requests with their own trace headers. If your system trusts them blindly, an outsider could push their trace IDs into your data, force your system to record every request, or use baggage to inject values. At the edge of your system, decide whether to accept incoming context or start a new trace, and cap the size of any baggage you accept.

RiskWhat could happenProtection
Secrets in attributesTokens or passwords stored and readable by manyRedaction rules, review of new attributes
Open collector portAnyone can send fake or huge amounts of dataNetwork rules, authentication, limits
Public viewerOutsiders read internal detailsSingle sign-on and private access
Trusting outside headersForced sampling, cost blowup, injected dataStart fresh traces at the edge
Long retentionOld private data lingersShort, deliberate keeping times
!
Collectors read the Kubernetes API

Collectors that add pod details need permission to read information about pods. Give them a read-only role for exactly the objects they need, and nothing that can change the cluster.

13Advantages, Disadvantages, and Trade-offs

Tracing is powerful, but it has real costs. Knowing both sides helps you invest where it pays off.

Advantages

  • Shows exactly where time goes in a chain of services.
  • Finds the first service that failed, not just the ones that passed the error on.
  • Reveals real dependencies between services.
  • Speeds up incident diagnosis, especially in large systems.
  • Open standards mean you can change tools without changing code.
  • Works together with metrics and logs for a full picture.

Disadvantages

  • Adds a small delay and resource use to every instrumented program.
  • Data volume and storage cost can grow quickly.
  • Missing context breaks traces, and finding the gap takes effort.
  • Sampling means some requests are never seen.
  • Traces can expose private data if handled carelessly.
  • Teams need training to read traces well.

The trade-offs in plain words

ChoiceBenefit of going furtherCost of going further
Keep more tracesFewer rare problems missedMore storage and more money
Add more spansFiner detail inside servicesBigger traces, harder to read, slower programs
Add more attributesBetter searching and filteringMore storage, more privacy risk
Tail samplingKeeps the most useful tracesMore memory, more moving parts
Keep data longerCompare with earlier weeksHigher cost and more risk
Simple Analogy

Think of installing cameras in a shop. More cameras show more, but they cost money, produce mountains of video, and raise privacy questions. A sensible owner covers the entrance and the till first, and adds more only where real problems appear.

When tracing is worth it

Tracing pays off most when requests cross many services, when teams are separate and cannot see each other’s code, and when problems are about slowness or partial failure rather than a single crash. If you have one or two services, good logs and metrics may be enough for now. As the number of services grows, the value of tracing grows faster than its cost.

i
Begin with the critical path

You do not need to trace everything on day one. Start with the most important customer journey, such as sign-in or checkout, and trace that end to end. Expand from there.

14Design Patterns and Anti-patterns

Patterns are arrangements that many teams have found to work. Anti-patterns are habits that seem sensible but cause trouble.

Helpful patterns

Pattern 1

Agent and gateway

Applications send to a nearby agent, agents send to a central gateway, and the gateway decides what to keep and where to send it.

Pattern 2

Automatic first, manual where it matters

Use automatic instrumentation for coverage, and add hand-made spans around key business steps.

Pattern 3

Keep all errors, sample the rest

Use tail sampling to keep every failed and slow trace, and a small share of ordinary ones.

Pattern 4

Trace ID in every log

Write the trace ID into log lines so one search links the trace to all its logs.

Pattern 5

Standard names and conventions

Follow the shared attribute names, and agree on service names, so tools and people understand each other.

Pattern 6

Fresh trace at the edge

Start a new trace at the public entrance instead of trusting headers from outside.

Simple Analogy

A well-run airport gives every bag a barcode at check-in, uses the same barcode format at every stage, and keeps a full record for any bag that goes missing. These habits are the same as agreeing on standards, adding identifiers early, and keeping evidence for problems.

Anti-patterns to avoid

ANTI-PATTERN-01 Avoid
Problem

Tracing every request at full detail, forever, with no sampling and no retention limit.

Why It’s Harmful

Storage and network costs grow without limit, searches slow down, and the important traces are buried among millions of ordinary ones.

Correct Approach

Choose a sampling plan, keep errors and slow traces, and set clear retention periods.

ANTI-PATTERN-02 Avoid
Problem

Creating a span for every tiny function call inside a program.

Why It’s Harmful

Traces become huge and unreadable, the program slows down, and the real story is lost in noise.

Correct Approach

Create spans for meaningful units of work: calls to other services, database queries, and key business steps.

ANTI-PATTERN-03 Avoid
Problem

Putting values such as user emails, full web addresses with tokens, or order contents into span attributes.

Why It’s Harmful

Private data is stored and shown widely, which breaks privacy rules and creates a security risk.

Correct Approach

Record safe identifiers or categories instead, and use redaction rules in the collector as a second line of defence.

ANTI-PATTERN-04 Avoid
Problem

Sending spans directly from every application to storage, with no collector in between.

Why It’s Harmful

Every application must hold storage details, a slow backend can affect applications, and there is nowhere to apply shared rules.

Correct Approach

Send to a collector layer, and change the shared rules in one place.

ANTI-PATTERN-05 Avoid
Problem

Treating tracing as a one-time project, with nobody owning the data quality afterwards.

Why It’s Harmful

New services join without tracing, context breaks appear, names drift, and trust in the tool falls until people stop using it.

Correct Approach

Give a team ownership, include tracing in the checklist for new services, and review trace quality regularly.

15Best Practices and Common Mistakes

A short list of habits that keep tracing useful, and the mistakes that most often spoil it.

Best practices

1

Use OpenTelemetry and the standard header

Standard tools and formats keep you free to change backends and let services from different teams work together.

2

Start with one important journey

Trace the customer path that matters most, prove its value, then widen coverage.

3

Name services and spans clearly

Use stable service names and short, meaningful span names that describe the work, not the customer or the ID.

4

Put a collector layer in front of storage

Let agents and gateways enrich, batch, sample, and redact before anything is stored.

5

Sample wisely

Keep errors and slow traces, sample the rest, and record the sampling rate.

6

Link the three signals

Add trace IDs to logs and use exemplars on metrics so you can jump between them.

7

Protect the data

Redact, encrypt, restrict access, and delete on a schedule.

8

Make it part of the launch checklist

Every new service should ship with tracing, standard names, and a link to its dashboards.

Simple Analogy

Keeping tracing healthy is like keeping a library catalogue in order. If every new book is catalogued the same way on the day it arrives, anyone can find anything. If books are added with no labels, the catalogue slowly becomes useless.

Common mistakes

MistakeWhat goes wrongBetter habit
Forgetting to pass context through queuesTraces end at the queue and restart on the other sideStore context in the message and read it back
Different header formats in different servicesTraces split in the middleChoose one format and set every tool to it
High-variety values in span namesThousands of unique names make searching uselessKeep names generic and put details in attributes
No timeouts on the exporterA slow collector slows the applicationSet short timeouts and limited queues
Sampling only at the headRare failures are usually missedAdd tail rules for errors and slow traces
Ignoring the gap between client and server spansNetwork and queue delays stay hiddenCompare both spans to find the missing time
Never checking that traces are completeBroken traces are trusted as realWatch for orphans and short traces regularly
!
Do not judge from one trace

One trace is a single example. A slow trace may be unusual, and a fast one may be lucky. When you find something interesting, look at several similar traces and at metrics before deciding what is normal.

A gentle start plan

In the first week, install the collector agents and the backend, and turn on automatic instrumentation for two or three services on your main customer journey. In the second week, fix any broken context, add trace IDs to logs, and build a first dashboard link. In the third week, add a few manual spans, choose a sampling plan, and add redaction rules. Then review with the team and grow from there.

16Monitoring the Tracing Pipeline and Troubleshooting

A tracing system also needs watching. If it fails quietly, you will only find out when you need it most.

Numbers to watch

Collectors and backends report their own metrics. A few tell you most of what you need. Watch how many spans are received and how many are sent onward. Watch how many are dropped or refused, and why. Watch the size of the internal queues, the memory use of collectors, and how long storage takes to accept data. Watch also how much the query service is used and how slow it is.

Received
spans arriving at each collector
Dropped
spans lost, refused, or discarded on purpose
Queue
how full the buffers are
Memory
use by collectors, especially with tail sampling
Simple Analogy

A security camera system needs someone to check that the cameras are still recording. A camera that failed last Tuesday is worthless when the incident happens on Friday. The same goes for your tracing pipeline.

Alerts worth having

Warn when the number of spans received drops suddenly, which often means a service lost its instrumentation or a collector is down. Warn when drops or refusals rise, when queues stay nearly full, and when collector memory approaches its limit. Warn also when the storage backend is failing to write. These alerts should go through your normal alert system, not through the tracing system itself.

Troubleshooting the usual suspects

SymptomLikely causeWhere to look
No traces from one serviceInstrumentation not attached, wrong collector address, or a blocking network ruleService settings, network rules, collector received counts
Traces split in twoA hop that does not pass context, such as a queue or a gatewayThe place where the trace ends and the next one begins
Child span starts before its parentClocks out of sync between nodesTime synchronisation on the nodes
Traces missing errorsOnly head sampling is used, or tail rules do not matchSampling settings and gateway routing
Collector restarts with out-of-memoryTail sampling holding too many spans, or too much trafficMemory limits, wait times, and scaling of the gateway
Application slower after enabling tracingToo many spans, or exporter blockingSpan counts, queue settings, and timeouts
Traces slow to appearLong batching delays or overloaded backendBatch settings and backend write times
i
Follow the spans hop by hop

When spans go missing, check each stage in order: is the program creating them, is the agent receiving them, is the gateway forwarding them, and is the backend storing them? The collector counters at each stage will show where the numbers stop matching.

Scaling the pipeline

As traffic grows, add more agent and gateway replicas and more storage capacity. Keep the routing by trace ID so that tail sampling still works. Lower the cost by sampling more, shortening retention, or removing spans and attributes that nobody uses. Review the top contributors to volume every few months, since one busy service can account for most of the data.

17Real-World Examples

Three short stories show the ideas at work. The details are typical rather than taken from any one company.

Example 1: The mysterious slow checkout

Real-World Use Case

Customers complain that checkout is sometimes very slow. Metrics show that average time is fine, but the slowest one percent is terrible. A team opens a few slow traces and sees the same pattern: a call to the tax service takes six seconds, and inside the tax service, a span called “load rules” is the slow part. The tax service was loading a big rules file from a remote store on every request for a certain region. They add a cache, the slow requests vanish, and the trace comparison after the change proves it.

Example 2: A hidden dependency

Real-World Use Case

A team plans to retire an old reporting service. The wall diagram shows nobody uses it. The service map built from traces shows that the mobile app’s login flow quietly calls it once per day to fetch a banner message. Removing it would have broken logins for some users. Because traces show the real calls, the team plans a safe replacement before shutting it down.

Example 3: Retries that hide a failure

Real-World Use Case

Error metrics look calm, yet customers report occasional delays. A tail sampling rule keeps traces with more than one attempt on a call. Those traces show a notification service failing about one call in five, and the caller retrying up to three times before success. Users never see errors, but every retry adds a second. The team fixes the notification service, and the delay complaints stop.

Simple Analogy

These stories are like a detective using a security tape instead of guessing. Metrics say a crime happened somewhere in town. The trace is the tape of one visit to the shop, showing exactly who went where and how long they waited.

What the stories share

In each story, the answer came from looking at real requests instead of averages and assumptions. Teams started with a real complaint, opened a small number of representative traces, found a single surprising step, and confirmed the fix by looking at traces again afterwards.

“Metrics tell you something is wrong. A trace shows you where.”

18Frequently Asked Questions

Short answers to questions that beginners often ask.

Q1Do I need tracing if I already have logs and metrics?

If you have only a few services, maybe not yet. As the number of services grows, tracing becomes the fastest way to see the path and timing of a single request across them. It complements, rather than replaces, logs and metrics.

Q2What is the difference between a trace and a span?

A trace is the whole journey of one request. A span is one step within that journey. A trace is made of many spans arranged in a tree.

Q3What is OpenTelemetry, and do I have to use it?

OpenTelemetry is an open standard and set of tools for creating and collecting traces, metrics, and logs. You do not have to use it, but it is the widely supported choice and keeps you free from being tied to one vendor.

Q4Will tracing slow down my applications?

A little. Creating spans and sending them takes some processor time and memory. With sensible sampling, batching, and limits, the cost is usually small, but you should measure it on your own workloads.

Q5Why are my traces broken into pieces?

Almost always because context was not passed at some hop. Common causes are message queues, background threads, gateways that remove headers, services with no tracing, and mixed header formats.

Q6What is the difference between head and tail sampling?

Head sampling decides at the start of the request, cheaply, before it is known how it will turn out. Tail sampling decides after the whole trace is collected, so it can keep errors and slow traces, but it needs more memory and careful routing.

Q7Should the collector run as a sidecar or as a DaemonSet?

A DaemonSet, one per node, is simpler and uses fewer resources for most teams. A sidecar gives stronger separation per application and finer control, but costs more resources across many pods. Many teams start with a DaemonSet.

Q8Can a service mesh give me tracing without changing my code?

Partly. A mesh can create spans for network calls, giving a rough map. But it cannot see inside your programs, and your programs must still copy the trace headers from incoming to outgoing calls for the traces to connect.

Q9How long should I keep traces?

Days to a couple of weeks is common, since most investigations happen soon after an event. Keep error and slow traces a little longer, and copy important ones into incident reports.

Q10Is it safe to store traces from real customers?

It can be, with care. Avoid personal data in attributes, redact risky values in the collector, encrypt connections, control access, and set short retention. Check the rules that apply in your country and industry.

Q11What is an exemplar?

An exemplar is a link attached to a metric value that points to an example trace. It lets you click from a spike on a chart straight to a real request that contributed to it.

Q12Where should I start?

Pick one important customer journey, turn on automatic instrumentation for the services on it, send data through a collector to a simple backend, and open a few traces with your team. Fix broken context, add trace IDs to logs, and grow from there.

19Summary and Key Takeaways

A last look at the whole picture, in plain words.

Modern applications are built from many small services, and a single customer click may pass through a dozen of them. When something is slow or broken, metrics can tell you that there is a problem, and logs can tell you what a single program said, but only a trace shows the whole path of one request, step by step, with times.

A trace is a tree of spans. Each span is one piece of work, with a start, a duration, and helpful details. The trace ID and the parent link tie them together, and context propagation carries these identifiers from one program to the next. Lose the context, and the story breaks. Use a shared standard, and everything connects.

In Kubernetes, programs are instrumented with OpenTelemetry, automatically or by hand, and send spans to nearby agent collectors. A central gateway enriches, samples, and cleans the data, and forwards it to a backend where people can search and read it. Sampling keeps costs under control while preserving errors and slow requests. Linking traces to logs and metrics turns a spike on a chart into a cause in a few clicks. Finally, treat the data with care, and watch the pipeline itself, so it is ready when you need it.

Key Takeaways

  • A trace is one request’s whole journey — it is a tree of spans, each with a name, times, and details, joined by a shared trace ID and parent links.
  • Context propagation is the heart of tracing — the trace ID must travel with every call, through queues, threads, and gateways, using one standard header format.
  • OpenTelemetry gives you freedom — standard instrumentation and a Collector let you change backends without changing applications, and the operator can automate setup in Kubernetes.
  • Use agents and a gateway — agents receive and enrich near the applications, and the gateway samples, redacts, and forwards to storage.
  • Sample to keep what matters — keep every error and slow trace, keep a small share of the rest, and never use trace counts as request counts.
  • Connect the three signals — put trace IDs in logs and exemplars on metrics, so you can move from a spike to a trace to an exact error quickly.
  • Protect and monitor the pipeline — redact private data, encrypt and restrict access, keep retention short, and alert when spans stop flowing.