cf_rustracing/
tag.rs

1//! Span tag.
2use std::borrow::Cow;
3use std::net::{IpAddr, SocketAddr};
4
5/// Span tag.
6#[derive(Debug, Clone)]
7pub struct Tag {
8    name: Cow<'static, str>,
9    value: TagValue,
10}
11impl Tag {
12    /// # Examples
13    ///
14    /// ```
15    /// use cf_rustracing::tag::{Tag, TagValue};
16    ///
17    /// let tag = Tag::new("foo", "bar");
18    /// assert_eq!(tag.name(), "foo");
19    /// assert_eq!(tag.value(), &TagValue::from("bar"));
20    /// ```
21    pub fn new<N, V>(name: N, value: V) -> Self
22    where
23        N: Into<Cow<'static, str>>,
24        V: Into<TagValue>,
25    {
26        Tag {
27            name: name.into(),
28            value: value.into(),
29        }
30    }
31
32    /// Returns the name of this tag.
33    pub fn name(&self) -> &str {
34        self.name.as_ref()
35    }
36
37    /// Returns the value of this tag.
38    pub fn value(&self) -> &TagValue {
39        &self.value
40    }
41}
42
43/// Span tag value.
44#[derive(Debug, Clone, PartialEq, PartialOrd)]
45#[allow(missing_docs)]
46pub enum TagValue {
47    String(Cow<'static, str>),
48    Boolean(bool),
49    Integer(i64),
50    Float(f64),
51}
52impl From<&'static str> for TagValue {
53    fn from(f: &'static str) -> Self {
54        TagValue::String(Cow::Borrowed(f))
55    }
56}
57impl From<String> for TagValue {
58    fn from(f: String) -> Self {
59        TagValue::String(Cow::Owned(f))
60    }
61}
62impl From<Cow<'static, str>> for TagValue {
63    fn from(f: Cow<'static, str>) -> Self {
64        TagValue::String(f)
65    }
66}
67impl From<bool> for TagValue {
68    fn from(f: bool) -> Self {
69        TagValue::Boolean(f)
70    }
71}
72impl From<i64> for TagValue {
73    fn from(f: i64) -> Self {
74        TagValue::Integer(f)
75    }
76}
77impl From<f64> for TagValue {
78    fn from(f: f64) -> Self {
79        TagValue::Float(f)
80    }
81}
82
83/// [Standard span tags][tags].
84/// [tags]: https://github.com/opentracing/specification/blob/master/semantic_conventions.md#span-tags-table
85#[derive(Debug)]
86pub struct StdTag;
87impl StdTag {
88    /// Makes a `"component"` tag.
89    ///
90    /// It indicates the software package, framework, library,
91    /// or module that generated the associated `Span`.
92    ///
93    /// E.g., `"grpc"`, `"django"`, `"JDBI"`.
94    pub fn component<V>(value: V) -> Tag
95    where
96        V: Into<Cow<'static, str>>,
97    {
98        Tag::new("component", value.into())
99    }
100
101    /// Makes a `"db.instance"` tag.
102    ///
103    /// It indicates database instance name.
104    ///
105    /// E.g., In java, if the jdbc.url=`"jdbc:mysql://127.0.0.1:3306/customers"`,
106    /// the instance name is `"customers"`.
107    pub fn db_instance<V>(value: V) -> Tag
108    where
109        V: Into<Cow<'static, str>>,
110    {
111        Tag::new("db.instance", value.into())
112    }
113
114    /// Makes a `"db.statement"` tag.
115    ///
116    /// It indicates a database statement for the given database type.
117    ///
118    /// E.g.,
119    /// for db.type=`"sql"`, `"SELECT * FROM wuser_table"`;
120    /// for db.type=`"redis"`, `"SET mykey 'WuValue'"`.
121    pub fn db_statement<V>(value: V) -> Tag
122    where
123        V: Into<Cow<'static, str>>,
124    {
125        Tag::new("db.statement", value.into())
126    }
127
128    /// Makes a `"db.type"` tag.
129    ///
130    /// It indicates database type.
131    ///
132    /// For any SQL database, `"sql"`.
133    /// For others, the lower-case database category, e.g. `"cassandra"`, `"hbase"`, or `"redis"`.
134    pub fn db_type<V>(value: V) -> Tag
135    where
136        V: Into<Cow<'static, str>>,
137    {
138        Tag::new("db.type", value.into())
139    }
140
141    /// Makes a `"db.user"` tag.
142    ///
143    /// It indicates username for accessing database.
144    ///
145    /// E.g., `"readonly_user"` or `"reporting_user"`
146    pub fn db_user<V>(value: V) -> Tag
147    where
148        V: Into<Cow<'static, str>>,
149    {
150        Tag::new("db.user", value.into())
151    }
152
153    /// Makes a `"error"` tag that has the value `true`.
154    ///
155    /// It indicates the application considers the operation represented by the `Span` to have failed.
156    pub fn error() -> Tag {
157        Tag::new("error", true)
158    }
159
160    /// Makes a `"http.method"` tag.
161    ///
162    /// It indicates HTTP method of the request for the associated `Span`.
163    ///
164    /// E.g., `"GET"`, `"POST"`
165    pub fn http_method<V>(value: V) -> Tag
166    where
167        V: Into<Cow<'static, str>>,
168    {
169        Tag::new("http.method", value.into())
170    }
171
172    /// Makes a `"http.status_code"` tag.
173    ///
174    /// It indicates HTTP response status code for the associated `Span`.
175    ///
176    /// E.g., 200, 503, 404
177    pub fn http_status_code(value: u16) -> Tag {
178        Tag::new("http.status_code", i64::from(value))
179    }
180
181    /// Makes a `"http.url"` tag.
182    ///
183    /// It indicates URL of the request being handled in this segment of the trace, in standard URI format.
184    ///
185    /// E.g., `"https://domain.net/path/to?resource=here"`
186    pub fn http_url<V>(value: V) -> Tag
187    where
188        V: Into<Cow<'static, str>>,
189    {
190        Tag::new("http.url", value.into())
191    }
192
193    /// Makes a `"message_bus.destination" tag.
194    ///
195    /// It indicates an address at which messages can be exchanged.
196    ///
197    /// E.g. A Kafka record has an associated `"topic name"` that can be extracted by
198    /// the instrumented producer or consumer and stored using this tag.
199    pub fn message_bus_destination<V>(value: V) -> Tag
200    where
201        V: Into<Cow<'static, str>>,
202    {
203        Tag::new("message_bus.destination", value.into())
204    }
205
206    /// Makes a `"peer.address"` tag.
207    ///
208    /// It indicates remote "address", suitable for use in a networking client library.
209    ///
210    /// This may be a `"ip:port"`, a bare `"hostname"`, a FQDN,
211    /// or even a JDBC substring like `"mysql://prod-db:3306"`.
212    pub fn peer_address<V>(value: V) -> Tag
213    where
214        V: Into<Cow<'static, str>>,
215    {
216        Tag::new("peer.address", value.into())
217    }
218
219    /// Makes a `"peer.hostname"` tag.
220    ///
221    /// It indicates remote hostname.
222    ///
223    /// E.g., `"opentracing.io"`, `"internal.dns.name"`
224    pub fn peer_hostname<V>(value: V) -> Tag
225    where
226        V: Into<Cow<'static, str>>,
227    {
228        Tag::new("peer.hostname", value.into())
229    }
230
231    /// Makes a `"peer.ipXX"` and `"peer.port"` tags.
232    pub fn peer_addr(value: SocketAddr) -> Vec<Tag> {
233        vec![Self::peer_ip(value.ip()), Self::peer_port(value.port())]
234    }
235
236    /// Makes a tag which has the name either `"peer.ipv4"` or `"peer.ipv6"` depending on the value.
237    ///
238    /// It indicates remote IP address.
239    ///
240    /// E.g., `"127.0.0.1"`, `"2001:0db8:85a3:0000:0000:8a2e:0370:7334"`
241    pub fn peer_ip(value: IpAddr) -> Tag {
242        match value {
243            IpAddr::V4(v) => Tag::new("peer.ipv4", v.to_string()),
244            IpAddr::V6(v) => Tag::new("peer.ipv6", v.to_string()),
245        }
246    }
247
248    /// Makes a `"peer.port"` tag.
249    ///
250    /// It indicates remote port.
251    ///
252    /// E.g., `80`
253    pub fn peer_port(value: u16) -> Tag {
254        Tag::new("peer.port", i64::from(value))
255    }
256
257    /// Makes a `"peer.service"` tag.
258    ///
259    /// It indicates remote service name (for some unspecified definition of `"service"`).
260    ///
261    /// E.g., `"elasticsearch"`, `"a_custom_microservice"`, `"memcache"`
262    pub fn peer_service<V>(value: V) -> Tag
263    where
264        V: Into<Cow<'static, str>>,
265    {
266        Tag::new("peer.service", value.into())
267    }
268
269    /// Makes a `"samplingpriority"` tag.
270    ///
271    /// If greater than `0`, a hint to the `Tracer` to do its best to capture the trace.
272    /// If `0`, a hint to the trace to not-capture the trace.
273    /// If absent, the `Tracer` should use its default sampling mechanism.
274    pub fn sampling_priority(value: u32) -> Tag {
275        Tag::new("sampling.priority", i64::from(value))
276    }
277
278    /// Makes a `"span.ind"` tag.
279    ///
280    /// Either `"client"` or `"server"` for the appropriate roles in an RPC,
281    /// and `"producer"` or `"consumer"` for the appropriate roles in a messaging scenario.
282    pub fn span_kind<V>(value: V) -> Tag
283    where
284        V: Into<Cow<'static, str>>,
285    {
286        Tag::new("span.kind", value.into())
287    }
288}