mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
feat(runtime): send console output to OpenTelemetry collector (#3)
This commit is contained in:
parent
9e2fac050f
commit
dfbebad91e
17 changed files with 538 additions and 7 deletions
148
Cargo.lock
generated
148
Cargo.lock
generated
|
@ -1620,7 +1620,7 @@ dependencies = [
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"log",
|
"log",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"prost",
|
"prost 0.11.9",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
"rand",
|
"rand",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
@ -1835,6 +1835,7 @@ dependencies = [
|
||||||
name = "deno_runtime"
|
name = "deno_runtime"
|
||||||
version = "0.169.0"
|
version = "0.169.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"deno_ast",
|
"deno_ast",
|
||||||
"deno_broadcast_channel",
|
"deno_broadcast_channel",
|
||||||
"deno_cache",
|
"deno_cache",
|
||||||
|
@ -1872,13 +1873,19 @@ dependencies = [
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"maplit",
|
||||||
"netif",
|
"netif",
|
||||||
"nix 0.26.2",
|
"nix 0.26.2",
|
||||||
"notify",
|
"notify",
|
||||||
"ntapi",
|
"ntapi",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"opentelemetry",
|
||||||
|
"opentelemetry-otlp",
|
||||||
|
"opentelemetry-semantic-conventions",
|
||||||
|
"opentelemetry_sdk",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"regex",
|
"regex",
|
||||||
|
"reqwest",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
"serde",
|
"serde",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
|
@ -2061,7 +2068,7 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"futures",
|
"futures",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"prost",
|
"prost 0.11.9",
|
||||||
"serde",
|
"serde",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
@ -2081,7 +2088,7 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"log",
|
"log",
|
||||||
"prost",
|
"prost 0.11.9",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -4498,6 +4505,88 @@ version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opentelemetry"
|
||||||
|
version = "0.24.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c365a63eec4f55b7efeceb724f1336f26a9cf3427b70e59e2cd2a5b947fba96"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"js-sys",
|
||||||
|
"once_cell",
|
||||||
|
"pin-project-lite",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opentelemetry-http"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad31e9de44ee3538fb9d64fe3376c1362f406162434609e79aea2a41a0af78ab"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"http 1.1.0",
|
||||||
|
"opentelemetry",
|
||||||
|
"reqwest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opentelemetry-otlp"
|
||||||
|
version = "0.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b925a602ffb916fb7421276b86756027b37ee708f9dce2dbdcc51739f07e727"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"futures-core",
|
||||||
|
"http 1.1.0",
|
||||||
|
"opentelemetry",
|
||||||
|
"opentelemetry-http",
|
||||||
|
"opentelemetry-proto",
|
||||||
|
"opentelemetry_sdk",
|
||||||
|
"prost 0.13.1",
|
||||||
|
"reqwest",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opentelemetry-proto"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30ee9f20bff9c984511a02f082dc8ede839e4a9bf15cc2487c8d6fea5ad850d9"
|
||||||
|
dependencies = [
|
||||||
|
"opentelemetry",
|
||||||
|
"opentelemetry_sdk",
|
||||||
|
"prost 0.13.1",
|
||||||
|
"tonic",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opentelemetry-semantic-conventions"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cefe0543875379e47eb5f1e68ff83f45cc41366a92dfd0d073d513bf68e9a05"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opentelemetry_sdk"
|
||||||
|
version = "0.24.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "692eac490ec80f24a17828d49b40b60f5aeaccdfe6a503f939713afd22bc28df"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-util",
|
||||||
|
"glob",
|
||||||
|
"once_cell",
|
||||||
|
"opentelemetry",
|
||||||
|
"percent-encoding",
|
||||||
|
"rand",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -5041,7 +5130,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd"
|
checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"prost-derive",
|
"prost-derive 0.11.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"prost-derive 0.13.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5058,7 +5157,7 @@ dependencies = [
|
||||||
"multimap",
|
"multimap",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"prettyplease 0.1.25",
|
"prettyplease 0.1.25",
|
||||||
"prost",
|
"prost 0.11.9",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
"regex",
|
"regex",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
|
@ -5079,13 +5178,26 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-derive"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.58",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prost-types"
|
name = "prost-types"
|
||||||
version = "0.11.9"
|
version = "0.11.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13"
|
checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prost",
|
"prost 0.11.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5370,6 +5482,7 @@ dependencies = [
|
||||||
"async-compression",
|
"async-compression",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2 0.4.4",
|
"h2 0.4.4",
|
||||||
|
@ -6843,7 +6956,7 @@ dependencies = [
|
||||||
"os_pipe",
|
"os_pipe",
|
||||||
"parking_lot 0.12.3",
|
"parking_lot 0.12.3",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"prost",
|
"prost 0.11.9",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
@ -7090,6 +7203,27 @@ dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tonic"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38659f4a91aba8598d27821589f5db7dddd94601e7a01b1e485a50e5484c7401"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"base64 0.22.1",
|
||||||
|
"bytes",
|
||||||
|
"http 1.1.0",
|
||||||
|
"http-body 1.0.0",
|
||||||
|
"http-body-util",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project",
|
||||||
|
"prost 0.13.1",
|
||||||
|
"tokio-stream",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
|
|
|
@ -589,6 +589,7 @@ pub struct Flags {
|
||||||
pub permissions: PermissionFlags,
|
pub permissions: PermissionFlags,
|
||||||
pub allow_scripts: PackagesAllowedScripts,
|
pub allow_scripts: PackagesAllowedScripts,
|
||||||
pub eszip: bool,
|
pub eszip: bool,
|
||||||
|
pub otel: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||||
|
@ -3330,6 +3331,7 @@ fn runtime_args(
|
||||||
.arg(enable_testing_features_arg())
|
.arg(enable_testing_features_arg())
|
||||||
.arg(strace_ops_arg())
|
.arg(strace_ops_arg())
|
||||||
.arg(eszip_arg())
|
.arg(eszip_arg())
|
||||||
|
.arg(otel_arg())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inspect_args(app: Command) -> Command {
|
fn inspect_args(app: Command) -> Command {
|
||||||
|
@ -3456,6 +3458,14 @@ fn eszip_arg() -> Arg {
|
||||||
.help("Run eszip")
|
.help("Run eszip")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn otel_arg() -> Arg {
|
||||||
|
Arg::new("otel-internal-do-not-use")
|
||||||
|
.long("otel-internal-do-not-use")
|
||||||
|
.action(ArgAction::SetTrue)
|
||||||
|
.help("Enable OpenTelemetry")
|
||||||
|
.hide(true)
|
||||||
|
}
|
||||||
|
|
||||||
/// Used for subcommands that operate on executable scripts only.
|
/// Used for subcommands that operate on executable scripts only.
|
||||||
/// `deno fmt` has its own `--ext` arg because its possible values differ.
|
/// `deno fmt` has its own `--ext` arg because its possible values differ.
|
||||||
/// If --ext is not provided and the script doesn't have a file extension,
|
/// If --ext is not provided and the script doesn't have a file extension,
|
||||||
|
@ -4740,6 +4750,7 @@ fn runtime_args_parse(
|
||||||
env_file_arg_parse(flags, matches);
|
env_file_arg_parse(flags, matches);
|
||||||
strace_ops_parse(flags, matches);
|
strace_ops_parse(flags, matches);
|
||||||
eszip_arg_parse(flags, matches);
|
eszip_arg_parse(flags, matches);
|
||||||
|
otel_arg_parse(flags, matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inspect_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
fn inspect_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||||
|
@ -4831,6 +4842,12 @@ fn eszip_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn otel_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||||
|
if matches.get_flag("otel-internal-do-not-use") {
|
||||||
|
flags.otel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ext_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
fn ext_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||||
flags.ext = matches.remove_one::<String>("ext");
|
flags.ext = matches.remove_one::<String>("ext");
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ use deno_runtime::deno_fs::DenoConfigFsAdapter;
|
||||||
use deno_runtime::deno_fs::RealFs;
|
use deno_runtime::deno_fs::RealFs;
|
||||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||||
|
use deno_runtime::ops::otel::OtelConfig;
|
||||||
use deno_semver::npm::NpmPackageReqReference;
|
use deno_semver::npm::NpmPackageReqReference;
|
||||||
use import_map::resolve_import_map_value_from_specifier;
|
use import_map::resolve_import_map_value_from_specifier;
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ use once_cell::sync::Lazy;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
@ -1103,6 +1105,13 @@ impl CliOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn otel_config(&self) -> Option<OtelConfig> {
|
||||||
|
self.flags.otel.then(|| OtelConfig {
|
||||||
|
default_service_name: Cow::Borrowed("deno"),
|
||||||
|
default_service_version: Cow::Borrowed(crate::version::deno()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn env_file_name(&self) -> Option<&String> {
|
pub fn env_file_name(&self) -> Option<&String> {
|
||||||
self.flags.env_file.as_ref()
|
self.flags.env_file.as_ref()
|
||||||
}
|
}
|
||||||
|
|
|
@ -833,6 +833,7 @@ impl CliFactory {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
self.options.otel_config(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ use deno_core::serde_json;
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
use deno_npm::NpmSystemInfo;
|
use deno_npm::NpmSystemInfo;
|
||||||
use deno_runtime::deno_node::PackageJson;
|
use deno_runtime::deno_node::PackageJson;
|
||||||
|
use deno_runtime::ops::otel::OtelConfig;
|
||||||
use deno_semver::npm::NpmVersionReqParseError;
|
use deno_semver::npm::NpmVersionReqParseError;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
use deno_semver::VersionReqSpecifierParseError;
|
use deno_semver::VersionReqSpecifierParseError;
|
||||||
|
@ -103,6 +104,7 @@ pub struct Metadata {
|
||||||
pub node_modules: Option<NodeModules>,
|
pub node_modules: Option<NodeModules>,
|
||||||
pub disable_deprecated_api_warning: bool,
|
pub disable_deprecated_api_warning: bool,
|
||||||
pub unstable_config: UnstableConfig,
|
pub unstable_config: UnstableConfig,
|
||||||
|
pub otel_config: Option<OtelConfig>, // None means disabled.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_npm_vfs(root_dir_path: PathBuf) -> Result<FileBackedVfs, AnyError> {
|
pub fn load_npm_vfs(root_dir_path: PathBuf) -> Result<FileBackedVfs, AnyError> {
|
||||||
|
@ -645,6 +647,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
||||||
sloppy_imports: cli_options.unstable_sloppy_imports(),
|
sloppy_imports: cli_options.unstable_sloppy_imports(),
|
||||||
features: cli_options.unstable_features(),
|
features: cli_options.unstable_features(),
|
||||||
},
|
},
|
||||||
|
otel_config: cli_options.otel_config(),
|
||||||
};
|
};
|
||||||
|
|
||||||
write_binary_bytes(
|
write_binary_bytes(
|
||||||
|
|
|
@ -740,6 +740,7 @@ pub async fn run(
|
||||||
false,
|
false,
|
||||||
// Code cache is not supported for standalone binary yet.
|
// Code cache is not supported for standalone binary yet.
|
||||||
None,
|
None,
|
||||||
|
metadata.otel_config,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize v8 once from the main thread.
|
// Initialize v8 once from the main thread.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use deno_config::workspace::PackageJsonDepResolution;
|
use deno_config::workspace::PackageJsonDepResolution;
|
||||||
|
@ -11,6 +12,7 @@ use deno_core::futures::StreamExt;
|
||||||
use deno_core::unsync::spawn;
|
use deno_core::unsync::spawn;
|
||||||
use deno_runtime::deno_permissions::Permissions;
|
use deno_runtime::deno_permissions::Permissions;
|
||||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||||
|
use deno_runtime::ops::otel::OtelConfig;
|
||||||
use deno_runtime::WorkerExecutionMode;
|
use deno_runtime::WorkerExecutionMode;
|
||||||
use eszip::EszipV2;
|
use eszip::EszipV2;
|
||||||
use tokio_util::compat::TokioAsyncReadCompatExt;
|
use tokio_util::compat::TokioAsyncReadCompatExt;
|
||||||
|
@ -289,6 +291,10 @@ pub async fn run_eszip(
|
||||||
package_jsons: Default::default(),
|
package_jsons: Default::default(),
|
||||||
pkg_json_resolution: PackageJsonDepResolution::Disabled,
|
pkg_json_resolution: PackageJsonDepResolution::Disabled,
|
||||||
},
|
},
|
||||||
|
otel_config: flags.otel.then(|| OtelConfig {
|
||||||
|
default_service_name: Cow::Borrowed("deno"),
|
||||||
|
default_service_version: Cow::Borrowed(crate::version::deno()),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
run_flags.script.as_bytes(),
|
run_flags.script.as_bytes(),
|
||||||
"run-eszip",
|
"run-eszip",
|
||||||
|
|
|
@ -31,6 +31,7 @@ use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||||
use deno_runtime::deno_web::BlobStore;
|
use deno_runtime::deno_web::BlobStore;
|
||||||
use deno_runtime::fmt_errors::format_js_error;
|
use deno_runtime::fmt_errors::format_js_error;
|
||||||
use deno_runtime::inspector_server::InspectorServer;
|
use deno_runtime::inspector_server::InspectorServer;
|
||||||
|
use deno_runtime::ops::otel::OtelConfig;
|
||||||
use deno_runtime::ops::worker_host::CreateWebWorkerCb;
|
use deno_runtime::ops::worker_host::CreateWebWorkerCb;
|
||||||
use deno_runtime::web_worker::WebWorker;
|
use deno_runtime::web_worker::WebWorker;
|
||||||
use deno_runtime::web_worker::WebWorkerOptions;
|
use deno_runtime::web_worker::WebWorkerOptions;
|
||||||
|
@ -143,6 +144,7 @@ struct SharedWorkerState {
|
||||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||||
serve_port: Option<u16>,
|
serve_port: Option<u16>,
|
||||||
serve_host: Option<String>,
|
serve_host: Option<String>,
|
||||||
|
otel_config: Option<OtelConfig>, // `None` means OpenTelemetry is disabled.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedWorkerState {
|
impl SharedWorkerState {
|
||||||
|
@ -417,6 +419,7 @@ impl CliMainWorkerFactory {
|
||||||
disable_deprecated_api_warning: bool,
|
disable_deprecated_api_warning: bool,
|
||||||
verbose_deprecated_api_warning: bool,
|
verbose_deprecated_api_warning: bool,
|
||||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||||
|
otel_config: Option<OtelConfig>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
shared: Arc::new(SharedWorkerState {
|
shared: Arc::new(SharedWorkerState {
|
||||||
|
@ -443,6 +446,7 @@ impl CliMainWorkerFactory {
|
||||||
disable_deprecated_api_warning,
|
disable_deprecated_api_warning,
|
||||||
verbose_deprecated_api_warning,
|
verbose_deprecated_api_warning,
|
||||||
code_cache,
|
code_cache,
|
||||||
|
otel_config,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,6 +589,7 @@ impl CliMainWorkerFactory {
|
||||||
mode,
|
mode,
|
||||||
serve_port: shared.serve_port,
|
serve_port: shared.serve_port,
|
||||||
serve_host: shared.serve_host.clone(),
|
serve_host: shared.serve_host.clone(),
|
||||||
|
otel_config: shared.otel_config.clone(),
|
||||||
},
|
},
|
||||||
extensions: custom_extensions,
|
extensions: custom_extensions,
|
||||||
startup_snapshot: crate::js::deno_isolate_init(),
|
startup_snapshot: crate::js::deno_isolate_init(),
|
||||||
|
@ -789,6 +794,7 @@ fn create_web_worker_callback(
|
||||||
mode,
|
mode,
|
||||||
serve_port: shared.serve_port,
|
serve_port: shared.serve_port,
|
||||||
serve_host: shared.serve_host.clone(),
|
serve_host: shared.serve_host.clone(),
|
||||||
|
otel_config: shared.otel_config.clone(),
|
||||||
},
|
},
|
||||||
extensions: vec![],
|
extensions: vec![],
|
||||||
startup_snapshot: crate::js::deno_isolate_init(),
|
startup_snapshot: crate::js::deno_isolate_init(),
|
||||||
|
|
|
@ -68,6 +68,7 @@ serde.workspace = true
|
||||||
winapi.workspace = true
|
winapi.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow.workspace = true
|
||||||
deno_ast.workspace = true
|
deno_ast.workspace = true
|
||||||
deno_broadcast_channel.workspace = true
|
deno_broadcast_channel.workspace = true
|
||||||
deno_cache.workspace = true
|
deno_cache.workspace = true
|
||||||
|
@ -105,11 +106,17 @@ hyper-util.workspace = true
|
||||||
hyper_v014 = { workspace = true, features = ["server", "stream", "http1", "http2", "runtime"] }
|
hyper_v014 = { workspace = true, features = ["server", "stream", "http1", "http2", "runtime"] }
|
||||||
libc.workspace = true
|
libc.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
maplit = "1.0.2"
|
||||||
netif = "0.1.6"
|
netif = "0.1.6"
|
||||||
notify.workspace = true
|
notify.workspace = true
|
||||||
once_cell.workspace = true
|
once_cell.workspace = true
|
||||||
|
opentelemetry = "0.24.0"
|
||||||
|
opentelemetry-otlp = { version = "0.17.0", default-features = false, features = ["logs", "http-proto", "reqwest-rustls-webpki-roots"] }
|
||||||
|
opentelemetry-semantic-conventions = "0.16.0"
|
||||||
|
opentelemetry_sdk = "0.24.1"
|
||||||
percent-encoding.workspace = true
|
percent-encoding.workspace = true
|
||||||
regex.workspace = true
|
regex.workspace = true
|
||||||
|
reqwest.workspace = true
|
||||||
rustyline = { workspace = true, features = ["custom-bindings"] }
|
rustyline = { workspace = true, features = ["custom-bindings"] }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
signal-hook = "0.3.17"
|
signal-hook = "0.3.17"
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
op_bootstrap_no_color,
|
op_bootstrap_no_color,
|
||||||
op_bootstrap_pid,
|
op_bootstrap_pid,
|
||||||
op_main_module,
|
op_main_module,
|
||||||
|
op_otel_log,
|
||||||
op_ppid,
|
op_ppid,
|
||||||
op_set_format_exception_callback,
|
op_set_format_exception_callback,
|
||||||
op_snapshot_options,
|
op_snapshot_options,
|
||||||
|
@ -61,6 +62,7 @@ import * as version from "ext:runtime/01_version.ts";
|
||||||
import * as os from "ext:runtime/30_os.js";
|
import * as os from "ext:runtime/30_os.js";
|
||||||
import * as timers from "ext:deno_web/02_timers.js";
|
import * as timers from "ext:deno_web/02_timers.js";
|
||||||
import {
|
import {
|
||||||
|
Console,
|
||||||
customInspect,
|
customInspect,
|
||||||
getDefaultInspectOptions,
|
getDefaultInspectOptions,
|
||||||
getStderrNoColor,
|
getStderrNoColor,
|
||||||
|
@ -710,6 +712,7 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) {
|
||||||
11: mode,
|
11: mode,
|
||||||
12: servePort,
|
12: servePort,
|
||||||
13: serveHost,
|
13: serveHost,
|
||||||
|
14: otelEnabled,
|
||||||
} = runtimeOptions;
|
} = runtimeOptions;
|
||||||
|
|
||||||
if (mode === executionModes.run || mode === executionModes.serve) {
|
if (mode === executionModes.run || mode === executionModes.serve) {
|
||||||
|
@ -796,6 +799,15 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) {
|
||||||
});
|
});
|
||||||
ObjectSetPrototypeOf(globalThis, Window.prototype);
|
ObjectSetPrototypeOf(globalThis, Window.prototype);
|
||||||
|
|
||||||
|
if (otelEnabled) {
|
||||||
|
const otelConsole = new Console(op_otel_log);
|
||||||
|
ObjectDefineProperty(
|
||||||
|
globalThis,
|
||||||
|
"console",
|
||||||
|
core.propNonEnumerable(otelConsole),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (inspectFlag) {
|
if (inspectFlag) {
|
||||||
const consoleFromDeno = globalThis.console;
|
const consoleFromDeno = globalThis.console;
|
||||||
core.wrapConsole(consoleFromDeno, core.v8Console);
|
core.wrapConsole(consoleFromDeno, core.v8Console);
|
||||||
|
@ -924,6 +936,10 @@ function bootstrapWorkerRuntime(
|
||||||
8: shouldDisableDeprecatedApiWarning,
|
8: shouldDisableDeprecatedApiWarning,
|
||||||
9: shouldUseVerboseDeprecatedApiWarning,
|
9: shouldUseVerboseDeprecatedApiWarning,
|
||||||
10: future,
|
10: future,
|
||||||
|
// 11: mode,
|
||||||
|
// 12: servePort,
|
||||||
|
// 13: serveHost,
|
||||||
|
14: otelEnabled,
|
||||||
} = runtimeOptions;
|
} = runtimeOptions;
|
||||||
|
|
||||||
// TODO(iuioiua): remove in Deno v2. This allows us to dynamically delete
|
// TODO(iuioiua): remove in Deno v2. This allows us to dynamically delete
|
||||||
|
@ -961,6 +977,15 @@ function bootstrapWorkerRuntime(
|
||||||
}
|
}
|
||||||
ObjectSetPrototypeOf(globalThis, DedicatedWorkerGlobalScope.prototype);
|
ObjectSetPrototypeOf(globalThis, DedicatedWorkerGlobalScope.prototype);
|
||||||
|
|
||||||
|
if (otelEnabled) {
|
||||||
|
const otelConsole = new Console(op_otel_log);
|
||||||
|
ObjectDefineProperty(
|
||||||
|
globalThis,
|
||||||
|
"console",
|
||||||
|
core.propNonEnumerable(otelConsole),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const consoleFromDeno = globalThis.console;
|
const consoleFromDeno = globalThis.console;
|
||||||
core.wrapConsole(consoleFromDeno, core.v8Console);
|
core.wrapConsole(consoleFromDeno, core.v8Console);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ pub mod bootstrap;
|
||||||
pub mod fs_events;
|
pub mod fs_events;
|
||||||
pub mod http;
|
pub mod http;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
|
pub mod otel;
|
||||||
pub mod permissions;
|
pub mod permissions;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
|
|
|
@ -174,6 +174,8 @@ fn op_get_exit_code(state: &mut OpState) -> i32 {
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
fn op_exit(state: &mut OpState) {
|
fn op_exit(state: &mut OpState) {
|
||||||
|
crate::ops::otel::otel_drop_logger(state);
|
||||||
|
|
||||||
let code = state.borrow::<ExitCode>().get();
|
let code = state.borrow::<ExitCode>().get();
|
||||||
std::process::exit(code)
|
std::process::exit(code)
|
||||||
}
|
}
|
||||||
|
|
308
runtime/ops/otel.rs
Normal file
308
runtime/ops/otel.rs
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use crate::tokio_util::create_basic_runtime;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use deno_core::futures::channel::mpsc;
|
||||||
|
use deno_core::futures::channel::mpsc::UnboundedSender;
|
||||||
|
use deno_core::futures::future::BoxFuture;
|
||||||
|
use deno_core::futures::stream;
|
||||||
|
use deno_core::futures::Stream;
|
||||||
|
use deno_core::futures::StreamExt;
|
||||||
|
use deno_core::op2;
|
||||||
|
use deno_core::OpState;
|
||||||
|
use maplit::hashmap;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use opentelemetry::logs::LogRecord;
|
||||||
|
use opentelemetry::logs::Logger as LoggerTrait;
|
||||||
|
use opentelemetry::logs::LoggerProvider;
|
||||||
|
use opentelemetry::logs::Severity;
|
||||||
|
use opentelemetry::Key;
|
||||||
|
use opentelemetry::KeyValue;
|
||||||
|
use opentelemetry_otlp::HttpExporterBuilder;
|
||||||
|
use opentelemetry_otlp::LogExporterBuilder;
|
||||||
|
use opentelemetry_sdk::logs::Logger;
|
||||||
|
use opentelemetry_sdk::Resource;
|
||||||
|
use opentelemetry_semantic_conventions::resource::SERVICE_NAME;
|
||||||
|
use opentelemetry_semantic_conventions::resource::SERVICE_VERSION;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::env;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::Context;
|
||||||
|
use std::task::Poll;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
deno_core::extension!(
|
||||||
|
deno_otel,
|
||||||
|
ops = [op_otel_log],
|
||||||
|
options = {
|
||||||
|
otel_config: Option<OtelConfig>, // `None` means OpenTelemetry is disabled.
|
||||||
|
},
|
||||||
|
state = |state, options| {
|
||||||
|
if let Some(otel_config) = options.otel_config {
|
||||||
|
let logger = otel_create_logger(otel_config)
|
||||||
|
.expect("Failed to create OpenTelemetry logger");
|
||||||
|
state.put::<Logger>(logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct OtelConfig {
|
||||||
|
pub default_service_name: Cow<'static, str>,
|
||||||
|
pub default_service_version: Cow<'static, str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OtelConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
default_service_name: Cow::Borrowed(env!("CARGO_PKG_NAME")),
|
||||||
|
default_service_version: Cow::Borrowed(env!("CARGO_PKG_VERSION")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OTEL_SHARED_RUNTIME_SPAWN_TASK_TX: Lazy<
|
||||||
|
UnboundedSender<BoxFuture<'static, ()>>,
|
||||||
|
> = Lazy::new(otel_create_shared_runtime);
|
||||||
|
|
||||||
|
fn otel_create_shared_runtime() -> UnboundedSender<BoxFuture<'static, ()>> {
|
||||||
|
let (spawn_task_tx, mut spawn_task_rx) =
|
||||||
|
mpsc::unbounded::<BoxFuture<'static, ()>>();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let rt = create_basic_runtime();
|
||||||
|
rt.block_on(async move {
|
||||||
|
while let Some(task) = spawn_task_rx.next().await {
|
||||||
|
tokio::spawn(task);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
spawn_task_tx
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct OtelSharedRuntime;
|
||||||
|
|
||||||
|
impl opentelemetry_sdk::runtime::Runtime for OtelSharedRuntime {
|
||||||
|
type Interval = Pin<Box<dyn Stream<Item = ()> + Send + 'static>>;
|
||||||
|
type Delay = Pin<Box<tokio::time::Sleep>>;
|
||||||
|
|
||||||
|
fn interval(&self, period: Duration) -> Self::Interval {
|
||||||
|
stream::repeat(())
|
||||||
|
.then(move |_| tokio::time::sleep(period))
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn(&self, future: BoxFuture<'static, ()>) {
|
||||||
|
(*OTEL_SHARED_RUNTIME_SPAWN_TASK_TX)
|
||||||
|
.unbounded_send(future)
|
||||||
|
.expect("failed to send task to shared OpenTelemetry runtime");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delay(&self, duration: Duration) -> Self::Delay {
|
||||||
|
Box::pin(tokio::time::sleep(duration))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl opentelemetry_sdk::runtime::RuntimeChannel for OtelSharedRuntime {
|
||||||
|
type Receiver<T: Debug + Send> = BatchMessageChannelReceiver<T>;
|
||||||
|
type Sender<T: Debug + Send> = BatchMessageChannelSender<T>;
|
||||||
|
|
||||||
|
fn batch_message_channel<T: Debug + Send>(
|
||||||
|
&self,
|
||||||
|
capacity: usize,
|
||||||
|
) -> (Self::Sender<T>, Self::Receiver<T>) {
|
||||||
|
let (batch_tx, batch_rx) = tokio::sync::mpsc::channel::<T>(capacity);
|
||||||
|
(batch_tx.into(), batch_rx.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BatchMessageChannelSender<T: Send> {
|
||||||
|
sender: tokio::sync::mpsc::Sender<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send> From<tokio::sync::mpsc::Sender<T>>
|
||||||
|
for BatchMessageChannelSender<T>
|
||||||
|
{
|
||||||
|
fn from(sender: tokio::sync::mpsc::Sender<T>) -> Self {
|
||||||
|
Self { sender }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send> opentelemetry_sdk::runtime::TrySend
|
||||||
|
for BatchMessageChannelSender<T>
|
||||||
|
{
|
||||||
|
type Message = T;
|
||||||
|
|
||||||
|
fn try_send(
|
||||||
|
&self,
|
||||||
|
item: Self::Message,
|
||||||
|
) -> Result<(), opentelemetry_sdk::runtime::TrySendError> {
|
||||||
|
self.sender.try_send(item).map_err(|err| match err {
|
||||||
|
tokio::sync::mpsc::error::TrySendError::Full(_) => {
|
||||||
|
opentelemetry_sdk::runtime::TrySendError::ChannelFull
|
||||||
|
}
|
||||||
|
tokio::sync::mpsc::error::TrySendError::Closed(_) => {
|
||||||
|
opentelemetry_sdk::runtime::TrySendError::ChannelClosed
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BatchMessageChannelReceiver<T> {
|
||||||
|
receiver: tokio::sync::mpsc::Receiver<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<tokio::sync::mpsc::Receiver<T>>
|
||||||
|
for BatchMessageChannelReceiver<T>
|
||||||
|
{
|
||||||
|
fn from(receiver: tokio::sync::mpsc::Receiver<T>) -> Self {
|
||||||
|
Self { receiver }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Stream for BatchMessageChannelReceiver<T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn poll_next(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Self::Item>> {
|
||||||
|
self.receiver.poll_recv(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn otel_create_logger(config: OtelConfig) -> anyhow::Result<Logger> {
|
||||||
|
// Parse the `OTEL_EXPORTER_OTLP_PROTOCOL` variable. The opentelemetry_*
|
||||||
|
// crates don't do this automatically. Currently, the only supported protocol
|
||||||
|
// is "http/protobuf".
|
||||||
|
// TODO(piscisaureus): enable GRPC support.
|
||||||
|
let _protocol = match env::var("OTEL_EXPORTER_OTLP_PROTOCOL").as_deref() {
|
||||||
|
Ok(protocol @ "http/protobuf") => protocol,
|
||||||
|
Ok("") | Err(env::VarError::NotPresent) => {
|
||||||
|
return Err(anyhow!("OTEL_EXPORTER_OTLP_PROTOCOL must be set",))
|
||||||
|
}
|
||||||
|
Ok(protocol) => {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an unsupported protocol: {}",
|
||||||
|
protocol
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL: {}",
|
||||||
|
err
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify that `OTEL_EXPORTER_OTLP_ENDPOINT` is set. If unspecified,
|
||||||
|
// `HttpExporterBuilder` will use http://localhost:4317 as the default
|
||||||
|
// endpoint, but this seems not very useful.
|
||||||
|
match env::var("OTEL_EXPORTER_OTLP_ENDPOINT").as_deref() {
|
||||||
|
Ok(endpoint) if !endpoint.is_empty() => {}
|
||||||
|
Ok(_) | Err(env::VarError::NotPresent) => {
|
||||||
|
return Err(anyhow!("OTEL_EXPORTER_OTLP_ENDPOINT must be set",))
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Failed to read env var OTEL_EXPORTER_OTLP_ENDPOINT: {}",
|
||||||
|
err
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The OTLP endpoint is automatically picked up from the
|
||||||
|
// `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable. Additional headers can
|
||||||
|
// be specified using `OTEL_EXPORTER_OTLP_HEADERS`.
|
||||||
|
let exporter = LogExporterBuilder::Http(
|
||||||
|
HttpExporterBuilder::default().with_http_client(reqwest::Client::new()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Define the resource attributes that will be attached to all log records.
|
||||||
|
// These attributes are sourced as follows (in order of precedence):
|
||||||
|
// * The `service.name` attribute from the `OTEL_SERVICE_NAME` env var.
|
||||||
|
// * Additional attributes from the `OTEL_RESOURCE_ATTRIBUTES` env var.
|
||||||
|
// * Default attribute values defined here.
|
||||||
|
// TODO(piscisaureus): add more default attributes (e.g. script path).
|
||||||
|
let mut resource = Resource::default();
|
||||||
|
// The default service name assigned by `Resource::default()`, if not
|
||||||
|
// otherwise specified via environment variables, is "unknown_service".
|
||||||
|
// Override this with the current crate name and version.
|
||||||
|
if resource
|
||||||
|
.get(Key::from_static_str(SERVICE_NAME))
|
||||||
|
.filter(|service_name| service_name.as_str() != "unknown_service")
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
resource = resource.merge(&Resource::new(
|
||||||
|
hashmap! {
|
||||||
|
SERVICE_NAME => config.default_service_name,
|
||||||
|
SERVICE_VERSION => config.default_service_version,
|
||||||
|
}
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| KeyValue::new(k, v)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
let logging_provider = opentelemetry_otlp::new_pipeline()
|
||||||
|
.logging()
|
||||||
|
.with_exporter(exporter)
|
||||||
|
.with_resource(resource)
|
||||||
|
.install_batch(OtelSharedRuntime)?;
|
||||||
|
|
||||||
|
// Create the `Logger` instance that will be used to emit console logs.
|
||||||
|
// The "console" argument is used to specify the `otel.scope.name` attribute,
|
||||||
|
// which is a standard attribute to instrumentation scope of log records.
|
||||||
|
let logger = logging_provider.logger_builder("console").build();
|
||||||
|
|
||||||
|
Ok(logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function is called by the runtime whenever it is about to call
|
||||||
|
/// `os::process::exit()`, to ensure that all OpenTelemetry logs are properly
|
||||||
|
/// flushed before the process terminates.
|
||||||
|
pub fn otel_drop_logger(state: &mut OpState) {
|
||||||
|
let Some(logger) = state.try_take::<Logger>() else {
|
||||||
|
// Since this function is called unconditionaly before `os::process::exit()`,
|
||||||
|
// it is not an error if the logger is not available.
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// When the `Logger` is dropped, the underlying `LoggerProvider` will be
|
||||||
|
// dropped as well. The provider's Drop implementation will flush all logs
|
||||||
|
// and block until the exporter has successfully sent them.
|
||||||
|
drop(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[op2(fast)]
|
||||||
|
fn op_otel_log(
|
||||||
|
state: &mut OpState,
|
||||||
|
#[string] message: String,
|
||||||
|
#[smi] level: i32,
|
||||||
|
) {
|
||||||
|
let Some(logger) = state.try_borrow::<Logger>() else {
|
||||||
|
log::error!("op_otel_log: OpenTelemetry Logger not available");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert the integer log level that ext/console uses to the corresponding
|
||||||
|
// OpenTelemetry log severity.
|
||||||
|
let severity = match level {
|
||||||
|
..=0 => Severity::Debug,
|
||||||
|
1 => Severity::Info,
|
||||||
|
2 => Severity::Warn,
|
||||||
|
3.. => Severity::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut log_record = logger.create_log_record();
|
||||||
|
log_record.set_body(message.into());
|
||||||
|
log_record.set_severity_number(severity);
|
||||||
|
log_record.set_severity_text(Cow::Borrowed(severity.name()));
|
||||||
|
logger.emit(log_record);
|
||||||
|
}
|
|
@ -263,6 +263,7 @@ pub fn create_runtime_snapshot(
|
||||||
),
|
),
|
||||||
ops::fs_events::deno_fs_events::init_ops(),
|
ops::fs_events::deno_fs_events::init_ops(),
|
||||||
ops::os::deno_os::init_ops(Default::default()),
|
ops::os::deno_os::init_ops(Default::default()),
|
||||||
|
ops::otel::deno_otel::init_ops(None),
|
||||||
ops::permissions::deno_permissions::init_ops(),
|
ops::permissions::deno_permissions::init_ops(),
|
||||||
ops::process::deno_process::init_ops(),
|
ops::process::deno_process::init_ops(),
|
||||||
ops::signal::deno_signal::init_ops(),
|
ops::signal::deno_signal::init_ops(),
|
||||||
|
|
|
@ -504,6 +504,7 @@ impl WebWorker {
|
||||||
),
|
),
|
||||||
ops::fs_events::deno_fs_events::init_ops_and_esm(),
|
ops::fs_events::deno_fs_events::init_ops_and_esm(),
|
||||||
ops::os::deno_os_worker::init_ops_and_esm(),
|
ops::os::deno_os_worker::init_ops_and_esm(),
|
||||||
|
ops::otel::deno_otel::init_ops_and_esm(options.bootstrap.otel_config),
|
||||||
ops::permissions::deno_permissions::init_ops_and_esm(),
|
ops::permissions::deno_permissions::init_ops_and_esm(),
|
||||||
ops::process::deno_process::init_ops_and_esm(),
|
ops::process::deno_process::init_ops_and_esm(),
|
||||||
ops::signal::deno_signal::init_ops_and_esm(),
|
ops::signal::deno_signal::init_ops_and_esm(),
|
||||||
|
|
|
@ -430,6 +430,7 @@ impl MainWorker {
|
||||||
),
|
),
|
||||||
ops::fs_events::deno_fs_events::init_ops_and_esm(),
|
ops::fs_events::deno_fs_events::init_ops_and_esm(),
|
||||||
ops::os::deno_os::init_ops_and_esm(exit_code.clone()),
|
ops::os::deno_os::init_ops_and_esm(exit_code.clone()),
|
||||||
|
ops::otel::deno_otel::init_ops_and_esm(options.bootstrap.otel_config),
|
||||||
ops::permissions::deno_permissions::init_ops_and_esm(),
|
ops::permissions::deno_permissions::init_ops_and_esm(),
|
||||||
ops::process::deno_process::init_ops_and_esm(),
|
ops::process::deno_process::init_ops_and_esm(),
|
||||||
ops::signal::deno_signal::init_ops_and_esm(),
|
ops::signal::deno_signal::init_ops_and_esm(),
|
||||||
|
|
|
@ -8,6 +8,8 @@ use std::thread;
|
||||||
|
|
||||||
use deno_terminal::colors;
|
use deno_terminal::colors;
|
||||||
|
|
||||||
|
use crate::ops::otel::OtelConfig;
|
||||||
|
|
||||||
/// The execution mode for this worker. Some modes may have implicit behaviour.
|
/// The execution mode for this worker. Some modes may have implicit behaviour.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -94,6 +96,8 @@ pub struct BootstrapOptions {
|
||||||
// Used by `deno serve`
|
// Used by `deno serve`
|
||||||
pub serve_port: Option<u16>,
|
pub serve_port: Option<u16>,
|
||||||
pub serve_host: Option<String>,
|
pub serve_host: Option<String>,
|
||||||
|
// OpenTelemetry output options. If `None`, OpenTelemetry is disabled.
|
||||||
|
pub otel_config: Option<OtelConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BootstrapOptions {
|
impl Default for BootstrapOptions {
|
||||||
|
@ -130,6 +134,7 @@ impl Default for BootstrapOptions {
|
||||||
mode: WorkerExecutionMode::None,
|
mode: WorkerExecutionMode::None,
|
||||||
serve_port: Default::default(),
|
serve_port: Default::default(),
|
||||||
serve_host: Default::default(),
|
serve_host: Default::default(),
|
||||||
|
otel_config: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,6 +178,8 @@ struct BootstrapV8<'a>(
|
||||||
u16,
|
u16,
|
||||||
// serve host
|
// serve host
|
||||||
Option<&'a str>,
|
Option<&'a str>,
|
||||||
|
// OTEL enabled
|
||||||
|
bool,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl BootstrapOptions {
|
impl BootstrapOptions {
|
||||||
|
@ -199,6 +206,7 @@ impl BootstrapOptions {
|
||||||
self.mode as u8 as _,
|
self.mode as u8 as _,
|
||||||
self.serve_port.unwrap_or_default(),
|
self.serve_port.unwrap_or_default(),
|
||||||
self.serve_host.as_deref(),
|
self.serve_host.as_deref(),
|
||||||
|
self.otel_config.is_some(),
|
||||||
);
|
);
|
||||||
|
|
||||||
bootstrap.serialize(ser).unwrap()
|
bootstrap.serialize(ser).unwrap()
|
||||||
|
|
Loading…
Reference in a new issue