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}