-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
feat: OpenTelemetry Tracing API and Exporting #26710
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First pass from me. This looks really great 🚀
@@ -1619,7 +1666,7 @@ dependencies = [ | |||
"encoding_rs", | |||
"futures", | |||
"import_map", | |||
"indexmap", | |||
"indexmap 2.3.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devsnek could you try to remove so many duplicate versions of various dependencies added in this PR? Maybe we could bump some of the version we use in Deno?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is because opentelemetry-otel
uses tonic
, which still relies on tonic 0.4
rather than tonic 0.5
. This will be fixed in the next tonic
release (see hyperium/tonic@58345a6). There is not much we can do for now.
exit(): void; | ||
|
||
/** | ||
* End this span, and exit it as the "current" span. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the difference between exit()
and end()
. Does end()
not restore the previous one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enter and exit control the span scope. end marks the end time of the span and submits it to be collected.
|
||
[Symbol.dispose](): void; | ||
|
||
static current(): Span | undefined | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this on purpose that it's undefined | null
?
} | ||
|
||
/** | ||
* A SpanExporter compatible with OpenTelemetry.js |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you link here and in the next one to relevant package or repo?
let out = ""; | ||
for (let i = 0; i < bytes / 4; i += 1) { | ||
const r32 = (MathRandom() * 2 ** 32) >>> 0; | ||
out += hexSliceLookupTable[(r32 >> 24) & 0xff]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this somehow faster than r32.toString(16).padStart(8, '0')
?
@@ -186,6 +186,8 @@ fn op_get_exit_code(state: &mut OpState) -> i32 { | |||
|
|||
#[op2(fast)] | |||
fn op_exit(state: &mut OpState) { | |||
crate::ops::otel::otel_drop_state(state); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have some tests that ensure the OTEL pipeline is properly flushed before the process exits. Some scenarios:
console.log("foo"); // Program naturally exits here
console.log("foo"); Deno.exit(0);
console.log("foo"); throw new Error("uncaught");
- Web worker logs something and immediate calls
self.close()
- Web worker logs something and the main worker immediately calls
worker.terminate()
- Web worker logs something and calls
Deno.exit()
- Web worker logs something and throws an exception.
Does this in any way go towards #22102? |
@KnorpelSenf No, not really. |
@@ -1619,7 +1666,7 @@ dependencies = [ | |||
"encoding_rs", | |||
"futures", | |||
"import_map", | |||
"indexmap", | |||
"indexmap 2.3.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is because opentelemetry-otel
uses tonic
, which still relies on tonic 0.4
rather than tonic 0.5
. This will be fixed in the next tonic
release (see hyperium/tonic@58345a6). There is not much we can do for now.
/** | ||
* Enter this span as the "current" span. | ||
*/ | ||
enter(): void; | ||
|
||
/** | ||
* Exit this span as the "current" span and restore the previous one. | ||
*/ | ||
exit(): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not something that exists in otel-js, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
otel-js has a pretty confusing api but at a high level it does not have the ability to enter/exit spans without calling a callback, like this: const span = tracer.startActiveSpan(() => { doSomething(); span.end(); });
. On our side we have enter/exit, but we also have the nicer choice of doing using span = new Deno.tracing.Span();
which will automatically exit/end when disposed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok - because we have that, do we need enter
and exit
? I think we should just force people to use using
?
runtime/js/telemetry.js
Outdated
startTime; | ||
endTime; | ||
status = null; | ||
attributes = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
attributes = {}; | |
attributes = { __proto__: null }; |
runtime/js/telemetry.js
Outdated
if (span.spanContext) { | ||
const context = span.spanContext(); | ||
traceId = context.traceId; | ||
spanId = context.spanId; | ||
traceFlags = context.traceFlags; | ||
} else { | ||
traceId = span.traceId; | ||
spanId = span.spanId; | ||
traceFlags = span.traceFlags; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get it - when is spanContext
empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
originally when i wrote this our spans did not have spanContext
for compat. i can reverse this to be if (span.spanId)
to avoid calling spanContext unless needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes that'd be good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM once you resolve the two open threads
runtime/js/telemetry.js
Outdated
this.traceId = context.traceId ?? generateId(TRACE_ID_BYTES); | ||
} else { | ||
this.parentSpanId = parent.spanId; | ||
this.traceId = parent.traceId ?? generateId(TRACE_ID_BYTES); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does this need to default to generateId
?
Initial import of OTEL code supporting tracing. Metrics soon to come. Implements APIs for https://jsr.io/@deno/otel so that code using OpenTelemetry.js just works tm.
There is still a lot of work to do with configuration and adding built-in tracing to core APIs, which will come in followup PRs.