1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-01 16:51:13 -05:00

refactor(unstable): move telemetry to own ext (#27067)

Move telemetry to its own ext to clean up some code and resolve circular
deps.
This commit is contained in:
snek 2024-11-26 12:22:18 +01:00 committed by Bartek Iwańczuk
parent ec81cbbd86
commit 6755f5b55d
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
28 changed files with 164 additions and 88 deletions

30
Cargo.lock generated
View file

@ -1233,6 +1233,7 @@ dependencies = [
"deno_runtime",
"deno_semver",
"deno_task_shell",
"deno_telemetry",
"deno_terminal 0.2.0",
"deno_tower_lsp",
"dhat",
@ -2063,7 +2064,6 @@ dependencies = [
name = "deno_runtime"
version = "0.188.0"
dependencies = [
"async-trait",
"color-print",
"deno_ast",
"deno_broadcast_channel",
@ -2084,6 +2084,7 @@ dependencies = [
"deno_node",
"deno_path_util",
"deno_permissions",
"deno_telemetry",
"deno_terminal 0.2.0",
"deno_tls",
"deno_url",
@ -2109,13 +2110,7 @@ dependencies = [
"notify",
"ntapi",
"once_cell",
"opentelemetry",
"opentelemetry-http",
"opentelemetry-otlp",
"opentelemetry-semantic-conventions",
"opentelemetry_sdk",
"percent-encoding",
"pin-project",
"regex",
"rustyline",
"same-file",
@ -2164,6 +2159,27 @@ dependencies = [
"tokio-util",
]
[[package]]
name = "deno_telemetry"
version = "0.1.0"
dependencies = [
"async-trait",
"deno_core",
"http-body-util",
"hyper 1.4.1",
"hyper-util",
"log",
"once_cell",
"opentelemetry",
"opentelemetry-http",
"opentelemetry-otlp",
"opentelemetry-semantic-conventions",
"opentelemetry_sdk",
"pin-project",
"serde",
"tokio",
]
[[package]]
name = "deno_terminal"
version = "0.1.1"

View file

@ -21,6 +21,7 @@ members = [
"ext/napi/sym",
"ext/net",
"ext/node",
"ext/telemetry",
"ext/url",
"ext/web",
"ext/webgpu",
@ -82,6 +83,7 @@ deno_kv = { version = "0.87.0", path = "./ext/kv" }
deno_napi = { version = "0.110.0", path = "./ext/napi" }
deno_net = { version = "0.171.0", path = "./ext/net" }
deno_node = { version = "0.116.0", path = "./ext/node" }
deno_telemetry = { version = "0.1.0", path = "./ext/telemetry" }
deno_tls = { version = "0.166.0", path = "./ext/tls" }
deno_url = { version = "0.179.0", path = "./ext/url" }
deno_web = { version = "0.210.0", path = "./ext/web" }

View file

@ -83,6 +83,7 @@ deno_resolver.workspace = true
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_semver.workspace = true
deno_task_shell = "=0.18.1"
deno_telemetry.workspace = true
deno_terminal.workspace = true
libsui = "0.5.0"
node_resolver.workspace = true

View file

@ -36,7 +36,7 @@ use deno_path_util::normalize_path;
use deno_path_util::url_to_file_path;
use deno_runtime::deno_permissions::PermissionsOptions;
use deno_runtime::deno_permissions::SysDescriptor;
use deno_runtime::ops::otel::OtelConfig;
use deno_telemetry::OtelConfig;
use log::debug;
use log::Level;
use serde::Deserialize;
@ -2662,7 +2662,7 @@ By default, outdated dependencies are only displayed.
Display outdated dependencies:
<p(245)>deno outdated</>
<p(245)>deno outdated --compatible</>
Update dependencies:
<p(245)>deno outdated --update</>
<p(245)>deno outdated --update --latest</>
@ -3047,7 +3047,7 @@ fn task_subcommand() -> Command {
List all available tasks:
<p(245)>deno task</>
Evaluate a task from string
<p(245)>deno task --eval \"echo $(pwd)\"</>"
),

View file

@ -28,8 +28,8 @@ use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmSystemInfo;
use deno_path_util::normalize_path;
use deno_runtime::ops::otel::OtelConfig;
use deno_semver::npm::NpmPackageReqReference;
use deno_telemetry::OtelConfig;
use import_map::resolve_import_map_value_from_specifier;
pub use deno_config::deno_json::BenchConfig;

View file

@ -448,7 +448,7 @@ fn resolve_flags_and_init(
};
if let Some(otel_config) = flags.otel_config() {
deno_runtime::ops::otel::init(otel_config)?;
deno_telemetry::init(otel_config)?;
}
util::logger::init(flags.log_level);

View file

@ -88,7 +88,7 @@ fn main() {
match standalone {
Ok(Some(data)) => {
if let Some(otel_config) = data.metadata.otel_config.clone() {
deno_runtime::ops::otel::init(otel_config)?;
deno_telemetry::init(otel_config)?;
}
util::logger::init(data.metadata.log_level);
load_env_vars(&data.metadata.env_vars_from_env_file);

View file

@ -47,11 +47,11 @@ use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_fs::RealFs;
use deno_runtime::deno_io::fs::FsError;
use deno_runtime::deno_node::PackageJson;
use deno_runtime::ops::otel::OtelConfig;
use deno_semver::npm::NpmVersionReqParseError;
use deno_semver::package::PackageReq;
use deno_semver::Version;
use deno_semver::VersionReqSpecifierParseError;
use deno_telemetry::OtelConfig;
use indexmap::IndexMap;
use log::Level;
use serde::Deserialize;

View file

@ -29,7 +29,7 @@ impl log::Log for CliLogger {
// thread's state
DrawThread::hide();
self.0.log(record);
deno_runtime::ops::otel::handle_log(record);
deno_telemetry::handle_log(record);
DrawThread::show();
}
}

View file

@ -30,7 +30,6 @@ use deno_runtime::deno_tls::RootCertStoreProvider;
use deno_runtime::deno_web::BlobStore;
use deno_runtime::fmt_errors::format_js_error;
use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::ops::otel::OtelConfig;
use deno_runtime::ops::process::NpmProcessStateProviderRc;
use deno_runtime::ops::worker_host::CreateWebWorkerCb;
use deno_runtime::web_worker::WebWorker;
@ -43,6 +42,7 @@ use deno_runtime::BootstrapOptions;
use deno_runtime::WorkerExecutionMode;
use deno_runtime::WorkerLogLevel;
use deno_semver::npm::NpmPackageReqReference;
use deno_telemetry::OtelConfig;
use deno_terminal::colors;
use node_resolver::NodeModuleKind;
use node_resolver::NodeResolutionMode;

View file

@ -10,7 +10,7 @@
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
import { core, internals, primordials } from "ext:core/mod.js";
import { core, primordials } from "ext:core/mod.js";
import {
op_fetch,
op_fetch_promise_is_settled,
@ -32,7 +32,6 @@ const {
SafePromisePrototypeFinally,
String,
StringPrototypeEndsWith,
StringPrototypeSlice,
StringPrototypeStartsWith,
StringPrototypeToLowerCase,
TypeError,
@ -59,6 +58,17 @@ import {
toInnerResponse,
} from "ext:deno_fetch/23_response.js";
import * as abortSignal from "ext:deno_web/03_abort_signal.js";
import {
endSpan,
enterSpan,
exitSpan,
Span,
TRACING_ENABLED,
} from "ext:deno_telemetry/telemetry.ts";
import {
updateSpanFromRequest,
updateSpanFromResponse,
} from "ext:deno_telemetry/util.ts";
const REQUEST_BODY_HEADER_NAMES = [
"content-encoding",
@ -343,9 +353,9 @@ function httpRedirectFetch(request, response, terminator) {
function fetch(input, init = { __proto__: null }) {
let span;
try {
if (internals.telemetry?.tracingEnabled) {
span = new internals.telemetry.Span("fetch", { kind: 2 });
internals.telemetry.enterSpan(span);
if (TRACING_ENABLED) {
span = new Span("fetch", { kind: 2 });
enterSpan(span);
}
// There is an async dispatch later that causes a stack trace disconnect.
@ -361,16 +371,7 @@ function fetch(input, init = { __proto__: null }) {
const requestObject = new Request(input, init);
if (span) {
span.updateName(requestObject.method);
span.setAttribute("http.request.method", requestObject.method);
const url = new URL(requestObject.url);
span.setAttribute("url.full", requestObject.url);
span.setAttribute(
"url.scheme",
StringPrototypeSlice(url.protocol, 0, -1),
);
span.setAttribute("url.path", url.pathname);
span.setAttribute("url.query", StringPrototypeSlice(url.search, 1));
updateSpanFromRequest(span, requestObject);
}
// 3.
@ -432,10 +433,7 @@ function fetch(input, init = { __proto__: null }) {
responseObject = fromInnerResponse(response, "immutable");
if (span) {
span.setAttribute(
"http.response.status_code",
String(responseObject.status),
);
updateSpanFromResponse(span, responseObject);
}
resolve(responseObject);
@ -457,7 +455,7 @@ function fetch(input, init = { __proto__: null }) {
return result;
} finally {
if (span) {
internals.telemetry.endSpan(span);
endSpan(span);
}
}
})();
@ -471,18 +469,18 @@ function fetch(input, init = { __proto__: null }) {
// XXX: This should always be true, otherwise `opPromise` would be present.
if (op_fetch_promise_is_settled(result)) {
// It's already settled.
internals.telemetry.endSpan(span);
endSpan(span);
} else {
// Not settled yet, we can return a new wrapper promise.
return SafePromisePrototypeFinally(result, () => {
internals.telemetry.endSpan(span);
endSpan(span);
});
}
}
return result;
} finally {
if (span) {
internals.telemetry.exitSpan(span);
exitSpan(span);
}
}
}

View file

@ -36,9 +36,7 @@ const {
PromisePrototypeCatch,
SafePromisePrototypeFinally,
PromisePrototypeThen,
String,
StringPrototypeIncludes,
StringPrototypeSlice,
Symbol,
TypeError,
TypedArrayPrototypeGetSymbolToStringTag,
@ -91,6 +89,16 @@ import {
} from "ext:deno_net/01_net.js";
import { hasTlsKeyPairOptions, listenTls } from "ext:deno_net/02_tls.js";
import { SymbolAsyncDispose } from "ext:deno_web/00_infra.js";
import {
endSpan,
enterSpan,
Span,
TRACING_ENABLED,
} from "ext:deno_telemetry/telemetry.ts";
import {
updateSpanFromRequest,
updateSpanFromResponse,
} from "ext:deno_telemetry/util.ts";
const _upgraded = Symbol("_upgraded");
@ -527,16 +535,7 @@ function mapToCallback(context, callback, onError) {
innerRequest.request = request;
if (span) {
span.updateName(request.method);
span.setAttribute("http.request.method", request.method);
const url = new URL(request.url);
span.setAttribute("url.full", request.url);
span.setAttribute(
"url.scheme",
StringPrototypeSlice(url.protocol, 0, -1),
);
span.setAttribute("url.path", url.pathname);
span.setAttribute("url.query", StringPrototypeSlice(url.search, 1));
updateSpanFromRequest(span, request);
}
response = await callback(
@ -578,10 +577,7 @@ function mapToCallback(context, callback, onError) {
}
if (span) {
span.setAttribute(
"http.response.status_code",
String(response.status),
);
updateSpanFromResponse(span, response);
}
const inner = toInnerResponse(response);
@ -617,8 +613,7 @@ function mapToCallback(context, callback, onError) {
fastSyncResponseOrStream(req, inner.body, status, innerRequest);
};
if (internals.telemetry?.tracingEnabled) {
const { Span, enterSpan, endSpan } = internals.telemetry;
if (TRACING_ENABLED) {
const origMapped = mapped;
mapped = function (req, _span) {
const oldCtx = getAsyncContext();

31
ext/telemetry/Cargo.toml Normal file
View file

@ -0,0 +1,31 @@
# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
[package]
name = "deno_telemetry"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
readme = "README.md"
repository.workspace = true
description = "Telemetry for Deno"
[lib]
path = "lib.rs"
[dependencies]
async-trait.workspace = true
deno_core.workspace = true
http-body-util.workspace = true
hyper.workspace = true
hyper-util.workspace = true
log.workspace = true
once_cell.workspace = true
opentelemetry.workspace = true
opentelemetry-http.workspace = true
opentelemetry-otlp.workspace = true
opentelemetry-semantic-conventions.workspace = true
opentelemetry_sdk.workspace = true
pin-project.workspace = true
serde.workspace = true
tokio.workspace = true

3
ext/telemetry/README.md Normal file
View file

@ -0,0 +1,3 @@
# `deno_telemetry`
This crate implements telemetry for Deno using OpenTelemetry.

View file

@ -1,6 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::tokio_util::create_basic_runtime;
use deno_core::anyhow;
use deno_core::anyhow::anyhow;
use deno_core::futures::channel::mpsc;
@ -59,7 +58,7 @@ type SpanProcessor = BatchSpanProcessor<OtelSharedRuntime>;
type LogProcessor = BatchLogProcessor<OtelSharedRuntime>;
deno_core::extension!(
deno_otel,
deno_telemetry,
ops = [
op_otel_log,
op_otel_instrumentation_scope_create_and_enter,
@ -73,6 +72,7 @@ deno_core::extension!(
op_otel_span_set_dropped,
op_otel_span_flush,
],
esm = ["telemetry.ts", "util.ts"],
);
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -111,7 +111,26 @@ fn otel_create_shared_runtime() -> UnboundedSender<BoxFuture<'static, ()>> {
mpsc::unbounded::<BoxFuture<'static, ()>>();
thread::spawn(move || {
let rt = create_basic_runtime();
let rt = tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
// This limits the number of threads for blocking operations (like for
// synchronous fs ops) or CPU bound tasks like when we run dprint in
// parallel for deno fmt.
// The default value is 512, which is an unhelpfully large thread pool. We
// don't ever want to have more than a couple dozen threads.
.max_blocking_threads(if cfg!(windows) {
// on windows, tokio uses blocking tasks for child process IO, make sure
// we have enough available threads for other tasks to run
4 * std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(8)
} else {
32
})
.build()
.unwrap();
rt.block_on(async move {
while let Some(task) = spawn_task_rx.next().await {
tokio::spawn(task);

View file

@ -1,6 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { core, internals, primordials } from "ext:core/mod.js";
import { core, primordials } from "ext:core/mod.js";
import {
op_crypto_get_random_values,
op_otel_instrumentation_scope_create_and_enter,
@ -38,7 +38,7 @@ const {
} = primordials;
const { AsyncVariable, setAsyncContext } = core;
let TRACING_ENABLED = false;
export let TRACING_ENABLED = false;
let DETERMINISTIC = false;
// Note: These start at 0 in the JS library,
@ -709,12 +709,3 @@ export const telemetry = {
SpanExporter,
ContextManager,
};
internals.telemetry = {
Span,
enterSpan,
exitSpan,
endSpan,
get tracingEnabled() {
return TRACING_ENABLED;
},
};

27
ext/telemetry/util.ts Normal file
View file

@ -0,0 +1,27 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { primordials } from "ext:core/mod.js";
import type { Span } from "ext:deno_telemetry/telemetry.ts";
const { String, StringPrototypeSlice } = primordials;
export function updateSpanFromRequest(span: Span, request: Request) {
span.updateName(request.method);
span.setAttribute("http.request.method", request.method);
const url = new URL(request.url);
span.setAttribute("url.full", request.url);
span.setAttribute(
"url.scheme",
StringPrototypeSlice(url.protocol, 0, -1),
);
span.setAttribute("url.path", url.pathname);
span.setAttribute("url.query", StringPrototypeSlice(url.search, 1));
}
export function updateSpanFromResponse(span: Span, response: Response) {
span.setAttribute(
"http.response.status_code",
String(response.status),
);
}

View file

@ -90,6 +90,7 @@ deno_net.workspace = true
deno_node.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
deno_telemetry.workspace = true
deno_terminal.workspace = true
deno_tls.workspace = true
deno_url.workspace = true
@ -100,7 +101,6 @@ deno_websocket.workspace = true
deno_webstorage.workspace = true
node_resolver = { workspace = true, features = ["sync"] }
async-trait.workspace = true
color-print.workspace = true
dlopen2.workspace = true
encoding_rs.workspace = true
@ -115,13 +115,7 @@ log.workspace = true
netif = "0.1.6"
notify.workspace = true
once_cell.workspace = true
opentelemetry.workspace = true
opentelemetry-http.workspace = true
opentelemetry-otlp.workspace = true
opentelemetry-semantic-conventions.workspace = true
opentelemetry_sdk.workspace = true
percent-encoding.workspace = true
pin-project.workspace = true
regex.workspace = true
rustyline = { workspace = true, features = ["custom-bindings"] }
same-file = "1.0.6"

View file

@ -29,7 +29,7 @@ import * as tty from "ext:runtime/40_tty.js";
import * as kv from "ext:deno_kv/01_db.ts";
import * as cron from "ext:deno_cron/01_cron.ts";
import * as webgpuSurface from "ext:deno_webgpu/02_surface.js";
import * as telemetry from "ext:runtime/telemetry.ts";
import * as telemetry from "ext:deno_telemetry/telemetry.ts";
const denoNs = {
Process: process.Process,

View file

@ -86,7 +86,7 @@ import {
workerRuntimeGlobalProperties,
} from "ext:runtime/98_global_scope_worker.js";
import { SymbolDispose, SymbolMetadata } from "ext:deno_web/00_infra.js";
import { bootstrap as bootstrapOtel } from "ext:runtime/telemetry.ts";
import { bootstrap as bootstrapOtel } from "ext:deno_telemetry/telemetry.ts";
// deno-lint-ignore prefer-primordials
if (Symbol.metadata) {

View file

@ -148,7 +148,7 @@ pub static UNSTABLE_GRANULAR_FLAGS: &[UnstableGranularFlag] = &[
];
pub fn exit(code: i32) -> ! {
crate::ops::otel::flush();
deno_telemetry::flush();
#[allow(clippy::disallowed_methods)]
std::process::exit(code);
}

View file

@ -4,7 +4,6 @@ pub mod bootstrap;
pub mod fs_events;
pub mod http;
pub mod os;
pub mod otel;
pub mod permissions;
pub mod process;
pub mod runtime;

View file

@ -47,7 +47,6 @@ extension!(runtime,
"40_signals.js",
"40_tty.js",
"41_prompt.js",
"telemetry.ts",
"90_deno_ns.js",
"98_global_scope_shared.js",
"98_global_scope_window.js",

View file

@ -268,6 +268,7 @@ pub fn create_runtime_snapshot(
// `runtime/worker.rs`, `runtime/web_worker.rs` and `runtime/snapshot.rs`!
let fs = std::sync::Arc::new(deno_fs::RealFs);
let mut extensions: Vec<Extension> = vec![
deno_telemetry::deno_telemetry::init_ops_and_esm(),
deno_webidl::deno_webidl::init_ops_and_esm(),
deno_console::deno_console::init_ops_and_esm(),
deno_url::deno_url::init_ops_and_esm(),
@ -314,7 +315,6 @@ pub fn create_runtime_snapshot(
),
ops::fs_events::deno_fs_events::init_ops(),
ops::os::deno_os::init_ops(Default::default()),
ops::otel::deno_otel::init_ops(),
ops::permissions::deno_permissions::init_ops(),
ops::process::deno_process::init_ops(None),
ops::signal::deno_signal::init_ops(),

View file

@ -440,6 +440,7 @@ impl WebWorker {
// `runtime/worker.rs` and `runtime/snapshot.rs`!
let mut extensions = vec![
deno_telemetry::deno_telemetry::init_ops_and_esm(),
// Web APIs
deno_webidl::deno_webidl::init_ops_and_esm(),
deno_console::deno_console::init_ops_and_esm(),
@ -517,7 +518,6 @@ impl WebWorker {
),
ops::fs_events::deno_fs_events::init_ops_and_esm(),
ops::os::deno_os_worker::init_ops_and_esm(),
ops::otel::deno_otel::init_ops_and_esm(),
ops::permissions::deno_permissions::init_ops_and_esm(),
ops::process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,

View file

@ -348,6 +348,7 @@ impl MainWorker {
// NOTE(bartlomieju): ordering is important here, keep it in sync with
// `runtime/web_worker.rs` and `runtime/snapshot.rs`!
let mut extensions = vec![
deno_telemetry::deno_telemetry::init_ops_and_esm(),
// Web APIs
deno_webidl::deno_webidl::init_ops_and_esm(),
deno_console::deno_console::init_ops_and_esm(),
@ -428,7 +429,6 @@ impl MainWorker {
),
ops::fs_events::deno_fs_events::init_ops_and_esm(),
ops::os::deno_os::init_ops_and_esm(exit_code.clone()),
ops::otel::deno_otel::init_ops_and_esm(),
ops::permissions::deno_permissions::init_ops_and_esm(),
ops::process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,

View file

@ -1,8 +1,8 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::ops::otel::OtelConfig;
use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_telemetry::OtelConfig;
use serde::Serialize;
use std::cell::RefCell;
use std::thread;

View file

@ -247,8 +247,9 @@
"ext:runtime/41_prompt.js": "../runtime/js/41_prompt.js",
"ext:runtime/90_deno_ns.js": "../runtime/js/90_deno_ns.js",
"ext:runtime/98_global_scope.js": "../runtime/js/98_global_scope.js",
"ext:runtime/telemetry.ts": "../runtime/js/telemetry.ts",
"ext:deno_node/_util/std_fmt_colors.ts": "../ext/node/polyfills/_util/std_fmt_colors.ts",
"ext:deno_telemetry/telemetry.ts": "../ext/deno_telemetry/telemetry.ts",
"ext:deno_telemetry/util.ts": "../ext/deno_telemetry/util.ts",
"@std/archive": "../tests/util/std/archive/mod.ts",
"@std/archive/tar": "../tests/util/std/archive/tar.ts",
"@std/archive/untar": "../tests/util/std/archive/untar.ts",