Observability Is a Prerequisite for Splitting a Monolith, Not a Follow-Up Task
Software EngineeringAugust 13, 2026 · 6 min read

Observability Is a Prerequisite for Splitting a Monolith, Not a Follow-Up Task

FE
Fastnexa EngineeringSoftware Development Team

Almost every migration schedules tracing after the first services ship. That ordering removes the stack trace before anything replaces it, and it hides the data you needed to choose the boundaries.

In a monolith, a stack trace is a distributed trace. One exception object contains the full causal chain from the HTTP handler down to the failing query, and it arrives in your error tracker for free. The moment you extract the first service, that artefact is gone and nothing has replaced it. What you get instead is a 500 in service A caused by a timeout in service B caused by connection pool exhaustion in service C, presented as three unrelated log lines in three different places with three different clocks.

Nearly every migration plan puts observability after the first extraction. The reasoning is that you cannot instrument services that do not exist yet, which sounds obvious and is wrong twice over. It is wrong because tracing inside a monolith is both possible and useful, and it is wrong because the trace data is the input to the boundary decision, not a consequence of it.

The instrumentation you need does not require services

Distributed tracing works within a single process. You instrument the framework at the entry point, the HTTP and database clients, and the internal module boundaries you expect to become service boundaries, and you get spans showing exactly which modules participate in each request, in what order, and how much wall clock time each one contributes.

That gives you three things before a single service is extracted:

  • A call graph derived from actual traffic rather than from reading imports. Static analysis shows what could call what. Traces show what does, and at what frequency.
  • A latency budget per module, so you know which candidate boundaries sit on the hot path and would convert an in-process call into a network hop on your slowest endpoints.
  • A baseline. When p99 moves after the extraction, you can say whether it moved, by how much, and where. Without the baseline the honest answer is that nobody knows, and the argument gets settled by whoever is loudest.

The last one is the one teams miss and later regret. Post-split performance complaints are unfalsifiable without pre-split numbers, and they surface about six weeks in, when the rollback option has already closed.

Correlation IDs are the part you cannot retrofit cheaply

Adding trace context propagation to a codebase is intrusive in a specific, boring way: it touches every client call, every background job enqueue, every message publish, and every thread or async boundary. In a monolith you do this once, in one repository, with one deployment, and you can verify it end to end because everything is in front of you.

After the split, the same work has to happen in every service, in every repository, coordinated across teams, and half of them will get the propagation wrong in a way that only shows up as traces that mysteriously terminate at a service boundary. Header propagation through message queues is the usual casualty, because it is the one path where the framework does not do it for you.

The other retrofit that gets underestimated is structured logging. Free-text logs are readable when one process produced them in order. Across services they need to be queryable by request ID, tenant, and service name, which means changing every log statement in the codebase. Doing that while the codebase is still one codebase is a fraction of the work.

Sequencing, compared

SignalAdd before the splitAdd after the split
Trace context propagationOne repo, one deploy, verifiable end to endEvery repo, coordinated, silently broken at queues
Structured logs with request IDMechanical edit across one codebaseSame edit times N, in N release cycles
Latency baselineAvailable for comparisonGone, arguments become opinion
Real call graphInforms where to cutConfirms you cut badly
Error attributionStack trace still worksManual correlation across services
Cost of getting it wrongA sprint of instrumentationAn incident with no root cause

The pattern in that table is that everything in the left column is cheaper and produces information you can act on. The guide on why observability belongs before the split rather than after goes further into what to instrument and in what order.

Why nobody sequences it this way

Because instrumentation has no demo. A migration plan that opens with "two sprints of tracing and structured logging in the existing system" is asking a sponsor to fund work with no visible output, while the alternative opens with an extracted service that can be shown in a review. The first extraction is usually something low risk and stateless, it goes well, and it creates the impression that the hard part is behind you. It is not. The hard part is the third extraction, the one that touches shared state, and by then you are debugging distributed failures with monolith-era tools.

There is also a genuine argument on the other side, which is that instrumentation added speculatively can miss what turns out to matter. That argument is fair for detailed business metrics and less fair for trace propagation, which is generic. Propagate context and log a request ID first, and defer the specific dashboards until you know which numbers you care about.

A workable order of operations

  1. Instrument the entry points and the database layer in the monolith. Get end to end traces for the top endpoints by traffic and by error rate.
  2. Add trace context propagation to every outbound call, background job, and message publish. Verify that a trace survives a queue round trip, because that is where it usually does not.
  3. Convert logging to structured output carrying the request ID, and confirm you can reconstruct one request across every log line it produced.
  4. Run for a few weeks. Record baseline latency distributions per endpoint and per module, not averages.
  5. Read the call graph the traces produced. Compare it to the proposed service map and change whichever one is wrong.
  6. Only then extract, and use the first extraction to confirm traces still stitch across the network boundary before doing a second.

Step five is where this pays for itself twice, because the same trace data that makes the new system debuggable also tells you where the seams actually are. Teams that follow this order usually find that at least one proposed boundary sits directly on a hot path, and the sequence described in the guide on staged approaches to migrating out of a monolith changes accordingly.

What to do next

Pick your highest-traffic endpoint and try to answer, from data you already collect, how much of its p99 is spent in each internal module. If you cannot answer that today, you cannot make an informed decomposition decision, and the first two sprints of the migration are already defined for you. That work also has standalone value: it improves debugging in the system you have now, which is the argument that gets it funded.

When the traces are in place and the call graph disagrees with the plan, that is the point at which an outside read is worth something, and our microservices architecture practice starts from that data rather than from a target diagram.

observabilitydistributed tracingmonolith migrationmicroservices
Share
FE
Written by

Fastnexa Engineering

Software Development Team at Fastnexa. We write from real client work, and we are happy to talk through yours.

Ready to ship this?

Bring this problem to a free 30-minute call with the team that wrote the post.

Book a demo

More from the blog

View all

Related services

Want help putting this into practice? Here is how we deliver it.

Work with us

Reading about it is good. Shipping it is better.

Every article here comes from real client work. If one of these problems looks like yours, bring it to a free 30-minute call with the team that wrote the post.

Fastnexa Logo

© 2026 fastnexa. All rights reserved.