summaryrefslogtreecommitdiff
path: root/runtime/js/telemetry.js
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/js/telemetry.js')
-rw-r--r--runtime/js/telemetry.js409
1 files changed, 0 insertions, 409 deletions
diff --git a/runtime/js/telemetry.js b/runtime/js/telemetry.js
deleted file mode 100644
index 195839fb1..000000000
--- a/runtime/js/telemetry.js
+++ /dev/null
@@ -1,409 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { core, primordials } from "ext:core/mod.js";
-import {
- op_otel_log,
- op_otel_span_attribute,
- op_otel_span_attribute2,
- op_otel_span_attribute3,
- op_otel_span_continue,
- op_otel_span_flush,
- op_otel_span_start,
-} from "ext:core/ops";
-import { Console } from "ext:deno_console/01_console.js";
-import { performance } from "ext:deno_web/15_performance.js";
-
-const {
- SymbolDispose,
- MathRandom,
- Array,
- ObjectEntries,
- SafeMap,
- ReflectApply,
- SymbolFor,
- Error,
- NumberPrototypeToString,
- StringPrototypePadStart,
-} = primordials;
-const { AsyncVariable, setAsyncContext } = core;
-
-const CURRENT = new AsyncVariable();
-let TRACING_ENABLED = false;
-let DETERMINISTIC = false;
-
-const SPAN_ID_BYTES = 8;
-const TRACE_ID_BYTES = 16;
-
-const TRACE_FLAG_SAMPLED = 1 << 0;
-
-const hexSliceLookupTable = (function () {
- const alphabet = "0123456789abcdef";
- const table = new Array(256);
- for (let i = 0; i < 16; ++i) {
- const i16 = i * 16;
- for (let j = 0; j < 16; ++j) {
- table[i16 + j] = alphabet[i] + alphabet[j];
- }
- }
- return table;
-})();
-
-let counter = 1;
-
-const INVALID_SPAN_ID = "0000000000000000";
-const INVALID_TRACE_ID = "00000000000000000000000000000000";
-
-function generateId(bytes) {
- if (DETERMINISTIC) {
- return StringPrototypePadStart(
- NumberPrototypeToString(counter++, 16),
- bytes * 2,
- "0",
- );
- }
- let out = "";
- for (let i = 0; i < bytes / 4; i += 1) {
- const r32 = (MathRandom() * 2 ** 32) >>> 0;
- out += hexSliceLookupTable[(r32 >> 24) & 0xff];
- out += hexSliceLookupTable[(r32 >> 16) & 0xff];
- out += hexSliceLookupTable[(r32 >> 8) & 0xff];
- out += hexSliceLookupTable[r32 & 0xff];
- }
- return out;
-}
-
-function submit(span) {
- if (!(span.traceFlags & TRACE_FLAG_SAMPLED)) return;
-
- op_otel_span_start(
- span.traceId,
- span.spanId,
- span.parentSpanId ?? "",
- span.kind,
- span.name,
- span.startTime,
- span.endTime,
- );
-
- if (span.status !== null && span.status.code !== 0) {
- op_otel_span_continue(span.code, span.message ?? "");
- }
-
- const attributes = ObjectEntries(span.attributes);
- let i = 0;
- while (i < attributes.length) {
- if (i + 2 < attributes.length) {
- op_otel_span_attribute3(
- attributes.length,
- attributes[i][0],
- attributes[i][1],
- attributes[i + 1][0],
- attributes[i + 1][1],
- attributes[i + 2][0],
- attributes[i + 2][1],
- );
- i += 3;
- } else if (i + 1 < attributes.length) {
- op_otel_span_attribute2(
- attributes.length,
- attributes[i][0],
- attributes[i][1],
- attributes[i + 1][0],
- attributes[i + 1][1],
- );
- i += 2;
- } else {
- op_otel_span_attribute(
- attributes.length,
- attributes[i][0],
- attributes[i][1],
- );
- i += 1;
- }
- }
-
- op_otel_span_flush();
-}
-
-const now = () => (performance.timeOrigin + performance.now()) / 1000;
-
-const NO_ASYNC_CONTEXT = {};
-
-class Span {
- traceId;
- spanId;
- parentSpanId;
- kind;
- name;
- startTime;
- endTime;
- status = null;
- attributes = { __proto__: null };
- traceFlags = TRACE_FLAG_SAMPLED;
-
- enabled = TRACING_ENABLED;
- #asyncContext = NO_ASYNC_CONTEXT;
-
- constructor(name, kind = "internal") {
- if (!this.enabled) {
- this.traceId = INVALID_TRACE_ID;
- this.spanId = INVALID_SPAN_ID;
- this.parentSpanId = INVALID_SPAN_ID;
- return;
- }
-
- this.startTime = now();
-
- this.spanId = generateId(SPAN_ID_BYTES);
-
- let traceId;
- let parentSpanId;
- const parent = Span.current();
- if (parent) {
- if (parent.spanId !== undefined) {
- parentSpanId = parent.spanId;
- traceId = parent.traceId;
- } else {
- const context = parent.spanContext();
- parentSpanId = context.spanId;
- traceId = context.traceId;
- }
- }
- if (
- traceId && traceId !== INVALID_TRACE_ID && parentSpanId &&
- parentSpanId !== INVALID_SPAN_ID
- ) {
- this.traceId = traceId;
- this.parentSpanId = parentSpanId;
- } else {
- this.traceId = generateId(TRACE_ID_BYTES);
- this.parentSpanId = INVALID_SPAN_ID;
- }
-
- this.name = name;
-
- switch (kind) {
- case "internal":
- this.kind = 0;
- break;
- case "server":
- this.kind = 1;
- break;
- case "client":
- this.kind = 2;
- break;
- case "producer":
- this.kind = 3;
- break;
- case "consumer":
- this.kind = 4;
- break;
- default:
- throw new Error(`Invalid span kind: ${kind}`);
- }
-
- this.enter();
- }
-
- // helper function to match otel js api
- spanContext() {
- return {
- traceId: this.traceId,
- spanId: this.spanId,
- traceFlags: this.traceFlags,
- };
- }
-
- setAttribute(name, value) {
- if (!this.enabled) return;
- this.attributes[name] = value;
- }
-
- enter() {
- if (!this.enabled) return;
- const context = (CURRENT.get() || ROOT_CONTEXT).setValue(SPAN_KEY, this);
- this.#asyncContext = CURRENT.enter(context);
- }
-
- exit() {
- if (!this.enabled || this.#asyncContext === NO_ASYNC_CONTEXT) return;
- setAsyncContext(this.#asyncContext);
- this.#asyncContext = NO_ASYNC_CONTEXT;
- }
-
- end() {
- if (!this.enabled || this.endTime !== undefined) return;
- this.exit();
- this.endTime = now();
- submit(this);
- }
-
- [SymbolDispose]() {
- this.end();
- }
-
- static current() {
- return CURRENT.get()?.getValue(SPAN_KEY);
- }
-}
-
-function hrToSecs(hr) {
- return ((hr[0] * 1e3 + hr[1] / 1e6) / 1000);
-}
-
-// Exporter compatible with opentelemetry js library
-class SpanExporter {
- export(spans, resultCallback) {
- try {
- for (let i = 0; i < spans.length; i += 1) {
- const span = spans[i];
- const context = span.spanContext();
- submit({
- spanId: context.spanId,
- traceId: context.traceId,
- traceFlags: context.traceFlags,
- name: span.name,
- kind: span.kind,
- parentSpanId: span.parentSpanId,
- startTime: hrToSecs(span.startTime),
- endTime: hrToSecs(span.endTime),
- status: span.status,
- attributes: span.attributes,
- });
- }
- resultCallback({ code: 0 });
- } catch (error) {
- resultCallback({ code: 1, error });
- }
- }
-
- async shutdown() {}
-
- async forceFlush() {}
-}
-
-// SPAN_KEY matches symbol in otel-js library
-const SPAN_KEY = SymbolFor("OpenTelemetry Context Key SPAN");
-
-// Context tracker compatible with otel-js api
-class Context {
- #data = new SafeMap();
-
- constructor(data) {
- this.#data = data ? new SafeMap(data) : new SafeMap();
- }
-
- getValue(key) {
- return this.#data.get(key);
- }
-
- setValue(key, value) {
- const c = new Context(this.#data);
- c.#data.set(key, value);
- return c;
- }
-
- deleteValue(key) {
- const c = new Context(this.#data);
- c.#data.delete(key);
- return c;
- }
-}
-
-const ROOT_CONTEXT = new Context();
-
-// Context manager for opentelemetry js library
-class ContextManager {
- active() {
- return CURRENT.get() ?? ROOT_CONTEXT;
- }
-
- with(context, fn, thisArg, ...args) {
- const ctx = CURRENT.enter(context);
- try {
- return ReflectApply(fn, thisArg, args);
- } finally {
- setAsyncContext(ctx);
- }
- }
-
- bind(context, f) {
- return (...args) => {
- const ctx = CURRENT.enter(context);
- try {
- return ReflectApply(f, thisArg, args);
- } finally {
- setAsyncContext(ctx);
- }
- };
- }
-
- enable() {
- return this;
- }
-
- disable() {
- return this;
- }
-}
-
-function otelLog(message, level) {
- let traceId = "";
- let spanId = "";
- let traceFlags = 0;
- const span = Span.current();
- if (span) {
- if (span.spanId !== undefined) {
- spanId = span.spanId;
- traceId = span.traceId;
- traceFlags = span.traceFlags;
- } else {
- const context = span.spanContext();
- spanId = context.spanId;
- traceId = context.traceId;
- traceFlags = context.traceFlags;
- }
- }
- return op_otel_log(message, level, traceId, spanId, traceFlags);
-}
-
-const otelConsoleConfig = {
- ignore: 0,
- capture: 1,
- replace: 2,
-};
-
-export function bootstrap(config) {
- if (config.length === 0) return;
- const { 0: consoleConfig, 1: deterministic } = config;
-
- TRACING_ENABLED = true;
- DETERMINISTIC = deterministic === 1;
-
- switch (consoleConfig) {
- case otelConsoleConfig.capture:
- core.wrapConsole(globalThis.console, new Console(otelLog));
- break;
- case otelConsoleConfig.replace:
- ObjectDefineProperty(
- globalThis,
- "console",
- core.propNonEnumerable(new Console(otelLog)),
- );
- break;
- default:
- break;
- }
-}
-
-export const tracing = {
- get enabled() {
- return TRACING_ENABLED;
- },
- Span,
- SpanExporter,
- ContextManager,
-};
-
-// TODO(devsnek): implement metrics
-export const metrics = {};