You have narrowed the incident to one service and one endpoint. The trace says the time went "inside the handler." Then what? Continuous profiling answers the question traces cannot: which line.
The fourth signal
For years, profiling meant reproducing a problem locally and running a profiler by hand. Continuous profiling flips that: a low-overhead sampler runs in production all the time, so the flame graph for any moment is already there when you need it.
What it adds to the stack
- Metrics tell you something is slow.
- Traces tell you which service and span.
- Profiles tell you which function and line, down to the CPU cycle.
Correlate it with the rest
The magic is joining a profile to the trace that triggered it. A slow span becomes a flame graph of exactly that request's execution:
traces
| where duration > 3s and service == "render"
| join profiles on trace_id
| top_functions by self_cpu
| limit 15
The overhead question
The reason this is practical now is cost. Modern sampling profilers add a couple of percent of CPU — cheap enough to leave on everywhere. That is the whole unlock: profiling stopped being a special expedition and became just another always-on signal, ready before the incident starts.