nobeh
·5 min read

Distributed Tracing in a monolith is different than a microservice

More code instrumentation with tracing doesn't always mean more insight, especially in a monolithic system — a look at why tracing behaves differently in monoliths vs. microservices.


Distributed Tracing1 has been an industry practice for the past decade. More recently, in the past few years, OpenTelemetry2 has made its way to be the standard across different technology stacks.

A typical developer question is: how to instrument the code for tracing. This is easily doable either in a programmatic way using OpenTelemetry Tracer API3 or more declaratively @WithSpan. But …

This is tempting. As a developer, we commonly find ourselves in a situation where we need to collect more data on performance (i.e. latency) or scale (i.e. count) around the context. This is easy now; i.e. either via an annotation on a method or a small block of code adding a new span4.

There’s a hidden lesson when comparing tracing in monoliths vs. microservices:

It’s important to recognize that increasing the code instrumentation with tracing may not always lead to more insights esp. in a monolithic system.

This can be largely explained by the differences between a monolithic application and a microservice architecture when it comes to distributed tracing. A nuanced detail that impacts the value of distributed tracing.

A microservice is typically expected to follow the principles of a bounded context or limited responsibility. This implies that a microservice generally exposes a limited number of service interface endpoints, such as an HTTP API. Consequently, in various distributed tracing implementations, developers often utilize the HTTP method name alongside the service component name as the default naming convention; for instance, a span name may appear as GET with service.name = billing-service.

Though, a monolithic application could easily expose large number of HTTP endpoints, with each HTTP request traversing multiple business components in the same application. These components exhibit logical dependencies on one another. A component is composed of various logical components, including business logic, data management, and other integrations. At the same time, OpenTelemetry instrumentation offers a wide range of integrations tailored for different frameworks.

This is only one of the primary reasons why a monolithic application trace can easily consist of several hundred (if not thousands) of spans, whereas a microservice typically does not exceed several tens of spans.

While adding tracing instrumentation improves the detail and accuracy of our tracing data, it’s good to keep in mind that the value we get depends on how tracing is applied. So, it’s crucial to think through when and how tracing instrumentation is necessary.

What follows are few guidelines to help you make informed decisions about tracing instrumentation esp. in a monolithic application.

  1. Evaluate the nearest boundary to your code for tracing. This may include a business-level API, or a framework-level API, such as executing a database query or utilizing an HTTP client. If the nearest boundaries are equipped with tracing, they can provide valuable insights. First, analyze the current traced boundaries to evaluate if you need more instrumentation.
  2. Deciding the intent with tracing instrumentation is essential. Monolith tracing instrumentation proves most beneficial in few primary scenarios:
    • Analyzing and breaking down a significant unaccounted latency block (a large span)
    • Explaining latency gaps between two consequent spans
    • Identifying code patterns such as recurring sequences, loops, and the n+1 problem, facilitating the evolution from sequential processing to concurrent execution or transitioning from repetitive tasks to bulk processing.
  3. Utilize local development for initial experimentation. Instrument your code and explore the data using local development. This helps better assessment whether to roll out the instrumentation to production or not.
  4. Technical Debt is always around the corner. OpenTelemetry like any technology is not written in stone. For example, in Java ecosystem, there was Zipkin (with Brave 3.x) and then OpenTracing with Brave 4.x and eventually with Brave 5.x. Then, OpenTelemetry arrived. When adding your spans, consider to make it easy for the future engineer doing the refactoring. Prefer @WithSpan when possible. When using Tracer API, consider using wrapper methods to increase readability and ease of change.
  5. When you have a hammer, everything looks like a nail (Law of Instrument5). Tracing is great and useful but remember it’s one of the tools in the toolbox of performance engineering. Familiarize yourself with others and use them. For example, tracing is additionally interesting because it reveals code flow esp. in a large code bases. It helps to understand how logic flows from one point of code to another. So, another good reason to add tracing instrumentation. For example, you might use profiling next to tracing. Instead of using a trace to understand the code flow, you could use the profiling tool to search for the code area and follow its flow.
  6. Remember that tracing data provide a single request view. Derived or aggregated metrics via tracing is a recent addition. However, they’re not straightforward due to limitations of storage or real-time processing. If you need aggregated data based on tracing, you need to use other types of instrumentation.

Performance Engineering requires a toolbox and tracing is one tool in the box.

Originally published on Medium.

Notes

  1. Distributed Tracing

  2. OpenTelemetry

  3. OpenTelemetry Tracer API

  4. Span

  5. Law of Instrument

← All posts

Citation

Behrooz Nobakht (2025). "Distributed Tracing in a monolith is different than a microservice." Available at: https://nobeh.com/blog/2025/02/distributed-tracing-in-a-monolith-is-different-than-a-microservice/
or
@misc{nobakht2025distributed,
  author = {Nobakht, Behrooz},
  title = {Distributed Tracing in a monolith is different than a microservice},
  howpublished = {\url{https://nobeh.com/blog/2025/02/distributed-tracing-in-a-monolith-is-different-than-a-microservice/}},
  year = {2025},
  note = {Accessed: 2026-09-09}
}

tracingopentelemetryobservabilitymicroservicesperformance