Learnitweb

Span parent–child relationships

1. Introduction

Before talking about parent and child spans, we must first clearly understand what a span is in OpenTelemetry.

A span represents a single unit of work in your system. That unit of work could be:

  • Handling one HTTP request in a controller
  • Calling a database
  • Calling another microservice
  • Publishing or consuming a Kafka message
  • Doing a computation inside your code

A trace is simply a collection of spans that all belong to the same request or transaction.

So, you should always think like this: A trace is a tree of spans, not a flat list. And that brings us naturally to parent–child relationships.

2. Why Do We Even Need Parent–Child Relationships?

Let us take a very realistic example from your kind of systems:

Imagine a request comes to your application:

/placeholder

Inside your backend, the following things happen:

  1. Controller receives the request
  2. Service validates the order
  3. Service calls Payment Service
  4. Service calls Inventory Service
  5. Service writes to database
  6. Service publishes Kafka event

Now, conceptually, all of this is one logical operation: Place Order.

But technically, it is made of many smaller operations.

So OpenTelemetry models this as:

  • One root span = “Handle /placeOrder request”
  • Many child spans = “Validate order”, “Call payment service”, “DB insert”, “Publish Kafka message”, etc.

This gives us a hierarchical structure, not a flat log.

3. The Tree Structure of a Trace

A trace always looks like a tree. Let us draw a textual diagram:

Trace: PlaceOrder (TraceId = abc123)

└── Span A: HTTP POST /placeOrder   (Root Span)
    ├── Span B: Validate Order
    ├── Span C: Call Payment Service
    │   └── Span D: HTTP POST /pay
    ├── Span E: Call Inventory Service
    │   └── Span F: HTTP POST /reserve
    ├── Span G: Insert Order into DB
    └── Span H: Publish Kafka Event

Important things to notice:

  • Span A is the root span (it has no parent).
  • Every other span has exactly one parent.
  • A parent span can have many children.
  • This forms a tree, not a graph and not a cycle.

4. What Exactly Is a Parent Span?

A parent span is simply:

The span that represents the operation that caused another operation to happen.

For example:

  • The HTTP request handler span causes the DB call → so it is the parent of the DB span.
  • The service method span causes the REST call to another service → so it is the parent of that HTTP client span.

In simple words:

If operation B happened because of operation A, then span A is the parent of span B.

5. What Exactly Is a Child Span?

A child span is:

A span that represents a sub-operation inside a bigger operation.

For example:

  • “Insert into DB” is a child of “Process Order”.
  • “Call Payment Service” is a child of “Process Order”.

The child span always:

  • Shares the same Trace ID as the parent.
  • Has its Parent Span ID set to the parent’s Span ID.

6. The Two IDs That Make This Work

Every span has:

  • Trace ID → identifies the whole trace (the whole request journey)
  • Span ID → identifies this particular span
  • Parent Span ID → identifies who its parent is

So internally it looks like this:

Span A:
  TraceId = abc123
  SpanId  = 111
  Parent  = null

Span B:
  TraceId = abc123
  SpanId  = 222
  Parent  = 111

Span C:
  TraceId = abc123
  SpanId  = 333
  Parent  = 111

Span D:
  TraceId = abc123
  SpanId  = 444
  Parent  = 333

This is how tools like Tempo, Jaeger, Zipkin, Dynatrace, etc. reconstruct the tree view.

7. Nested Spans: Depth Is Unlimited

Spans can be nested to any depth.

Example:

HTTP Request
└── Service Method
    └── Business Rule Check
        └── DB Query
            └── JDBC Driver Call

This means:

A span can be both a child and a parent at the same time.