common_telemetry/tracing_context.rs
1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! tracing stuffs, inspired by RisingWave
16use std::collections::HashMap;
17
18use opentelemetry::propagation::TextMapPropagator;
19use opentelemetry_sdk::propagation::TraceContextPropagator;
20use tracing_opentelemetry::OpenTelemetrySpanExt;
21
22// An wapper for `Futures` that provides tracing instrument adapters.
23pub trait FutureExt: std::future::Future + Sized {
24 fn trace(self, span: tracing::span::Span) -> tracing::instrument::Instrumented<Self>;
25}
26
27impl<T: std::future::Future> FutureExt for T {
28 #[inline]
29 fn trace(self, span: tracing::span::Span) -> tracing::instrument::Instrumented<Self> {
30 tracing::instrument::Instrument::instrument(self, span)
31 }
32}
33
34/// Context for tracing used for propagating tracing information in a distributed system.
35///
36/// Generally, the caller of a service should create a tracing context from the current tracing span
37/// and pass it to the callee through the network. The callee will then attach its local tracing
38/// span as a child of the tracing context, so that the external tracing service can associate them
39/// in a single trace.
40///
41/// The tracing context must be serialized into the W3C trace context format and passed in rpc
42/// message headers when communication of frontend, datanode and meta.
43///
44/// See [Trace Context](https://www.w3.org/TR/trace-context/) for more information.
45#[derive(Debug, Clone)]
46pub struct TracingContext(opentelemetry::Context);
47
48pub type W3cTrace = HashMap<String, String>;
49
50impl Default for TracingContext {
51 fn default() -> Self {
52 Self::new()
53 }
54}
55
56type Propagator = TraceContextPropagator;
57
58impl TracingContext {
59 /// Create a new tracing context from a tracing span.
60 pub fn from_span(span: &tracing::Span) -> Self {
61 Self(span.context())
62 }
63
64 /// Create a new tracing context from the current tracing span considered by the subscriber.
65 pub fn from_current_span() -> Self {
66 Self::from_span(&tracing::Span::current())
67 }
68
69 /// Create a no-op tracing context.
70 pub fn new() -> Self {
71 Self(opentelemetry::Context::new())
72 }
73
74 /// Attach the given span as a child of the context. Returns the attached span.
75 pub fn attach(&self, span: tracing::Span) -> tracing::Span {
76 span.set_parent(self.0.clone());
77 span
78 }
79
80 /// Convert the tracing context to the W3C trace context format.
81 pub fn to_w3c(&self) -> W3cTrace {
82 let mut fields = HashMap::new();
83 Propagator::new().inject_context(&self.0, &mut fields);
84 fields
85 }
86
87 /// Create a new tracing context from the W3C trace context format.
88 pub fn from_w3c(fields: &W3cTrace) -> Self {
89 let context = Propagator::new().extract(fields);
90 Self(context)
91 }
92
93 /// Convert the tracing context to a JSON string in W3C trace context format.
94 pub fn to_json(&self) -> String {
95 serde_json::to_string(&self.to_w3c()).unwrap()
96 }
97
98 /// Create a new tracing context from a JSON string in W3C trace context format.
99 ///
100 /// Illegal json string will produce an empty tracing context and no error will be reported.
101 pub fn from_json(json: &str) -> Self {
102 let fields: W3cTrace = serde_json::from_str(json).unwrap_or_default();
103 Self::from_w3c(&fields)
104 }
105}