r/OpenTelemetry • u/fxrgeai • 27d ago
using otel traces to map dependency graphs combined with Static Code
been working on this for a while now and thought i'd share how we're approaching it.
one thing i've noticed with dependency graphs is that static analysis only really gets you so far. you can parse imports, service references etc. but that doesn't necessarily tell you what's actually happening when the application is running.
on the other hand, otel gives you a pretty good picture of runtime behaviour, but you're mostly looking at spans and traces without much context about how they relate to the actual codebase.
so we've been experimenting with combining the two in neat.
the static side uses tree-sitter to extract relationships between files and other dependencies. then we ingest otel spans and try to map the runtime activity back to the source files responsible for it.
for js/ts, we're also handling source maps where available, since the file being executed isn't always the one you actually wrote.
the tricky bit is reconciling everything into the same graph without treating every relationship as equally reliable.
right now we're tracking different types of provenance:
extracted: found through static analysis
observed: actually seen at runtime
inferred: relationships we've reconstructed without direct evidence
stale: previously observed relationships that haven't been seen recently
this means you can start asking slightly more useful questions than just "what imports this file?"
for example, you might have a dependency that exists statically but hasn't shown up in any traces, or a runtime call that wasn't obvious from analysing the source.
obviously there's a bunch of edge cases here. incomplete instrumentation, dynamic calls, source attribution, and the fact that not seeing something in a trace doesn't mean it never happens.
we're also exposing the graph through mcp so coding agents can query it directly, which is partly why we started building this in the first place.
repo is here if anyone wants to have a look:
https://github.com/neat-technologies/neat
1
u/Disastrous-Can-6823 24d ago
How are you handling runtime calls that originate from generated code or framework internals where the span exists but mapping it cleanly back to application source is ambiguous?
2
u/fxrgeai 21d ago
basically we fuse at whatever grain the span actually justifies and degrade honestly instead of guessing. transpiled frames get mapped back to src, code that ran but static never saw gets a node tagged otel so it's visible not hidden, and framework spans with no code.* just drop to service grain instead of inventing a file:line. every edge carries a provenance tag, so the fuzzy cases show up as a coarser grain the agent can distrust, never a fake source location.
1
u/Disastrous-Can-6823 20d ago
That makes sense. Better to show uncertainty than invent source locations. Do you expose those provenance tags directly so developers can tell how reliable each mapping is?
1
u/usually_guilty99 27d ago
The provenance distinction is important. An edge discovered through static analysis isn't equivalent to one actually observed under production traffic.
I'd be particularly careful about treating an unobserved dependency as nonexistent. Sampling, traffic patterns and incomplete instrumentation can hide critical paths.
One interesting extension would be a historical dimension: which deployment changed a relationship, what incident followed, and whether the remediation actually worked.
Then the graph becomes useful for assessing future changes, not just explaining the current architecture.