-
Notifications
You must be signed in to change notification settings - Fork 847
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a withSpan
(or similar) convenience API
#3250
Comments
For reference, we made those utils at my company: import * as otelAPI from '@opentelemetry/api'
import * as otelCore from '@opentelemetry/core'
export function withSpan <T extends () => ReturnType<T>> (span: otelAPI.Span, fn: T): ReturnType<T> {
return otelAPI.context.with(
otelAPI.trace.setSpan(otelAPI.context.active(), span),
fn
)
}
export function withoutSpan <T extends () => ReturnType<T>> (fn: T): ReturnType<T> {
return otelAPI.context.with(
otelCore.suppressTracing(otelAPI.context.active()),
fn
)
}
export function newSpan (spanName: string, attributes: otelAPI.SpanAttributes) {
return otelAPI.trace.getTracer('default').startSpan(spanName, {
attributes
})
}
type Unpromisify<T> = T extends Promise<infer U> ? U : T
export async function withNewSpan <T extends () => ReturnType<T>> (
spanName: string,
attributes: otelAPI.SpanAttributes,
fn: T
): Promise<Unpromisify<ReturnType<T>>> {
const span = newSpan(spanName, attributes)
// note: we await even if not needed to ensure we end() the span when the function
// as been fully executed
// tslint:disable-next-line: await-promise
const result = await withSpan(span, fn)
span.end()
return result as any
}
export function withNewSpanSync <T extends () => ReturnType<T>> (
spanName: string,
attributes: otelAPI.SpanAttributes,
fn: T
): ReturnType<T> {
const span = newSpan(spanName, attributes)
const result = withSpan(span, fn)
span.end()
return result as any
} |
I wonder if export class SugaredTracer implements Tracer {
constructor(private _tracer: Tracer) {
this.startSpan = _tracer.startSpan.bind(_tracer);
this.startActiveSpan = _tracer.startActiveSpan.bind(_tracer);
}
startActiveSpan: Tracer['startActiveSpan'];
startSpan: Tracer['startSpan'];
withSpan <F extends (span: Span) => unknown>(name: string, options: SpanOptions, fn: F): ReturnType<F> {
const span = this._tracer.startSpan(name, options);
const ret = fn(span);
if (ret instanceof Promise) {
return ret.finally(() => span.end()) as ReturnType<F>;
}
span.end();
return ret as ReturnType<F>;
}
} |
Above helpers require also |
Another decision point would be if such a helper made the span the active span or not (and/or if there should be an equivalent Might be helpful to look at other languages that do this too:
|
only |
I think most of the time you're trying to wrap a callback in a span you would want it to be active in the callback. Almost by definition everything that happens within the callback would be a child of the callback operation and should be reflected that way in tracing data. |
Any concerns with implementing this? I'd be happy to contribute the sugared tracer design if that's preferred (it sounds like that would go in this repo and not the SDK repo?): #3250 |
@cartermp Are you working on this? I would really like to see a If not, I would start to look into it myself. |
@secustor I haven't started it no - was looking to see if anyone felt that was the right direction to go. But if you're keenly interested as well, I'd be more than happy to help review and discuss its usage. I too would love to see this added. |
Moving this to the main JS repository since we have decided to merge the repositories together. |
Thinking about if we could just make let sp = tracer.startActiveSpan("ugh", span => {
// something something something
return span
});
// This would now be a no-op if it were ended after the call to `startActiveSpan`
sp.addEvent("yippee");
sp.end(); Would that mean that any changes to |
It depends on your definition of "break" since the API itself isn't really changing, but assuming we agree that would be a breaking change then that's the way I understand it yes. But the name I think your code sample has the comment on the wrong line :) |
Here's our wrapper in case it's useful to others (would appreciate feedback). It has automatic span ending and error logging.
|
We have tried to make an improvement on the above ^
|
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days. |
👋🏽 I still consider this to be a need that's unmet by the JS tooling; the ability to use |
This is currently blocked by specification discussions. See the linked PR. |
Would #3827 solve this issue? |
I think so. I adapted the code proposed in the comments for my own company's instrumentation helpers. |
It kind of does. It doesn't solve the issue of wanting an auto-closing span within a function: function doot() {
withSpan((span) => {
// track an operation
});
// do something else
withSpan((span) => {
// track a different operation
});
} But it does likely eliminate a lot of the need for such a convenience API. |
I think this can be closed since #3317 has been merged. |
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days. |
This issue was closed because it has been stale for 14 days with no activity. |
We can close this issue since the question is addressed and we can create new issues for proposed convenience APIs
Originally posted by @dyladan in open-telemetry/opentelemetry-js-api#164 (comment)
I propose we add an API which takes a callback, automatically creating and ending a span. This has been proposed in the past and blocked for administrative reasons explained in the previously linked ticket, but I think now is the time to address it.
The text was updated successfully, but these errors were encountered: