Skip to content
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

Merged
merged 6 commits into from
Nov 13, 2024
Merged

feat: OpenTelemetry Tracing API and Exporting #26710

merged 6 commits into from
Nov 13, 2024

Conversation

devsnek
Copy link
Member

@devsnek devsnek commented Nov 4, 2024

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.

@devsnek devsnek changed the title feat: OpenTelemetry API and Exporting feat: OpenTelemetry Tracing API and Exporting Nov 4, 2024
@bartlomieju bartlomieju added this to the 2.1.0 milestone Nov 4, 2024
@devsnek devsnek added the ci-draft Run the CI on draft PRs. label Nov 5, 2024
@devsnek devsnek marked this pull request as ready for review November 6, 2024 10:15
Copy link
Member

@bartlomieju bartlomieju left a 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",
Copy link
Member

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?

Copy link
Member

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.

cli/ops/bench.rs Outdated Show resolved Hide resolved
exit(): void;

/**
* End this span, and exit it as the "current" span.
Copy link
Member

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?

Copy link
Member Author

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;
Copy link
Member

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
Copy link
Member

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?

ext/web/15_performance.js Outdated Show resolved Hide resolved
ext/web/benches/timers_ops.rs Outdated Show resolved Hide resolved
runtime/lib.rs Show resolved Hide resolved
runtime/ops/os/mod.rs Show resolved Hide resolved
runtime/ops/otel.rs Outdated Show resolved Hide resolved
runtime/Cargo.toml Outdated Show resolved Hide resolved
let out = "";
for (let i = 0; i < bytes / 4; i += 1) {
const r32 = (MathRandom() * 2 ** 32) >>> 0;
out += hexSliceLookupTable[(r32 >> 24) & 0xff];
Copy link
Member

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);
Copy link
Member

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.

cli/args/mod.rs Outdated Show resolved Hide resolved
runtime/ops/otel.rs Show resolved Hide resolved
runtime/ops/otel.rs Show resolved Hide resolved
runtime/ops/otel.rs Outdated Show resolved Hide resolved
@KnorpelSenf
Copy link
Contributor

Does this in any way go towards #22102?

@lucacasonato
Copy link
Member

@KnorpelSenf No, not really.

@@ -1619,7 +1666,7 @@ dependencies = [
"encoding_rs",
"futures",
"import_map",
"indexmap",
"indexmap 2.3.0",
Copy link
Member

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.

Comment on lines +1280 to +1288
/**
* Enter this span as the "current" span.
*/
enter(): void;

/**
* Exit this span as the "current" span and restore the previous one.
*/
exit(): void;
Copy link
Member

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?

Copy link
Member Author

@devsnek devsnek Nov 12, 2024

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.

Copy link
Member

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?

startTime;
endTime;
status = null;
attributes = {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
attributes = {};
attributes = { __proto__: null };

Comment on lines 326 to 335
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;
}
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member

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

runtime/js/telemetry.js Show resolved Hide resolved
Copy link
Member

@lucacasonato lucacasonato left a 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

this.traceId = context.traceId ?? generateId(TRACE_ID_BYTES);
} else {
this.parentSpanId = parent.spanId;
this.traceId = parent.traceId ?? generateId(TRACE_ID_BYTES);
Copy link
Member

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?

@devsnek devsnek enabled auto-merge (squash) November 13, 2024 10:05
@devsnek devsnek merged commit aa54618 into main Nov 13, 2024
17 checks passed
@devsnek devsnek deleted the otel branch November 13, 2024 10:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci-draft Run the CI on draft PRs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants