mirror of
https://github.com/katanemo/plano.git
synced 2026-05-11 16:52:41 +02:00
cargo clippy (#660)
This commit is contained in:
parent
c75e7606f9
commit
ca95ffb63d
62 changed files with 1864 additions and 1187 deletions
|
|
@ -1,5 +1,5 @@
|
|||
use super::shapes::Span;
|
||||
use super::resource_span_builder::ResourceSpanBuilder;
|
||||
use super::shapes::Span;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
|
@ -160,7 +160,11 @@ impl TraceCollector {
|
|||
}
|
||||
|
||||
let total_spans: usize = service_batches.iter().map(|(_, spans)| spans.len()).sum();
|
||||
debug!("Flushing {} spans across {} services to OTEL collector", total_spans, service_batches.len());
|
||||
debug!(
|
||||
"Flushing {} spans across {} services to OTEL collector",
|
||||
total_spans,
|
||||
service_batches.len()
|
||||
);
|
||||
|
||||
// Build canonical OTEL payload structure - one ResourceSpan per service
|
||||
let resource_spans = self.build_resource_spans(service_batches);
|
||||
|
|
@ -178,7 +182,10 @@ impl TraceCollector {
|
|||
}
|
||||
|
||||
/// Build OTEL-compliant resource spans from collected spans, one ResourceSpan per service
|
||||
fn build_resource_spans(&self, service_batches: Vec<(String, Vec<Span>)>) -> Vec<super::shapes::ResourceSpan> {
|
||||
fn build_resource_spans(
|
||||
&self,
|
||||
service_batches: Vec<(String, Vec<Span>)>,
|
||||
) -> Vec<super::shapes::ResourceSpan> {
|
||||
service_batches
|
||||
.into_iter()
|
||||
.map(|(service_name, spans)| {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
/// OpenTelemetry semantic convention constants for tracing
|
||||
///
|
||||
/// These constants ensure consistency across the codebase and prevent typos
|
||||
|
||||
/// Resource attribute keys following OTEL semantic conventions
|
||||
pub mod resource {
|
||||
/// Logical name of the service
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
// Original tracing types (OTEL structures)
|
||||
mod shapes;
|
||||
// New tracing utilities
|
||||
mod span_builder;
|
||||
mod resource_span_builder;
|
||||
mod constants;
|
||||
mod resource_span_builder;
|
||||
mod span_builder;
|
||||
|
||||
#[cfg(feature = "trace-collection")]
|
||||
mod collector;
|
||||
|
|
@ -13,14 +13,14 @@ mod tests;
|
|||
|
||||
// Re-export original types
|
||||
pub use shapes::{
|
||||
Span, Event, Traceparent, TraceparentNewError,
|
||||
ResourceSpan, Resource, ScopeSpan, Scope, Attribute, AttributeValue,
|
||||
Attribute, AttributeValue, Event, Resource, ResourceSpan, Scope, ScopeSpan, Span, Traceparent,
|
||||
TraceparentNewError,
|
||||
};
|
||||
|
||||
// Re-export new utilities
|
||||
pub use span_builder::{SpanBuilder, SpanKind, generate_random_span_id};
|
||||
pub use resource_span_builder::ResourceSpanBuilder;
|
||||
pub use constants::*;
|
||||
pub use resource_span_builder::ResourceSpanBuilder;
|
||||
pub use span_builder::{generate_random_span_id, SpanBuilder, SpanKind};
|
||||
|
||||
#[cfg(feature = "trace-collection")]
|
||||
pub use collector::{TraceCollector, parse_traceparent};
|
||||
pub use collector::{parse_traceparent, TraceCollector};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use super::shapes::{ResourceSpan, Resource, ScopeSpan, Scope, Span, Attribute, AttributeValue};
|
||||
use super::constants::{resource, scope};
|
||||
use super::shapes::{Attribute, AttributeValue, Resource, ResourceSpan, Scope, ScopeSpan, Span};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Builder for creating OTEL ResourceSpan structures
|
||||
|
|
@ -26,7 +26,11 @@ impl ResourceSpanBuilder {
|
|||
}
|
||||
|
||||
/// Add a resource attribute (e.g., deployment.environment, host.name)
|
||||
pub fn with_resource_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
|
||||
pub fn with_resource_attribute(
|
||||
mut self,
|
||||
key: impl Into<String>,
|
||||
value: impl Into<String>,
|
||||
) -> Self {
|
||||
self.resource_attributes.insert(key.into(), value.into());
|
||||
self
|
||||
}
|
||||
|
|
@ -58,14 +62,12 @@ impl ResourceSpanBuilder {
|
|||
/// Build the ResourceSpan
|
||||
pub fn build(self) -> ResourceSpan {
|
||||
// Build resource attributes
|
||||
let mut attributes = vec![
|
||||
Attribute {
|
||||
key: resource::SERVICE_NAME.to_string(),
|
||||
value: AttributeValue {
|
||||
string_value: Some(self.service_name),
|
||||
},
|
||||
}
|
||||
];
|
||||
let mut attributes = vec![Attribute {
|
||||
key: resource::SERVICE_NAME.to_string(),
|
||||
value: AttributeValue {
|
||||
string_value: Some(self.service_name),
|
||||
},
|
||||
}];
|
||||
|
||||
// Add custom resource attributes
|
||||
for (key, value) in self.resource_attributes {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::shapes::{Span, Attribute, AttributeValue};
|
||||
use super::shapes::{Attribute, AttributeValue, Span};
|
||||
use std::collections::HashMap;
|
||||
use std::time::SystemTime;
|
||||
|
||||
|
|
@ -116,10 +116,11 @@ impl SpanBuilder {
|
|||
let end_nanos = system_time_to_nanos(end_time);
|
||||
|
||||
// Generate trace_id if not provided
|
||||
let trace_id = self.trace_id.unwrap_or_else(|| generate_random_trace_id());
|
||||
let trace_id = self.trace_id.unwrap_or_else(generate_random_trace_id);
|
||||
|
||||
// Create attributes in OTEL format
|
||||
let attributes: Vec<Attribute> = self.attributes
|
||||
let attributes: Vec<Attribute> = self
|
||||
.attributes
|
||||
.into_iter()
|
||||
.map(|(key, value)| Attribute {
|
||||
key,
|
||||
|
|
@ -132,7 +133,7 @@ impl SpanBuilder {
|
|||
// Build span directly without going through Span::new()
|
||||
Span {
|
||||
trace_id,
|
||||
span_id: self.span_id.unwrap_or_else(|| generate_random_span_id()),
|
||||
span_id: self.span_id.unwrap_or_else(generate_random_span_id),
|
||||
parent_span_id: self.parent_span_id,
|
||||
name: self.name,
|
||||
start_time_unix_nano: format!("{}", start_nanos),
|
||||
|
|
|
|||
|
|
@ -21,10 +21,7 @@ use tokio::sync::RwLock;
|
|||
type SharedTraces = Arc<RwLock<Vec<Value>>>;
|
||||
|
||||
/// POST /v1/traces - capture incoming OTLP payload
|
||||
async fn post_traces(
|
||||
State(traces): State<SharedTraces>,
|
||||
Json(payload): Json<Value>,
|
||||
) -> StatusCode {
|
||||
async fn post_traces(State(traces): State<SharedTraces>, Json(payload): Json<Value>) -> StatusCode {
|
||||
traces.write().await.push(payload);
|
||||
StatusCode::OK
|
||||
}
|
||||
|
|
@ -67,9 +64,7 @@ impl MockOtelCollector {
|
|||
let address = format!("http://127.0.0.1:{}", addr.port());
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
axum::serve(listener, app)
|
||||
.await
|
||||
.expect("Server failed");
|
||||
axum::serve(listener, app).await.expect("Server failed");
|
||||
});
|
||||
|
||||
// Give server a moment to start
|
||||
|
|
|
|||
|
|
@ -36,9 +36,12 @@ fn extract_spans(payloads: &[Value]) -> Vec<&Value> {
|
|||
for payload in payloads {
|
||||
if let Some(resource_spans) = payload.get("resourceSpans").and_then(|v| v.as_array()) {
|
||||
for resource_span in resource_spans {
|
||||
if let Some(scope_spans) = resource_span.get("scopeSpans").and_then(|v| v.as_array()) {
|
||||
if let Some(scope_spans) =
|
||||
resource_span.get("scopeSpans").and_then(|v| v.as_array())
|
||||
{
|
||||
for scope_span in scope_spans {
|
||||
if let Some(span_list) = scope_span.get("spans").and_then(|v| v.as_array()) {
|
||||
if let Some(span_list) = scope_span.get("spans").and_then(|v| v.as_array())
|
||||
{
|
||||
spans.extend(span_list.iter());
|
||||
}
|
||||
}
|
||||
|
|
@ -54,9 +57,9 @@ fn get_string_attr<'a>(span: &'a Value, key: &str) -> Option<&'a str> {
|
|||
span.get("attributes")
|
||||
.and_then(|attrs| attrs.as_array())
|
||||
.and_then(|attrs| {
|
||||
attrs.iter().find(|attr| {
|
||||
attr.get("key").and_then(|k| k.as_str()) == Some(key)
|
||||
})
|
||||
attrs
|
||||
.iter()
|
||||
.find(|attr| attr.get("key").and_then(|k| k.as_str()) == Some(key))
|
||||
})
|
||||
.and_then(|attr| attr.get("value"))
|
||||
.and_then(|v| v.get("stringValue"))
|
||||
|
|
@ -70,7 +73,10 @@ async fn test_llm_span_contains_basic_attributes() {
|
|||
let mock_collector = MockOtelCollector::start().await;
|
||||
|
||||
// Create TraceCollector pointing to mock with 500ms flush intervalc
|
||||
std::env::set_var("OTEL_COLLECTOR_URL", format!("{}/v1/traces", mock_collector.address()));
|
||||
std::env::set_var(
|
||||
"OTEL_COLLECTOR_URL",
|
||||
format!("{}/v1/traces", mock_collector.address()),
|
||||
);
|
||||
std::env::set_var("OTEL_TRACING_ENABLED", "true");
|
||||
std::env::set_var("TRACE_FLUSH_INTERVAL_MS", "500");
|
||||
let trace_collector = Arc::new(TraceCollector::new(Some(true)));
|
||||
|
|
@ -102,7 +108,10 @@ async fn test_llm_span_contains_basic_attributes() {
|
|||
let span = spans[0];
|
||||
// Validate HTTP attributes
|
||||
assert_eq!(get_string_attr(span, "http.method"), Some("POST"));
|
||||
assert_eq!(get_string_attr(span, "http.target"), Some("/v1/chat/completions"));
|
||||
assert_eq!(
|
||||
get_string_attr(span, "http.target"),
|
||||
Some("/v1/chat/completions")
|
||||
);
|
||||
|
||||
// Validate LLM attributes
|
||||
assert_eq!(get_string_attr(span, "llm.model"), Some("gpt-4o"));
|
||||
|
|
@ -115,7 +124,10 @@ async fn test_llm_span_contains_basic_attributes() {
|
|||
#[serial]
|
||||
async fn test_llm_span_contains_tool_information() {
|
||||
let mock_collector = MockOtelCollector::start().await;
|
||||
std::env::set_var("OTEL_COLLECTOR_URL", format!("{}/v1/traces", mock_collector.address()));
|
||||
std::env::set_var(
|
||||
"OTEL_COLLECTOR_URL",
|
||||
format!("{}/v1/traces", mock_collector.address()),
|
||||
);
|
||||
std::env::set_var("OTEL_TRACING_ENABLED", "true");
|
||||
std::env::set_var("TRACE_FLUSH_INTERVAL_MS", "500");
|
||||
let trace_collector = Arc::new(TraceCollector::new(Some(true)));
|
||||
|
|
@ -144,19 +156,26 @@ async fn test_llm_span_contains_tool_information() {
|
|||
assert!(tools.unwrap().contains("get_weather(...)"));
|
||||
assert!(tools.unwrap().contains("search_web(...)"));
|
||||
assert!(tools.unwrap().contains("calculate(...)"));
|
||||
assert!(tools.unwrap().contains('\n'), "Tools should be newline-separated");
|
||||
assert!(
|
||||
tools.unwrap().contains('\n'),
|
||||
"Tools should be newline-separated"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_llm_span_contains_user_message_preview() {
|
||||
let mock_collector = MockOtelCollector::start().await;
|
||||
std::env::set_var("OTEL_COLLECTOR_URL", format!("{}/v1/traces", mock_collector.address()));
|
||||
std::env::set_var(
|
||||
"OTEL_COLLECTOR_URL",
|
||||
format!("{}/v1/traces", mock_collector.address()),
|
||||
);
|
||||
std::env::set_var("OTEL_TRACING_ENABLED", "true");
|
||||
std::env::set_var("TRACE_FLUSH_INTERVAL_MS", "500");
|
||||
let trace_collector = Arc::new(TraceCollector::new(Some(true)));
|
||||
|
||||
let long_message = "This is a very long user message that should be truncated to 50 characters in the span";
|
||||
let long_message =
|
||||
"This is a very long user message that should be truncated to 50 characters in the span";
|
||||
let preview = if long_message.len() > 50 {
|
||||
format!("{}...", &long_message[..50])
|
||||
} else {
|
||||
|
|
@ -187,7 +206,10 @@ async fn test_llm_span_contains_user_message_preview() {
|
|||
#[serial]
|
||||
async fn test_llm_span_contains_time_to_first_token() {
|
||||
let mock_collector = MockOtelCollector::start().await;
|
||||
std::env::set_var("OTEL_COLLECTOR_URL", format!("{}/v1/traces", mock_collector.address()));
|
||||
std::env::set_var(
|
||||
"OTEL_COLLECTOR_URL",
|
||||
format!("{}/v1/traces", mock_collector.address()),
|
||||
);
|
||||
std::env::set_var("OTEL_TRACING_ENABLED", "true");
|
||||
std::env::set_var("TRACE_FLUSH_INTERVAL_MS", "500");
|
||||
let trace_collector = Arc::new(TraceCollector::new(Some(true)));
|
||||
|
|
@ -217,7 +239,10 @@ async fn test_llm_span_contains_time_to_first_token() {
|
|||
#[serial]
|
||||
async fn test_llm_span_contains_upstream_path() {
|
||||
let mock_collector = MockOtelCollector::start().await;
|
||||
std::env::set_var("OTEL_COLLECTOR_URL", format!("{}/v1/traces", mock_collector.address()));
|
||||
std::env::set_var(
|
||||
"OTEL_COLLECTOR_URL",
|
||||
format!("{}/v1/traces", mock_collector.address()),
|
||||
);
|
||||
std::env::set_var("OTEL_TRACING_ENABLED", "true");
|
||||
std::env::set_var("TRACE_FLUSH_INTERVAL_MS", "500");
|
||||
let trace_collector = Arc::new(TraceCollector::new(Some(true)));
|
||||
|
|
@ -241,7 +266,10 @@ async fn test_llm_span_contains_upstream_path() {
|
|||
// Operation name should show the transformation
|
||||
let name = span.get("name").and_then(|v| v.as_str());
|
||||
assert!(name.is_some());
|
||||
assert!(name.unwrap().contains(">>"), "Operation name should show path transformation");
|
||||
assert!(
|
||||
name.unwrap().contains(">>"),
|
||||
"Operation name should show path transformation"
|
||||
);
|
||||
|
||||
// Check upstream target attribute
|
||||
let upstream = get_string_attr(span, "http.upstream_target");
|
||||
|
|
@ -252,7 +280,10 @@ async fn test_llm_span_contains_upstream_path() {
|
|||
#[serial]
|
||||
async fn test_llm_span_multiple_services() {
|
||||
let mock_collector = MockOtelCollector::start().await;
|
||||
std::env::set_var("OTEL_COLLECTOR_URL", format!("{}/v1/traces", mock_collector.address()));
|
||||
std::env::set_var(
|
||||
"OTEL_COLLECTOR_URL",
|
||||
format!("{}/v1/traces", mock_collector.address()),
|
||||
);
|
||||
std::env::set_var("OTEL_TRACING_ENABLED", "true");
|
||||
std::env::set_var("TRACE_FLUSH_INTERVAL_MS", "500");
|
||||
let trace_collector = Arc::new(TraceCollector::new(Some(true)));
|
||||
|
|
@ -285,7 +316,10 @@ async fn test_tracing_disabled_produces_no_spans() {
|
|||
let mock_collector = MockOtelCollector::start().await;
|
||||
|
||||
// Create TraceCollector with tracing DISABLED
|
||||
std::env::set_var("OTEL_COLLECTOR_URL", format!("{}/v1/traces", mock_collector.address()));
|
||||
std::env::set_var(
|
||||
"OTEL_COLLECTOR_URL",
|
||||
format!("{}/v1/traces", mock_collector.address()),
|
||||
);
|
||||
std::env::set_var("OTEL_TRACING_ENABLED", "false");
|
||||
std::env::set_var("TRACE_FLUSH_INTERVAL_MS", "500");
|
||||
let trace_collector = Arc::new(TraceCollector::new(Some(false)));
|
||||
|
|
@ -300,5 +334,9 @@ async fn test_tracing_disabled_produces_no_spans() {
|
|||
|
||||
let payloads = mock_collector.get_traces().await;
|
||||
let all_spans = extract_spans(&payloads);
|
||||
assert_eq!(all_spans.len(), 0, "No spans should be captured when tracing is disabled");
|
||||
assert_eq!(
|
||||
all_spans.len(),
|
||||
0,
|
||||
"No spans should be captured when tracing is disabled"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue