chore: return 404 if trace not found (#7304)

* chore: return 404 if trace not found

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

* chore: add test and fix

Signed-off-by: shuiyisong <xixing.sys@gmail.com>

---------

Signed-off-by: shuiyisong <xixing.sys@gmail.com>
This commit is contained in:
shuiyisong
2025-11-26 17:39:28 +08:00
committed by GitHub
parent 6485a26fa3
commit 5472bdfc0f
2 changed files with 51 additions and 1 deletions

View File

@@ -56,6 +56,9 @@ pub const JAEGER_QUERY_TABLE_NAME_KEY: &str = "jaeger_query_table_name";
const REF_TYPE_CHILD_OF: &str = "CHILD_OF";
const SPAN_KIND_TIME_FMTS: [&str; 2] = ["%Y-%m-%d %H:%M:%S%.6f%z", "%Y-%m-%d %H:%M:%S%.9f%z"];
const TRACE_NOT_FOUND_ERROR_CODE: i32 = 404;
const TRACE_NOT_FOUND_ERROR_MSG: &str = "trace not found";
/// JaegerAPIResponse is the response of Jaeger HTTP API.
/// The original version is `structuredResponse` which is defined in https://github.com/jaegertracing/jaeger/blob/main/cmd/query/app/http_handler.go.
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
@@ -67,6 +70,22 @@ pub struct JaegerAPIResponse {
pub errors: Vec<JaegerAPIError>,
}
impl JaegerAPIResponse {
pub fn trace_not_found() -> Self {
Self {
data: None,
total: 0,
limit: 0,
offset: 0,
errors: vec![JaegerAPIError {
code: TRACE_NOT_FOUND_ERROR_CODE,
msg: TRACE_NOT_FOUND_ERROR_MSG.to_string(),
trace_id: None,
}],
}
}
}
/// JaegerData is the query result of Jaeger HTTP API.
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
@@ -474,6 +493,10 @@ pub async fn handle_get_trace(
match covert_to_records(output).await {
Ok(Some(records)) => match traces_from_records(records) {
Ok(traces) if traces.is_empty() => (
HttpStatusCode::NOT_FOUND,
axum::Json(JaegerAPIResponse::trace_not_found()),
),
Ok(traces) => (
HttpStatusCode::OK,
axum::Json(JaegerAPIResponse {
@@ -486,7 +509,10 @@ pub async fn handle_get_trace(
error_response(err)
}
},
Ok(None) => (HttpStatusCode::OK, axum::Json(JaegerAPIResponse::default())),
Ok(None) => (
HttpStatusCode::NOT_FOUND,
axum::Json(JaegerAPIResponse::trace_not_found()),
),
Err(err) => {
error!("Failed to get trace '{}': {:?}", trace_id, err);
error_response(err)

View File

@@ -6575,6 +6575,30 @@ pub async fn test_jaeger_query_api_for_trace_v1(store_type: StorageType) {
let expected: Value = serde_json::from_str(expected).unwrap();
assert_eq!(resp, expected);
// Test `/api/traces/{trace_id}` API for non-existent trace.
let res = client
.get("/v1/jaeger/api/traces/0000000000000000000000000000dead")
.header("x-greptime-trace-table-name", trace_table_name)
.send()
.await;
assert_eq!(StatusCode::NOT_FOUND, res.status());
let expected = r#"{
"data": null,
"total": 0,
"limit": 0,
"offset": 0,
"errors": [
{
"code": 404,
"msg": "trace not found"
}
]
}
"#;
let resp: Value = serde_json::from_str(&res.text().await).unwrap();
let expected: Value = serde_json::from_str(expected).unwrap();
assert_eq!(resp, expected);
// Test `/api/traces` API.
let res = client
.get("/v1/jaeger/api/traces?service=test-jaeger-query-api&operation=access-mysql&start=1738726754492421&end=1738726754642422&tags=%7B%22operation.type%22%3A%22access-mysql%22%7D")