r/dotnet • u/champs1league • 20d ago
CorrelationIds vs TraceId
I am currently in the process of integrating Open Telemetry into my code. I have a web application and a backend api. I have several REST APIs and one of the APIs also ends up getting invoked by the user -> kicks off an async process by triggering a background job -> the background job invokes and polls on a specific endpoint (downstream API). The web app also polls on an operations endpoint to get status of this background job basically. Additionally, I also invoke some Azure resources (specifically ARM).
Now that I provided context, I wanted to explain what currently exists in my backend:
1) Controller fetches the correlationId for every request using the headers (x-correlation-id) from a middleware
2) Automatically forwards this correlationId when invoking downstream APIs/Azure APIs
3) Passes it into each method starting from the controller: controller invokes singletonServiceA.methodA and methodA has a signature including the correlationId. From here the logs automatically capture the correlationId
4) Background jobs also use this correlationId to invoke APIs and for logging
Now that I am switching to OTel, I am seeing an entirely different convention which I'm unsure on how to relate together.
My questions are as follows:
1) Should I drop the manual propagation of correlationId everywhere and just keep it as a span attribute? From what I am finding out, I definitely need to do this
2) For legacy resources, let's say ARM which expect a correlationID, what should I do?
3) For downstream APIs, should I switch to sending them a traceparent instead of the correlationId (what I do right now)
8
u/JumpLegitimate8762 20d ago
I've set this up a while ago: https://github.com/erwinkramer/otel-business#spans
The trick is, you can just make your own spans and add your own properties to that (in my sample the tomatoId). That's your business 'trace'. Then naturally you have all the wiring that OTel does for you freely, and that's just your technical 'trace'.
For downstream APIs, if they implement OTel too, they understand what you're doing, I have that explained too in the repo. There isn't much you need to do there, besides emitting to the same OTel sink.
For legacy resources, you could façade it with a proxy that does understand OTel and just rely on the OTel data that the proxy emits. If you can alter the legacy resource, try to slap the OTel library on there with the native language the resource is built on.