Skip to content

Commit 96ecb94

Browse files
author
Claude Sonnet (coordinator)
committed
fix(rotel-visual): resolve compilation errors — unclosed delimiters, shadowed identifiers
Rewrite otlp_logs_handler which had deeply corrupted nesting (dead code after early return, out-of-scope locals from incorrect merge resolution). Fix main.rs missing Ok(()) return. Fix test file function/variable shadowing where Router collided with — renamed to test_app.
1 parent a56ec94 commit 96ecb94

3 files changed

Lines changed: 67 additions & 90 deletions

File tree

crates/rotel-visual/src/lib.rs

Lines changed: 50 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -410,63 +410,51 @@ struct OtlpIngestResponse {
410410
#[instrument]
411411
async fn otlp_logs_handler(
412412
State(state): State<Arc<AppState>>,
413-
Json(req): Json<OtlpLogsRequest>,
413+
Json(payload): Json<serde_json::Value>,
414414
) -> impl IntoResponse {
415-
let request: Result<otlp_json::LogsRequest, _> = serde_json::from_value(payload.clone());
416-
match request {
417-
Ok(req) => {
418-
let mut logs = Vec::new();
419-
let mut classified = Vec::new();
420-
let mut log_count = 0u64;
421-
422-
for resource_log in &req.resource_logs {
423-
for scope_log in &resource_log.scope_logs {
424-
for record in &scope_log.log_records {
425-
log_count += 1;
426-
let body = record.body.string_value.clone().unwrap_or_default();
427-
let severity = match OTelSeverityNumber::try_from(record.severity_number) {
428-
Ok(s) => s,
429-
Err(e) => {
430-
error!("Invalid severity number: {}", e);
431-
continue;
432-
}
433-
};
434-
let time_unix_nano = match record.time_unix_nano.parse() {
435-
Ok(t) => t,
436-
Err(e) => {
437-
error!("Invalid time_unix_nano '{}': {}", record.time_unix_nano, e);
438-
continue;
439-
}
440-
};
441-
442-
let log = OTelLogRecord::new(
443-
time_unix_nano,
444-
severity,
445-
body.clone(),
446-
);
447-
let response = Json(serde_json::json!({
448-
"error": format!(
449-
"invalid OTLP log record timeUnixNano '{}': {}",
450-
record.time_unix_nano, error
451-
)
452-
}));
453-
return (axum::http::StatusCode::BAD_REQUEST, response)
454-
.into_response();
415+
let mut logs = Vec::new();
416+
let mut classified = Vec::new();
417+
let mut log_count = 0u64;
418+
419+
let request: otlp_json::LogsRequest = match serde_json::from_value(payload) {
420+
Ok(r) => r,
421+
Err(e) => {
422+
error!("Invalid OTLP log structure: {e}");
423+
let response = Json(serde_json::json!({
424+
"error": format!("invalid OTLP log structure: {e}")
425+
}));
426+
return (axum::http::StatusCode::BAD_REQUEST, response).into_response();
427+
}
428+
};
429+
430+
for resource_log in &request.resource_logs {
431+
for scope_log in &resource_log.scope_logs {
432+
for record in &scope_log.log_records {
433+
log_count += 1;
434+
let body = record.body.string_value.clone().unwrap_or_default();
435+
let severity = match OTelSeverityNumber::try_from(record.severity_number) {
436+
Ok(s) => s,
437+
Err(e) => {
438+
error!("Invalid severity number: {}", e);
439+
continue;
440+
}
441+
};
442+
let time_unix_nano: u64 = match record.time_unix_nano.parse() {
443+
Ok(t) => t,
444+
Err(e) => {
445+
error!("Invalid time_unix_nano '{}': {}", record.time_unix_nano, e);
446+
continue;
455447
}
456448
};
457449

458-
let artifacts = state.classifier.classify_log(&log);
459-
for artifact in &artifacts {
460-
classified.push(ClassifiedArtifactView::from(artifact));
461-
}
450+
let mut log = OTelLogRecord::new(time_unix_nano, severity, body);
462451

463-
// Extract log-record-level attributes
464452
for attr in &record.attributes {
465453
if let Some(val) = &attr.value.string_value {
466454
log.attributes.insert(attr.key.clone(), val.clone());
467455
}
468456
}
469-
// Extract resource-level attributes (log record wins on collision)
457+
470458
if let Some(resource) = &resource_log.resource {
471459
for attr in &resource.attributes {
472460
if let Some(val) = &attr.value.string_value {
@@ -477,38 +465,24 @@ async fn otlp_logs_handler(
477465
}
478466
}
479467

480-
state.metrics.inc_logs_ingested(log_count);
481-
state.metrics.inc_logs_classified(classified.len() as u64);
482-
483-
let telemetry = TelemetryData {
484-
logs,
485-
metrics: vec![],
486-
spans: vec![],
487-
classified,
488-
};
468+
let artifacts = state.classifier.classify_log(&log);
469+
for artifact in &artifacts {
470+
classified.push(ClassifiedArtifactView::from(artifact));
471+
}
489472

490-
state.broadcast(telemetry).await;
491-
492-
let response = Json(OtlpIngestResponse {
493-
accepted: true,
494-
signal: "log".to_string(),
495-
resource_count: req.resource_logs.len(),
496-
classification_columns: TelemetryArrowBatch::classification_columns()
497-
.iter()
498-
.map(|s| s.to_string())
499-
.collect(),
500-
});
501-
(axum::http::StatusCode::ACCEPTED, response).into_response()
502-
}
503-
Err(error) => {
504-
error!("Invalid OTLP JSON payload: {}", error);
505-
let response = Json(serde_json::json!({
506-
"error": format!("invalid OTLP JSON payload: {error}")
507-
}));
508-
(axum::http::StatusCode::BAD_REQUEST, response).into_response()
473+
logs.push(LogRecord {
474+
timestamp: time_unix_nano.to_string(),
475+
level: format!("{:?}", severity),
476+
message: log.body.clone(),
477+
shape: "otlp_log".to_string(),
478+
});
479+
}
509480
}
510481
}
511482

483+
state.metrics.inc_logs_ingested(log_count);
484+
state.metrics.inc_logs_classified(classified.len() as u64);
485+
512486
let telemetry = TelemetryData {
513487
logs,
514488
metrics: vec![],
@@ -521,7 +495,7 @@ async fn otlp_logs_handler(
521495
let response = Json(OtlpIngestResponse {
522496
accepted: true,
523497
signal: "log".to_string(),
524-
resource_count: req.resource_logs.len(),
498+
resource_count: request.resource_logs.len(),
525499
classification_columns: TelemetryArrowBatch::classification_columns()
526500
.iter()
527501
.map(|s| s.to_string())

crates/rotel-visual/src/main.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ async fn main() -> Result<(), anyhow::Error> {
44
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
55
.init();
66

7-
if let Err(err) = rotel_visual::run_server().await {
8-
eprintln!("Fatal: {err}");
9-
std::process::exit(1);
7+
match rotel_visual::run_server().await {
8+
Ok(()) => Ok(()),
9+
Err(err) => {
10+
eprintln!("Fatal: {err}");
11+
std::process::exit(1);
12+
}
1013
}
1114
}

crates/rotel-visual/tests/health_dashboard_tests.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use axum::http::{Request, StatusCode};
33
use serde_json::json;
44
use tower::ServiceExt;
55

6-
fn app() -> axum::Router {
6+
fn test_app() -> axum::Router {
77
rotel_visual::create_app().unwrap()
88
}
99

@@ -61,7 +61,7 @@ async fn test_otlp_logs_ingestion_accepts_json_and_returns_202() {
6161
]
6262
});
6363

64-
let response = app()
64+
let response = test_app()
6565
.oneshot(
6666
Request::builder()
6767
.uri("/v1/logs")
@@ -89,7 +89,7 @@ async fn test_otlp_metrics_ingestion_accepts_json_and_returns_202() {
8989
]
9090
});
9191

92-
let response = app()
92+
let response = test_app()
9393
.oneshot(
9494
Request::builder()
9595
.uri("/v1/metrics")
@@ -117,7 +117,7 @@ async fn test_otlp_traces_ingestion_accepts_json_and_returns_202() {
117117
]
118118
});
119119

120-
let response = app()
120+
let response = test_app()
121121
.oneshot(
122122
Request::builder()
123123
.uri("/v1/traces")
@@ -156,8 +156,8 @@ async fn test_classified_artifacts_are_accepted_via_otlp_logs() {
156156
// This test verifies that an OTLP log payload matching a classification
157157
// rule is accepted by the ingestion endpoint.
158158

159-
// Ingest a log that matches the GPU fault rule
160159
// Ingest a log that matches the GPU fault rule.
160+
let body = serde_json::json!({
161161
"resourceLogs": [
162162
{
163163
"resource": {
@@ -182,7 +182,7 @@ async fn test_classified_artifacts_are_accepted_via_otlp_logs() {
182182
]
183183
});
184184

185-
let response = app()
185+
let response = test_app()
186186
.clone()
187187
.oneshot(
188188
Request::builder()
@@ -226,7 +226,7 @@ async fn test_ring_buffer_populated_after_otlp_log_ingest() {
226226
]
227227
});
228228

229-
let response = app()
229+
let response = test_app()
230230
.clone()
231231
.oneshot(
232232
Request::builder()
@@ -244,7 +244,7 @@ async fn test_ring_buffer_populated_after_otlp_log_ingest() {
244244

245245
#[tokio::test]
246246
async fn test_metrics_endpoint_returns_self_telemetry() {
247-
let response = app()
247+
let response = test_app()
248248
.oneshot(
249249
Request::builder()
250250
.uri("/metrics")
@@ -265,7 +265,7 @@ async fn test_metrics_endpoint_returns_self_telemetry() {
265265

266266
#[tokio::test]
267267
async fn test_metrics_endpoint_increments_after_ingestion() {
268-
let app = app();
268+
let app = test_app();
269269

270270
// Get baseline
271271
let baseline = app
@@ -336,7 +336,7 @@ async fn test_rotel_evaluate_endpoint_returns_sarif() {
336336
"slo_expected": true
337337
});
338338

339-
let response = app()
339+
let response = test_app()
340340
.oneshot(
341341
Request::builder()
342342
.uri("/rotel/evaluate")
@@ -366,7 +366,7 @@ async fn test_rotel_evaluate_detects_slo_failure() {
366366
"slo_expected": true
367367
});
368368

369-
let response = app()
369+
let response = test_app()
370370
.oneshot(
371371
Request::builder()
372372
.uri("/rotel/evaluate")

0 commit comments

Comments
 (0)