You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Oct 3, 2023. It is now read-only.
Is your feature request related to a problem? Please describe.
It would be convenient to have more control over child spans instead of just having root spans for incoming requests and child spans for outgoing requests. For example, if I have a client library that makes several requests to other services for authentication/authorization, I'd like to group them together in a single span.
#105 mentions the inability to create child spans from child spans, but this is a request to specifically store this information in a CLS namespace in a way that is accessible from anywhere (via tracer), as well as a request to adapt the design to have arbitrary spans not specific to receiving/sending requests.
Describe the solution you'd like
I'd like to have something like a withSpan(() => { ... }) function where the span is accessible via CLS (instead of coming as an argument in the callback), perhaps with tracer.currentSpan(). Maybe this could just wrap the function in a try/finally block to ensure that the span is closed. It would have to work with async and synchronous functions.
If there were a way to make use of decorators, that'd be even better, so marking a function with @Span with some configuration would create child spans (or follows-from spans once OpenTracing support is added) that start when the function starts and end when the function ends (or throws, etc.). I don't know enough about decorators to say how this would work / if it's possible.
Describe alternatives you've considered
I've considered writing my own solution using CLS, but this is a feature that I think would benefit others and I believe would belong in OpenCensus-node.
I came up with a (half-working) solution that maintained which span was active by maintaining a stack of spans on the CLS namespace. When a span was created, it was added to the stack, and it was removed when the span ended. I was not sure how well this would work for spans that start in one continuation and end in another, or how event-based spans would work.
I also considered just creating a new namespace context when a span is created (which would essentially be like maintaining a stack, since I think that maintains a stack internally). This would be cleaner than maintaining the stack myself, but has similar potential problems to above.
One other problem I ran into... I had a withSpan(...) function working that was generic and returned whatever type the callback returned, but this had the unfortunate effect where I could not figure out how to return from a function like:
functionsomeFunction(){// START GROUP OF TASKSconsole.log("(some common group...");console.log("...of function...");if(somecondition){returnfalse;}console.log("...calls)");a=resultOfTheseTasks();// END GROUP OF TASKSconsole.log(`Some task with ${a}`);returntrue;}
When I move the group of tasks into something like const a = withSpan(...) callback, returning from the callback no longer has the effect I wanted (it's designed to return what I should store in a, so I can't return from the calling function with false), making the code more complex. I had to return a tuple, where the first argument was "isDone", which I'd use to see if I should return from the calling function or not. This made the code pretty sloppy, and I wasn't sure how to fix it. I guess I could have used closures, but wanted to be able to use const.
Additional context
In my attempted solution, I ran into a problem where (what OpenCensus calls) root spans would not be modifiable, since all that was available was the SpanContext (using OpenTracing) which is immutable. I resorted to creating child spans in middleware, so the root span was never accessible, and there was always a Span available to modify with tags and logs.
The text was updated successfully, but these errors were encountered:
Is your feature request related to a problem? Please describe.
It would be convenient to have more control over child spans instead of just having root spans for incoming requests and child spans for outgoing requests. For example, if I have a client library that makes several requests to other services for authentication/authorization, I'd like to group them together in a single span.
#105 mentions the inability to create child spans from child spans, but this is a request to specifically store this information in a CLS namespace in a way that is accessible from anywhere (via
tracer
), as well as a request to adapt the design to have arbitrary spans not specific to receiving/sending requests.Describe the solution you'd like
I'd like to have something like a
withSpan(() => { ... })
function where the span is accessible via CLS (instead of coming as an argument in the callback), perhaps withtracer.currentSpan()
. Maybe this could just wrap the function in a try/finally block to ensure that the span is closed. It would have to work with async and synchronous functions.If there were a way to make use of decorators, that'd be even better, so marking a function with
@Span
with some configuration would create child spans (or follows-from spans once OpenTracing support is added) that start when the function starts and end when the function ends (or throws, etc.). I don't know enough about decorators to say how this would work / if it's possible.Describe alternatives you've considered
I've considered writing my own solution using CLS, but this is a feature that I think would benefit others and I believe would belong in OpenCensus-node.
I came up with a (half-working) solution that maintained which span was active by maintaining a stack of spans on the CLS namespace. When a span was created, it was added to the stack, and it was removed when the span ended. I was not sure how well this would work for spans that start in one continuation and end in another, or how event-based spans would work.
I also considered just creating a new namespace context when a span is created (which would essentially be like maintaining a stack, since I think that maintains a stack internally). This would be cleaner than maintaining the stack myself, but has similar potential problems to above.
One other problem I ran into... I had a
withSpan(...)
function working that was generic and returned whatever type the callback returned, but this had the unfortunate effect where I could not figure out how to return from a function like:When I move the group of tasks into something like
const a = withSpan(...)
callback,return
ing from the callback no longer has the effect I wanted (it's designed to return what I should store ina
, so I can't return from the calling function withfalse
), making the code more complex. I had to return a tuple, where the first argument was "isDone", which I'd use to see if I should return from the calling function or not. This made the code pretty sloppy, and I wasn't sure how to fix it. I guess I could have used closures, but wanted to be able to useconst
.Additional context
In my attempted solution, I ran into a problem where (what OpenCensus calls) root spans would not be modifiable, since all that was available was the SpanContext (using OpenTracing) which is immutable. I resorted to creating child spans in middleware, so the root span was never accessible, and there was always a Span available to modify with tags and logs.
The text was updated successfully, but these errors were encountered: