Mnovich/otlp v2 (#3772)
This commit is contained in:
Generated
+245
-18
@@ -992,13 +992,40 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core 0.4.5",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"itoa",
|
||||
"matchit 0.7.3",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"sync_wrapper 1.0.2",
|
||||
"tower 0.5.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
|
||||
dependencies = [
|
||||
"axum-core",
|
||||
"axum-core 0.5.0",
|
||||
"axum-macros",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
@@ -1010,7 +1037,7 @@ dependencies = [
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"matchit 0.8.4",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
@@ -1030,6 +1057,26 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper 1.0.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.5.0"
|
||||
@@ -2695,7 +2742,7 @@ dependencies = [
|
||||
"futures",
|
||||
"hyper 0.14.32",
|
||||
"hyper-rustls 0.24.2",
|
||||
"hyper-timeout",
|
||||
"hyper-timeout 0.4.1",
|
||||
"log",
|
||||
"pin-project",
|
||||
"rand 0.8.5",
|
||||
@@ -3246,7 +3293,7 @@ dependencies = [
|
||||
"aws-sdk-bedrockruntime",
|
||||
"aws-sdk-sagemakerruntime",
|
||||
"aws-smithy-types",
|
||||
"axum",
|
||||
"axum 0.8.1",
|
||||
"base64 0.21.7",
|
||||
"blake3",
|
||||
"chrono",
|
||||
@@ -3271,6 +3318,9 @@ dependencies = [
|
||||
"mockall",
|
||||
"nanoid",
|
||||
"once_cell",
|
||||
"opentelemetry",
|
||||
"opentelemetry-otlp",
|
||||
"opentelemetry_sdk",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"reqwest 0.12.12",
|
||||
@@ -3289,7 +3339,9 @@ dependencies = [
|
||||
"tokio-cron-scheduler",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"tonic",
|
||||
"tracing",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"urlencoding",
|
||||
@@ -3329,7 +3381,7 @@ version = "1.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"axum 0.8.1",
|
||||
"base64 0.22.1",
|
||||
"bat",
|
||||
"chrono",
|
||||
@@ -3429,7 +3481,7 @@ version = "1.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"axum 0.8.1",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"chrono",
|
||||
@@ -3799,6 +3851,19 @@ dependencies = [
|
||||
"tokio-io-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-timeout"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
|
||||
dependencies = [
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.10"
|
||||
@@ -4391,7 +4456,7 @@ dependencies = [
|
||||
"object_store",
|
||||
"permutation",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"prost-build",
|
||||
"rand 0.8.5",
|
||||
"roaring",
|
||||
@@ -4450,7 +4515,7 @@ dependencies = [
|
||||
"num_cpus",
|
||||
"object_store",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"rand 0.8.5",
|
||||
"roaring",
|
||||
"serde_json",
|
||||
@@ -4484,7 +4549,7 @@ dependencies = [
|
||||
"lance-core",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"snafu",
|
||||
"tokio",
|
||||
]
|
||||
@@ -4518,7 +4583,7 @@ dependencies = [
|
||||
"log",
|
||||
"num-traits",
|
||||
"paste",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"prost-build",
|
||||
"prost-types",
|
||||
"rand 0.8.5",
|
||||
@@ -4555,7 +4620,7 @@ dependencies = [
|
||||
"log",
|
||||
"num-traits",
|
||||
"object_store",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"prost-build",
|
||||
"prost-types",
|
||||
"roaring",
|
||||
@@ -4603,7 +4668,7 @@ dependencies = [
|
||||
"moka",
|
||||
"num-traits",
|
||||
"object_store",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"prost-build",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
@@ -4649,7 +4714,7 @@ dependencies = [
|
||||
"object_store",
|
||||
"path_abs",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"prost-build",
|
||||
"rand 0.8.5",
|
||||
"shellexpand",
|
||||
@@ -4710,7 +4775,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"object_store",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"prost-build",
|
||||
"prost-types",
|
||||
"rand 0.8.5",
|
||||
@@ -5065,6 +5130,12 @@ dependencies = [
|
||||
"regex-automata 0.1.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.8.4"
|
||||
@@ -5087,7 +5158,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"axum 0.8.1",
|
||||
"base64 0.22.1",
|
||||
"eventsource-client",
|
||||
"futures",
|
||||
@@ -5754,6 +5825,87 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"js-sys",
|
||||
"pin-project-lite",
|
||||
"thiserror 1.0.69",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-http"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a8a7f5f6ba7c1b286c2fbca0454eaba116f63bbe69ed250b642d36fbb04d80"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"http 1.2.0",
|
||||
"opentelemetry",
|
||||
"reqwest 0.12.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-otlp"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-core",
|
||||
"http 1.2.0",
|
||||
"opentelemetry",
|
||||
"opentelemetry-http",
|
||||
"opentelemetry-proto",
|
||||
"opentelemetry_sdk",
|
||||
"prost 0.13.5",
|
||||
"reqwest 0.12.12",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-proto"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6"
|
||||
dependencies = [
|
||||
"opentelemetry",
|
||||
"opentelemetry_sdk",
|
||||
"prost 0.13.5",
|
||||
"tonic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry_sdk"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-channel",
|
||||
"futures-executor",
|
||||
"futures-util",
|
||||
"glob",
|
||||
"opentelemetry",
|
||||
"percent-encoding",
|
||||
"rand 0.8.5",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
@@ -6192,7 +6344,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
"prost-derive 0.12.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive 0.13.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6209,7 +6371,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"petgraph",
|
||||
"prettyplease",
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
"prost-types",
|
||||
"regex",
|
||||
"syn 2.0.99",
|
||||
@@ -6229,13 +6391,26 @@ dependencies = [
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.13.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.12.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0"
|
||||
dependencies = [
|
||||
"prost",
|
||||
"prost 0.12.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8335,6 +8510,36 @@ dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"axum 0.7.9",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"h2 0.4.8",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.6.0",
|
||||
"hyper-timeout 0.5.2",
|
||||
"hyper-util",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost 0.13.5",
|
||||
"socket2 0.5.8",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower 0.4.13",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
@@ -8343,9 +8548,13 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"indexmap 1.9.3",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"rand 0.8.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -8460,6 +8669,24 @@ dependencies = [
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-opentelemetry"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97a971f6058498b5c0f1affa23e7ea202057a7301dbff68e968b2d578bcbd053"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"opentelemetry",
|
||||
"opentelemetry_sdk",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-serde"
|
||||
version = "0.2.0"
|
||||
|
||||
@@ -701,6 +701,28 @@ pub async fn cli() -> Result<()> {
|
||||
eprintln!("Warning: Failed to update project tracker: {}", e);
|
||||
}
|
||||
|
||||
let command_name = match &cli.command {
|
||||
Some(Command::Configure {}) => "configure",
|
||||
Some(Command::Info { .. }) => "info",
|
||||
Some(Command::Mcp { .. }) => "mcp",
|
||||
Some(Command::Session { .. }) => "session",
|
||||
Some(Command::Project {}) => "project",
|
||||
Some(Command::Projects) => "projects",
|
||||
Some(Command::Run { .. }) => "run",
|
||||
Some(Command::Schedule { .. }) => "schedule",
|
||||
Some(Command::Update { .. }) => "update",
|
||||
Some(Command::Bench { .. }) => "bench",
|
||||
Some(Command::Recipe { .. }) => "recipe",
|
||||
Some(Command::Web { .. }) => "web",
|
||||
None => "default_session",
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
monotonic_counter.goose.cli_commands = 1,
|
||||
command = command_name,
|
||||
"CLI command executed"
|
||||
);
|
||||
|
||||
match cli.command {
|
||||
Some(Command::Configure {}) => {
|
||||
let _ = handle_configure().await;
|
||||
@@ -875,6 +897,11 @@ pub async fn cli() -> Result<()> {
|
||||
(input_config, None)
|
||||
}
|
||||
(_, _, Some(recipe_name)) => {
|
||||
tracing::info!(monotonic_counter.goose.recipe_runs = 1,
|
||||
recipe_name = %recipe_name,
|
||||
"Recipe execution started"
|
||||
);
|
||||
|
||||
if explain {
|
||||
explain_recipe(&recipe_name, params)?;
|
||||
return Ok(());
|
||||
|
||||
@@ -11,7 +11,7 @@ use tracing_subscriber::{
|
||||
Registry,
|
||||
};
|
||||
|
||||
use goose::tracing::langfuse_layer;
|
||||
use goose::tracing::{langfuse_layer, otlp_layer};
|
||||
use goose_bench::bench_session::BenchAgentError;
|
||||
use goose_bench::error_capture::ErrorCaptureLayer;
|
||||
|
||||
@@ -140,7 +140,21 @@ fn setup_logging_internal(
|
||||
layers.push(ErrorCaptureLayer::new().boxed());
|
||||
}
|
||||
|
||||
// Add Langfuse layer if available
|
||||
if !force {
|
||||
if let Ok((otlp_tracing_layer, otlp_metrics_layer)) = otlp_layer::init_otlp() {
|
||||
layers.push(
|
||||
otlp_tracing_layer
|
||||
.with_filter(otlp_layer::create_otlp_tracing_filter())
|
||||
.boxed(),
|
||||
);
|
||||
layers.push(
|
||||
otlp_metrics_layer
|
||||
.with_filter(otlp_layer::create_otlp_metrics_filter())
|
||||
.boxed(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(langfuse) = langfuse_layer::create_langfuse_observer() {
|
||||
layers.push(langfuse.with_filter(LevelFilter::DEBUG).boxed());
|
||||
}
|
||||
|
||||
@@ -1009,6 +1009,17 @@ impl Session {
|
||||
}
|
||||
// otherwise we have a model/tool to render
|
||||
else {
|
||||
for content in &message.content {
|
||||
if let MessageContent::ToolRequest(tool_request) = content {
|
||||
if let Ok(tool_call) = &tool_request.tool_call {
|
||||
tracing::info!(monotonic_counter.goose.tool_calls = 1,
|
||||
tool_name = %tool_call.name,
|
||||
"Tool call executed"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
push_message(&mut self.messages, message.clone());
|
||||
|
||||
// No need to update description on assistant messages
|
||||
|
||||
@@ -9,7 +9,7 @@ use tracing_subscriber::{
|
||||
};
|
||||
|
||||
use goose::config::APP_STRATEGY;
|
||||
use goose::tracing::langfuse_layer;
|
||||
use goose::tracing::{langfuse_layer, otlp_layer};
|
||||
|
||||
/// Returns the directory where log files should be stored.
|
||||
/// Creates the directory structure if it doesn't exist.
|
||||
@@ -91,22 +91,33 @@ pub fn setup_logging(name: Option<&str>) -> Result<()> {
|
||||
.add_directive(LevelFilter::WARN.into())
|
||||
});
|
||||
|
||||
// Build the subscriber with required layers
|
||||
let subscriber = Registry::default()
|
||||
.with(file_layer.with_filter(env_filter))
|
||||
.with(console_layer.with_filter(LevelFilter::INFO));
|
||||
let mut layers = vec![
|
||||
file_layer.with_filter(env_filter).boxed(),
|
||||
console_layer.with_filter(LevelFilter::INFO).boxed(),
|
||||
];
|
||||
|
||||
// Initialize with Langfuse if available
|
||||
if let Some(langfuse) = langfuse_layer::create_langfuse_observer() {
|
||||
subscriber
|
||||
.with(langfuse.with_filter(LevelFilter::DEBUG))
|
||||
.try_init()
|
||||
.context("Failed to set global subscriber")?;
|
||||
} else {
|
||||
subscriber
|
||||
.try_init()
|
||||
.context("Failed to set global subscriber")?;
|
||||
if let Ok((otlp_tracing_layer, otlp_metrics_layer)) = otlp_layer::init_otlp() {
|
||||
layers.push(
|
||||
otlp_tracing_layer
|
||||
.with_filter(otlp_layer::create_otlp_tracing_filter())
|
||||
.boxed(),
|
||||
);
|
||||
layers.push(
|
||||
otlp_metrics_layer
|
||||
.with_filter(otlp_layer::create_otlp_metrics_filter())
|
||||
.boxed(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(langfuse) = langfuse_layer::create_langfuse_observer() {
|
||||
layers.push(langfuse.with_filter(LevelFilter::DEBUG).boxed());
|
||||
}
|
||||
|
||||
let subscriber = Registry::default().with(layers);
|
||||
|
||||
subscriber
|
||||
.try_init()
|
||||
.context("Failed to set global subscriber")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -58,6 +58,11 @@ webbrowser = "0.8"
|
||||
lazy_static = "1.5.0"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
tracing-opentelemetry = "0.28"
|
||||
opentelemetry = "0.27"
|
||||
opentelemetry_sdk = { version = "0.27", features = ["rt-tokio", "metrics"] }
|
||||
opentelemetry-otlp = { version = "0.27", features = ["grpc-tonic", "http-proto", "reqwest-client"] }
|
||||
tonic = "0.12"
|
||||
keyring = { version = "3.6.2", features = ["apple-native", "windows-native", "sync-secret-service", "vendored"] }
|
||||
serde_yaml = "0.9.34"
|
||||
once_cell = "1.20.2"
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
pub mod langfuse_layer;
|
||||
mod observation_layer;
|
||||
pub mod otlp_layer;
|
||||
|
||||
pub use langfuse_layer::{create_langfuse_observer, LangfuseBatchManager};
|
||||
pub use observation_layer::{
|
||||
flatten_metadata, map_level, BatchManager, ObservationLayer, SpanData, SpanTracker,
|
||||
};
|
||||
pub use otlp_layer::{
|
||||
create_otlp_metrics_filter, create_otlp_tracing_filter, create_otlp_tracing_layer,
|
||||
init_otlp_metrics, init_otlp_tracing, init_otlp_tracing_only, shutdown_otlp, OtlpConfig,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
use opentelemetry::trace::TracerProvider;
|
||||
use opentelemetry::{global, KeyValue};
|
||||
use opentelemetry_otlp::WithExportConfig;
|
||||
use opentelemetry_sdk::trace::{self, RandomIdGenerator, Sampler};
|
||||
use opentelemetry_sdk::{runtime, Resource};
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
use tracing::{Level, Metadata};
|
||||
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
|
||||
use tracing_subscriber::filter::FilterFn;
|
||||
|
||||
pub type OtlpTracingLayer =
|
||||
OpenTelemetryLayer<tracing_subscriber::Registry, opentelemetry_sdk::trace::Tracer>;
|
||||
pub type OtlpMetricsLayer = MetricsLayer<tracing_subscriber::Registry>;
|
||||
pub type OtlpLayers = (OtlpTracingLayer, OtlpMetricsLayer);
|
||||
pub type OtlpResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OtlpConfig {
|
||||
pub endpoint: String,
|
||||
pub timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for OtlpConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
endpoint: "http://localhost:4318".to_string(),
|
||||
timeout: Duration::from_secs(10),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OtlpConfig {
|
||||
pub fn from_env() -> Option<Self> {
|
||||
if let Ok(endpoint) = env::var("OTEL_EXPORTER_OTLP_ENDPOINT") {
|
||||
let mut config = Self {
|
||||
endpoint,
|
||||
timeout: Duration::from_secs(10),
|
||||
};
|
||||
|
||||
if let Ok(timeout_str) = env::var("OTEL_EXPORTER_OTLP_TIMEOUT") {
|
||||
if let Ok(timeout_ms) = timeout_str.parse::<u64>() {
|
||||
config.timeout = Duration::from_millis(timeout_ms);
|
||||
}
|
||||
}
|
||||
|
||||
Some(config)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_otlp_tracing(config: &OtlpConfig) -> OtlpResult<()> {
|
||||
let resource = Resource::new(vec![
|
||||
KeyValue::new("service.name", "goose"),
|
||||
KeyValue::new("service.version", env!("CARGO_PKG_VERSION")),
|
||||
KeyValue::new("service.namespace", "goose"),
|
||||
]);
|
||||
|
||||
let exporter = opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_http()
|
||||
.with_endpoint(&config.endpoint)
|
||||
.with_timeout(config.timeout)
|
||||
.build()?;
|
||||
|
||||
let tracer_provider = trace::TracerProvider::builder()
|
||||
.with_batch_exporter(exporter, runtime::Tokio)
|
||||
.with_resource(resource.clone())
|
||||
.with_id_generator(RandomIdGenerator::default())
|
||||
.with_sampler(Sampler::AlwaysOn)
|
||||
.build();
|
||||
|
||||
global::set_tracer_provider(tracer_provider);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init_otlp_metrics(config: &OtlpConfig) -> OtlpResult<()> {
|
||||
let resource = Resource::new(vec![
|
||||
KeyValue::new("service.name", "goose"),
|
||||
KeyValue::new("service.version", env!("CARGO_PKG_VERSION")),
|
||||
KeyValue::new("service.namespace", "goose"),
|
||||
]);
|
||||
|
||||
let exporter = opentelemetry_otlp::MetricExporter::builder()
|
||||
.with_http()
|
||||
.with_endpoint(&config.endpoint)
|
||||
.with_timeout(config.timeout)
|
||||
.build()?;
|
||||
|
||||
let meter_provider = opentelemetry_sdk::metrics::SdkMeterProvider::builder()
|
||||
.with_resource(resource)
|
||||
.with_reader(
|
||||
opentelemetry_sdk::metrics::PeriodicReader::builder(exporter, runtime::Tokio)
|
||||
.with_interval(Duration::from_secs(3))
|
||||
.build(),
|
||||
)
|
||||
.build();
|
||||
|
||||
global::set_meter_provider(meter_provider);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_otlp_tracing_layer() -> OtlpResult<OtlpTracingLayer> {
|
||||
let config =
|
||||
OtlpConfig::from_env().ok_or("OTEL_EXPORTER_OTLP_ENDPOINT environment variable not set")?;
|
||||
|
||||
let resource = Resource::new(vec![
|
||||
KeyValue::new("service.name", "goose"),
|
||||
KeyValue::new("service.version", env!("CARGO_PKG_VERSION")),
|
||||
KeyValue::new("service.namespace", "goose"),
|
||||
]);
|
||||
|
||||
let exporter = opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_http()
|
||||
.with_endpoint(&config.endpoint)
|
||||
.with_timeout(config.timeout)
|
||||
.build()?;
|
||||
|
||||
let tracer_provider = trace::TracerProvider::builder()
|
||||
.with_batch_exporter(exporter, runtime::Tokio)
|
||||
.with_resource(resource)
|
||||
.with_id_generator(RandomIdGenerator::default())
|
||||
.with_sampler(Sampler::AlwaysOn)
|
||||
.build();
|
||||
|
||||
let tracer = tracer_provider.tracer("goose");
|
||||
Ok(tracing_opentelemetry::layer().with_tracer(tracer))
|
||||
}
|
||||
|
||||
pub fn create_otlp_metrics_layer() -> OtlpResult<OtlpMetricsLayer> {
|
||||
let config =
|
||||
OtlpConfig::from_env().ok_or("OTEL_EXPORTER_OTLP_ENDPOINT environment variable not set")?;
|
||||
|
||||
let resource = Resource::new(vec![
|
||||
KeyValue::new("service.name", "goose"),
|
||||
KeyValue::new("service.version", env!("CARGO_PKG_VERSION")),
|
||||
KeyValue::new("service.namespace", "goose"),
|
||||
]);
|
||||
|
||||
let exporter = opentelemetry_otlp::MetricExporter::builder()
|
||||
.with_http()
|
||||
.with_endpoint(&config.endpoint)
|
||||
.with_timeout(config.timeout)
|
||||
.build()?;
|
||||
|
||||
let meter_provider = opentelemetry_sdk::metrics::SdkMeterProvider::builder()
|
||||
.with_resource(resource)
|
||||
.with_reader(
|
||||
opentelemetry_sdk::metrics::PeriodicReader::builder(exporter, runtime::Tokio)
|
||||
.with_interval(Duration::from_secs(5)) // Reduced from 30s to 5s for faster metrics
|
||||
.build(),
|
||||
)
|
||||
.build();
|
||||
|
||||
global::set_meter_provider(meter_provider.clone());
|
||||
|
||||
Ok(tracing_opentelemetry::MetricsLayer::new(meter_provider))
|
||||
}
|
||||
|
||||
pub fn init_otlp() -> OtlpResult<OtlpLayers> {
|
||||
let tracing_layer = create_otlp_tracing_layer()?;
|
||||
let metrics_layer = create_otlp_metrics_layer()?;
|
||||
Ok((tracing_layer, metrics_layer))
|
||||
}
|
||||
|
||||
pub fn init_otlp_tracing_only() -> OtlpResult<OtlpTracingLayer> {
|
||||
create_otlp_tracing_layer()
|
||||
}
|
||||
|
||||
/// Creates a custom filter for OTLP tracing that captures:
|
||||
/// - All spans at INFO level and above
|
||||
/// - Specific spans marked with "otel.trace" field
|
||||
/// - Events from specific modules related to telemetry
|
||||
pub fn create_otlp_tracing_filter() -> FilterFn<impl Fn(&Metadata<'_>) -> bool> {
|
||||
FilterFn::new(|metadata: &Metadata<'_>| {
|
||||
if metadata.level() <= &Level::INFO {
|
||||
return true;
|
||||
}
|
||||
|
||||
if metadata.level() == &Level::DEBUG {
|
||||
let target = metadata.target();
|
||||
if target.starts_with("goose::")
|
||||
|| target.starts_with("opentelemetry")
|
||||
|| target.starts_with("tracing_opentelemetry")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a custom filter for OTLP metrics that captures:
|
||||
/// - All events at INFO level and above
|
||||
/// - Specific events marked with "otel.metric" field
|
||||
/// - Events that should be converted to metrics
|
||||
pub fn create_otlp_metrics_filter() -> FilterFn<impl Fn(&Metadata<'_>) -> bool> {
|
||||
FilterFn::new(|metadata: &Metadata<'_>| {
|
||||
if metadata.level() <= &Level::INFO {
|
||||
return true;
|
||||
}
|
||||
|
||||
if metadata.level() == &Level::DEBUG {
|
||||
let target = metadata.target();
|
||||
if target.starts_with("goose::telemetry")
|
||||
|| target.starts_with("goose::metrics")
|
||||
|| target.contains("metric")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
})
|
||||
}
|
||||
|
||||
/// Shutdown OTLP providers gracefully
|
||||
pub fn shutdown_otlp() {
|
||||
global::shutdown_tracer_provider();
|
||||
|
||||
// Note: There's currently no clean way to shutdown the global meter provider
|
||||
// in the OpenTelemetry Rust SDK. The meter provider will be cleaned up when
|
||||
// the process exits. Individual meter providers can be shut down if you have
|
||||
// a direct reference to them.
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::env;
|
||||
|
||||
#[test]
|
||||
fn test_otlp_config_default() {
|
||||
let config = OtlpConfig::default();
|
||||
assert_eq!(config.endpoint, "http://localhost:4318");
|
||||
assert_eq!(config.timeout, Duration::from_secs(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_otlp_config_from_env() {
|
||||
let original_endpoint = env::var("OTEL_EXPORTER_OTLP_ENDPOINT").ok();
|
||||
let original_timeout = env::var("OTEL_EXPORTER_OTLP_TIMEOUT").ok();
|
||||
|
||||
env::remove_var("OTEL_EXPORTER_OTLP_ENDPOINT");
|
||||
assert!(OtlpConfig::from_env().is_none());
|
||||
|
||||
env::set_var("OTEL_EXPORTER_OTLP_ENDPOINT", "http://test:4317");
|
||||
env::set_var("OTEL_EXPORTER_OTLP_TIMEOUT", "5000");
|
||||
|
||||
let config = OtlpConfig::from_env().unwrap();
|
||||
assert_eq!(config.endpoint, "http://test:4317");
|
||||
assert_eq!(config.timeout, Duration::from_millis(5000));
|
||||
|
||||
match original_endpoint {
|
||||
Some(val) => env::set_var("OTEL_EXPORTER_OTLP_ENDPOINT", val),
|
||||
None => env::remove_var("OTEL_EXPORTER_OTLP_ENDPOINT"),
|
||||
}
|
||||
match original_timeout {
|
||||
Some(val) => env::set_var("OTEL_EXPORTER_OTLP_TIMEOUT", val),
|
||||
None => env::remove_var("OTEL_EXPORTER_OTLP_TIMEOUT"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user