diff --git a/src/servers/src/otlp/trace/span.rs b/src/servers/src/otlp/trace/span.rs index 4a300bb1b6..65a2c87ca8 100644 --- a/src/servers/src/otlp/trace/span.rs +++ b/src/servers/src/otlp/trace/span.rs @@ -32,22 +32,22 @@ pub struct TraceSpan { pub service_name: Option, pub trace_id: String, pub span_id: String, - pub parent_span_id: String, + pub parent_span_id: Option, // the following are fields - pub resource_attributes: Attributes, // TODO(yuanbohan): Map in the future + pub resource_attributes: Attributes, pub scope_name: String, pub scope_version: String, - pub scope_attributes: Attributes, // TODO(yuanbohan): Map in the future + pub scope_attributes: Attributes, pub trace_state: String, pub span_name: String, pub span_kind: String, pub span_status_code: String, pub span_status_message: String, - pub span_attributes: Attributes, // TODO(yuanbohan): Map in the future - pub span_events: SpanEvents, // TODO(yuanbohan): List in the future - pub span_links: SpanLinks, // TODO(yuanbohan): List in the future - pub start_in_nanosecond: u64, // this is also the Timestamp Index + pub span_attributes: Attributes, + pub span_events: SpanEvents, // TODO(yuanbohan): List in the future + pub span_links: SpanLinks, // TODO(yuanbohan): List in the future + pub start_in_nanosecond: u64, // this is also the Timestamp Index pub end_in_nanosecond: u64, } @@ -203,7 +203,11 @@ pub fn parse_span( service_name, trace_id: bytes_to_hex_string(&span.trace_id), span_id: bytes_to_hex_string(&span.span_id), - parent_span_id: bytes_to_hex_string(&span.parent_span_id), + parent_span_id: if span.parent_span_id.is_empty() { + None + } else { + Some(bytes_to_hex_string(&span.parent_span_id)) + }, resource_attributes: Attributes::from(resource_attrs), trace_state: span.trace_state, diff --git a/src/servers/src/otlp/trace/v0.rs b/src/servers/src/otlp/trace/v0.rs index 44dbad47ea..8484f5f80e 100644 --- a/src/servers/src/otlp/trace/v0.rs +++ b/src/servers/src/otlp/trace/v0.rs @@ -91,7 +91,10 @@ pub fn write_span_to_row(writer: &mut TableData, span: TraceSpan) -> Result<()> let iter = vec![ (TRACE_ID_COLUMN, span.trace_id), (SPAN_ID_COLUMN, span.span_id), - (PARENT_SPAN_ID_COLUMN, span.parent_span_id), + ( + PARENT_SPAN_ID_COLUMN, + span.parent_span_id.unwrap_or_default(), + ), ] .into_iter() .map(|(col, val)| (col.to_string(), val)); diff --git a/src/servers/src/otlp/trace/v1.rs b/src/servers/src/otlp/trace/v1.rs index 8a01c589cc..2f6f077274 100644 --- a/src/servers/src/otlp/trace/v1.rs +++ b/src/servers/src/otlp/trace/v1.rs @@ -103,8 +103,18 @@ pub fn write_span_to_row(writer: &mut TableData, span: TraceSpan) -> Result<()> row_writer::write_tags(writer, tags.into_iter(), &mut row)?; // write fields + if let Some(parent_span_id) = span.parent_span_id { + row_writer::write_fields( + writer, + std::iter::once(make_string_column_data( + PARENT_SPAN_ID_COLUMN, + parent_span_id, + )), + &mut row, + )?; + } + let fields = vec![ - make_string_column_data(PARENT_SPAN_ID_COLUMN, span.parent_span_id), make_string_column_data(SPAN_KIND_COLUMN, span.span_kind), make_string_column_data(SPAN_NAME_COLUMN, span.span_name), make_string_column_data("span_status_code", span.span_status_code), diff --git a/tests-integration/tests/http.rs b/tests-integration/tests/http.rs index 154034dd67..0ad561c601 100644 --- a/tests-integration/tests/http.rs +++ b/tests-integration/tests/http.rs @@ -2197,7 +2197,7 @@ pub async fn test_otlp_traces_v1(store_type: StorageType) { assert_eq!(StatusCode::OK, res.status()); // select traces data - let expected = r#"[[1736480942444376000,1736480942444499000,123000,"c05d7a4ec8e1f231f02ed6e8da8655b4","9630f2916e2f7909","d24f921c75f68e23","SPAN_KIND_SERVER","okey-dokey-0","STATUS_CODE_UNSET","","","telemetrygen","","telemetrygen","1.2.3.4","telemetrygen-client",[],[]],[1736480942444376000,1736480942444499000,123000,"c05d7a4ec8e1f231f02ed6e8da8655b4","d24f921c75f68e23","","SPAN_KIND_CLIENT","lets-go","STATUS_CODE_UNSET","","","telemetrygen","","telemetrygen","1.2.3.4","telemetrygen-server",[],[]],[1736480942444589000,1736480942444712000,123000,"cc9e0991a2e63d274984bd44ee669203","8f847259b0f6e1ab","eba7be77e3558179","SPAN_KIND_SERVER","okey-dokey-0","STATUS_CODE_UNSET","","","telemetrygen","","telemetrygen","1.2.3.4","telemetrygen-client",[],[]],[1736480942444589000,1736480942444712000,123000,"cc9e0991a2e63d274984bd44ee669203","eba7be77e3558179","","SPAN_KIND_CLIENT","lets-go","STATUS_CODE_UNSET","","","telemetrygen","","telemetrygen","1.2.3.4","telemetrygen-server",[],[]]]"#; + let expected = r#"[[1736480942444376000,1736480942444499000,123000,"c05d7a4ec8e1f231f02ed6e8da8655b4","9630f2916e2f7909","d24f921c75f68e23","SPAN_KIND_SERVER","okey-dokey-0","STATUS_CODE_UNSET","","","telemetrygen","","telemetrygen","1.2.3.4","telemetrygen-client",[],[]],[1736480942444376000,1736480942444499000,123000,"c05d7a4ec8e1f231f02ed6e8da8655b4","d24f921c75f68e23",null,"SPAN_KIND_CLIENT","lets-go","STATUS_CODE_UNSET","","","telemetrygen","","telemetrygen","1.2.3.4","telemetrygen-server",[],[]],[1736480942444589000,1736480942444712000,123000,"cc9e0991a2e63d274984bd44ee669203","8f847259b0f6e1ab","eba7be77e3558179","SPAN_KIND_SERVER","okey-dokey-0","STATUS_CODE_UNSET","","","telemetrygen","","telemetrygen","1.2.3.4","telemetrygen-client",[],[]],[1736480942444589000,1736480942444712000,123000,"cc9e0991a2e63d274984bd44ee669203","eba7be77e3558179",null,"SPAN_KIND_CLIENT","lets-go","STATUS_CODE_UNSET","","","telemetrygen","","telemetrygen","1.2.3.4","telemetrygen-server",[],[]]]"#; validate_data("otlp_traces", &client, "select * from mytable;", expected).await; let expected_ddl = r#"[["mytable","CREATE TABLE IF NOT EXISTS \"mytable\" (\n \"timestamp\" TIMESTAMP(9) NOT NULL,\n \"timestamp_end\" TIMESTAMP(9) NULL,\n \"duration_nano\" BIGINT UNSIGNED NULL,\n \"trace_id\" STRING NULL SKIPPING INDEX WITH(granularity = '10240', type = 'BLOOM'),\n \"span_id\" STRING NULL,\n \"parent_span_id\" STRING NULL SKIPPING INDEX WITH(granularity = '10240', type = 'BLOOM'),\n \"span_kind\" STRING NULL,\n \"span_name\" STRING NULL SKIPPING INDEX WITH(granularity = '10240', type = 'BLOOM'),\n \"span_status_code\" STRING NULL,\n \"span_status_message\" STRING NULL,\n \"trace_state\" STRING NULL,\n \"scope_name\" STRING NULL,\n \"scope_version\" STRING NULL,\n \"service_name\" STRING NULL,\n \"span_attributes.net.peer.ip\" STRING NULL,\n \"span_attributes.peer.service\" STRING NULL,\n \"span_events\" JSON NULL,\n \"span_links\" JSON NULL,\n TIME INDEX (\"timestamp\"),\n PRIMARY KEY (\"trace_id\", \"span_id\")\n)\nPARTITION ON COLUMNS (\"trace_id\") (\n trace_id < '1',\n trace_id >= '1' AND trace_id < '2',\n trace_id >= '2' AND trace_id < '3',\n trace_id >= '3' AND trace_id < '4',\n trace_id >= '4' AND trace_id < '5',\n trace_id >= '5' AND trace_id < '6',\n trace_id >= '6' AND trace_id < '7',\n trace_id >= '7' AND trace_id < '8',\n trace_id >= '8' AND trace_id < '9',\n trace_id >= '9' AND trace_id < 'A',\n trace_id >= 'A' AND trace_id < 'B' OR trace_id >= 'a' AND trace_id < 'b',\n trace_id >= 'B' AND trace_id < 'C' OR trace_id >= 'b' AND trace_id < 'c',\n trace_id >= 'C' AND trace_id < 'D' OR trace_id >= 'c' AND trace_id < 'd',\n trace_id >= 'D' AND trace_id < 'E' OR trace_id >= 'd' AND trace_id < 'e',\n trace_id >= 'E' AND trace_id < 'F' OR trace_id >= 'e' AND trace_id < 'f',\n trace_id >= 'F' AND trace_id < 'a' OR trace_id >= 'f'\n)\nENGINE=mito\nWITH(\n append_mode = 'true'\n)"]]"#;