Skip to content

Commit 982e07c

Browse files
authored
refactor(stackable-telemetry): Use semantic convention constants (#1055)
* refactor(stackable-telemetry): Use semantic convention constants * chore(stackable-telemetry): Add changelog entry
1 parent cc7d240 commit 982e07c

File tree

5 files changed

+58
-30
lines changed

5 files changed

+58
-30
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ opentelemetry = "0.29.1"
4040
opentelemetry_sdk = { version = "0.29.0", features = ["rt-tokio"] }
4141
opentelemetry-appender-tracing = "0.29.1"
4242
opentelemetry-otlp = "0.29.0"
43-
# opentelemetry-semantic-conventions = "0.28.0"
43+
opentelemetry-semantic-conventions = "0.29.0"
4444
p256 = { version = "0.13.2", features = ["ecdsa"] }
4545
paste = "1.0.15"
4646
pin-project = "1.1.5"

crates/stackable-telemetry/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
66

77
### Changed
88

9+
- Use constants from `opentelemetry-semantic-conventions` instead of hard-coded strings ([#1055]).
910
- Bump `opentelemetry` and related crates to `0.29.x` and `tracing-opentelemetry` to `0.30.0` ([#1021]).
1011

1112
### Fixed
@@ -14,6 +15,7 @@ All notable changes to this project will be documented in this file.
1415

1516
[#1021]: https://github.com/stackabletech/operator-rs/pull/1021
1617
[#1026]: https://github.com/stackabletech/operator-rs/pull/1026
18+
[#1055]: https://github.com/stackabletech/operator-rs/pull/1055
1719

1820
## [0.6.0] - 2025-04-14
1921

crates/stackable-telemetry/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ futures-util.workspace = true
1616
opentelemetry = { workspace = true, features = ["logs"] }
1717
opentelemetry-appender-tracing.workspace = true
1818
opentelemetry-otlp = { workspace = true, features = ["grpc-tonic", "gzip-tonic", "logs"] }
19-
# opentelemetry-semantic-conventions.workspace = true
19+
opentelemetry-semantic-conventions.workspace = true
2020
opentelemetry_sdk = { workspace = true, features = ["logs", "rt-tokio", "spec_unstable_logs_enabled"] }
2121
pin-project.workspace = true
2222
snafu.workspace = true

crates/stackable-telemetry/src/instrumentation/axum/mod.rs

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ use opentelemetry::{
2525
Context,
2626
trace::{SpanKind, TraceContextExt},
2727
};
28+
use opentelemetry_semantic_conventions::{
29+
attribute::{OTEL_STATUS_CODE, OTEL_STATUS_DESCRIPTION},
30+
trace::{
31+
CLIENT_ADDRESS, CLIENT_PORT, HTTP_REQUEST_HEADER, HTTP_REQUEST_METHOD,
32+
HTTP_RESPONSE_STATUS_CODE, HTTP_ROUTE, SERVER_ADDRESS, SERVER_PORT, URL_PATH, URL_QUERY,
33+
URL_SCHEME, USER_AGENT_ORIGINAL,
34+
},
35+
};
2836
use pin_project::pin_project;
2937
use snafu::{ResultExt, Snafu};
3038
use tower::{Layer, Service};
@@ -41,6 +49,14 @@ const X_FORWARDED_HOST_HEADER_KEY: &str = "X-Forwarded-Host";
4149
const DEFAULT_HTTPS_PORT: u16 = 443;
4250
const DEFAULT_HTTP_PORT: u16 = 80;
4351

52+
// NOTE (@Techassi): These constants are defined here because they are private in
53+
// the tracing-opentelemetry crate.
54+
const OTEL_NAME: &str = "otel.name";
55+
const OTEL_KIND: &str = "otel.kind";
56+
57+
const OTEL_TRACE_ID_FROM: &str = "opentelemetry.trace_id.from";
58+
const OTEL_TRACE_ID_TO: &str = "opentelemetry.trace_id.to";
59+
4460
/// A Tower [`Layer`][1] which decorates [`TraceService`].
4561
///
4662
/// ### Example with Axum
@@ -414,21 +430,23 @@ impl SpanExt for Span {
414430

415431
let span = tracing::trace_span!(
416432
"HTTP request",
417-
"otel.name" = span_name,
418-
"otel.kind" = ?SpanKind::Server,
419-
"otel.status_code" = Empty,
420-
"otel.status_message" = Empty,
421-
"http.request.method" = http_method,
422-
"http.response.status_code" = Empty,
423-
"http.route" = Empty,
424-
"url.path" = url.path(),
425-
"url.query" = url.query(),
426-
"url.scheme" = url.scheme_str().unwrap_or_default(),
427-
"user_agent.original" = Empty,
428-
"server.address" = Empty,
429-
"server.port" = Empty,
430-
"client.address" = Empty,
431-
"client.port" = Empty,
433+
{ OTEL_NAME } = span_name,
434+
{ OTEL_KIND } = ?SpanKind::Server,
435+
{ OTEL_STATUS_CODE } = Empty,
436+
// The current tracing-opentelemetry version still uses the old semantic convention
437+
// See https://github.com/tokio-rs/tracing-opentelemetry/pull/209
438+
{ OTEL_STATUS_DESCRIPTION } = Empty,
439+
{ HTTP_REQUEST_METHOD } = http_method,
440+
{ HTTP_RESPONSE_STATUS_CODE } = Empty,
441+
{ HTTP_ROUTE } = Empty,
442+
{ URL_PATH } = url.path(),
443+
{ URL_QUERY } = url.query(),
444+
{ URL_SCHEME } = url.scheme_str().unwrap_or_default(),
445+
{ USER_AGENT_ORIGINAL } = Empty,
446+
{ SERVER_ADDRESS } = Empty,
447+
{ SERVER_PORT } = Empty,
448+
{ CLIENT_ADDRESS } = Empty,
449+
{ CLIENT_PORT } = Empty,
432450
// TODO (@Techassi): Add network.protocol.version
433451
);
434452

@@ -462,8 +480,8 @@ impl SpanExt for Span {
462480

463481
if new_span_context != current_span_context {
464482
tracing::trace!(
465-
opentelemetry.trace_id.from = ?current_span_context.trace_id(),
466-
opentelemetry.trace_id.to = ?new_span_context.trace_id(),
483+
{ OTEL_TRACE_ID_FROM } = ?current_span_context.trace_id(),
484+
{ OTEL_TRACE_ID_TO } = ?new_span_context.trace_id(),
467485
"set parent span context based on context extracted from request headers"
468486
);
469487

@@ -473,7 +491,7 @@ impl SpanExt for Span {
473491
}
474492

475493
if let Some(user_agent) = req.user_agent() {
476-
span.record("user_agent.original", user_agent);
494+
span.record(USER_AGENT_ORIGINAL, user_agent);
477495
}
478496

479497
// Setting server.address and server.port
@@ -483,21 +501,21 @@ impl SpanExt for Span {
483501
// NOTE (@Techassi): We cast to i64, because otherwise the field
484502
// will NOT be recorded as a number but as a string. This is likely
485503
// an issue in the tracing-opentelemetry crate.
486-
span.record("server.address", host)
487-
.record("server.port", port as i64);
504+
span.record(SERVER_ADDRESS, host)
505+
.record(SERVER_PORT, port as i64);
488506
}
489507

490508
// Setting fields according to the HTTP server semantic conventions
491509
// See https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-server-semantic-conventions
492510

493511
if let Some(client_socket_address) = req.client_socket_address() {
494-
span.record("client.address", client_socket_address.ip().to_string());
512+
span.record(CLIENT_ADDRESS, client_socket_address.ip().to_string());
495513

496514
if opt_in {
497515
// NOTE (@Techassi): We cast to i64, because otherwise the field
498516
// will NOT be recorded as a number but as a string. This is
499517
// likely an issue in the tracing-opentelemetry crate.
500-
span.record("client.port", client_socket_address.port() as i64);
518+
span.record(CLIENT_PORT, client_socket_address.port() as i64);
501519
}
502520
}
503521

@@ -511,7 +529,7 @@ impl SpanExt for Span {
511529
// See: https://github.com/tokio-rs/tracing/issues/1343
512530

513531
if let Some(http_route) = req.matched_path() {
514-
span.record("http.route", http_route.as_str());
532+
span.record(HTTP_ROUTE, http_route.as_str());
515533
}
516534

517535
span
@@ -525,7 +543,7 @@ impl SpanExt for Span {
525543
// header_name.as_str() always returns lowercase strings and thus we
526544
// don't need to call to_lowercase on it.
527545
let header_name = header_name.as_str();
528-
let field_name = format!("http.request.header.{header_name}");
546+
let field_name = format!("{HTTP_REQUEST_HEADER}.{header_name}");
529547

530548
self.record(
531549
field_name.as_str(),
@@ -540,15 +558,15 @@ impl SpanExt for Span {
540558
// NOTE (@Techassi): We cast to i64, because otherwise the field will
541559
// NOT be recorded as a number but as a string. This is likely an issue
542560
// in the tracing-opentelemetry crate.
543-
self.record("http.response.status_code", status_code.as_u16() as i64);
561+
self.record(HTTP_RESPONSE_STATUS_CODE, status_code.as_u16() as i64);
544562

545563
// Only set the span status to "Error" when we encountered an server
546564
// error. See:
547565
//
548566
// - https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
549567
// - https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/trace/api.md#set-status
550568
if status_code.is_server_error() {
551-
self.record("otel.status_code", "Error");
569+
self.record(OTEL_STATUS_CODE, "Error");
552570
// NOTE (@Techassi): Can we add a status_description here as well?
553571
}
554572

@@ -561,8 +579,9 @@ impl SpanExt for Span {
561579
E: std::error::Error,
562580
{
563581
// NOTE (@Techassi): This field might get renamed: https://github.com/tokio-rs/tracing-opentelemetry/issues/115
564-
self.record("otel.status_code", "Error")
565-
.record("otel.status_message", error.to_string());
582+
// NOTE (@Techassi): It got renamed, a fixed version of tracing-opentelemetry is not available yet
583+
self.record(OTEL_STATUS_CODE, "Error")
584+
.record(OTEL_STATUS_DESCRIPTION, error.to_string());
566585
}
567586
}
568587

0 commit comments

Comments
 (0)