opentelemetry_derive/lib.rs
1//! # Usage
2//!
3//! Add the crate to your `Cargo.toml`:
4//!
5//! ```toml
6//! opentelemetry_derive = "0.1"
7//! ```
8//!
9//! You also need to have `opentelemetry` as a dependency, because the macros will generate code
10//! that references `opentelemetry::{Key, KeyValue, StringValue, Value}`. The version does not
11//! matter as long as it publishes those types.
12//!
13//! ## `Key`
14//!
15//! If you do not set the key explicitly, the macro will autogenerate one,
16//! which will be your type's name, lowercased:
17//!
18//! ```rust
19//! use opentelemetry_derive::Key;
20//!
21//! #[derive(Key)]
22//! struct Auto;
23//!
24//! #[derive(Key)]
25//! #[otel(key = "custom")]
26//! struct Overriden;
27//! ```
28//!
29//! ## `Value`
30//!
31//! You must specify an intermediate type, into which your own type will be converted,
32//! that is itself already convertible into a [Value]:
33//!
34//! ```rust
35//! use opentelemetry_derive::Value;
36//!
37//! #[derive(Value)]
38//! #[otel(variant = i64)]
39//! struct Counter {
40//! count: i64,
41//! }
42//!
43//! impl From<&Counter> for i64 {
44//! fn from(value: &Counter) -> Self {
45//! value.count
46//! }
47//! }
48//! ```
49//!
50//! ## `StringValue`
51//!
52//! Your type must implement [ToString] (probably through [Display](std::fmt::Display)):
53//!
54//! ```rust
55//! use std::fmt;
56//!
57//! use opentelemetry_derive::StringValue;
58//!
59//! #[derive(StringValue)]
60//! enum Method {
61//! Get,
62//! Post,
63//! }
64//!
65//! impl fmt::Display for Method {
66//! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67//! write!(
68//! f,
69//! "{}",
70//! match self {
71//! Self::Get => "get",
72//! Self::Post => "post",
73//! }
74//! )
75//! }
76//! }
77//! ```
78//!
79//! ## `KeyValue`
80//!
81//! References to your type must be both `Into<Key>` and `Into<Value>`:
82//!
83//! ```rust
84//! use opentelemetry::{Key, Value};
85//! use opentelemetry_derive::KeyValue;
86//!
87//! #[derive(KeyValue)]
88//! struct Config {
89//! value: bool,
90//! }
91//!
92//! const KEY: &str = "config";
93//!
94//! impl From<&Config> for Key {
95//! fn from(_: &Config) -> Self {
96//! Self::from(KEY)
97//! }
98//! }
99//!
100//! impl From<&Config> for Value {
101//! fn from(value: &Config) -> Self {
102//! Value::from(value.value)
103//! }
104//! }
105//! ```
106//!
107//! Of course you can combine all the derives instead of manually implementing the required conversions:
108//!
109//! ```rust
110//! use std::fmt;
111//!
112//! use opentelemetry::StringValue;
113//! use opentelemetry_derive::{Key, KeyValue, StringValue, Value};
114//!
115//! #[derive(Key, KeyValue, StringValue, Value)]
116//! #[otel(key = "req", variant = StringValue)]
117//! struct Request {
118//! query: String,
119//! }
120//!
121//! impl fmt::Display for Request {
122//! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123//! write!(f, "{}", self.query)
124//! }
125//! }
126//! ```
127//!
128//! [Value]: https://docs.rs/opentelemetry/latest/opentelemetry/enum.Value.html
129
130/// Derive conversion into [Key].
131///
132/// The optional `key` attribute overrides the autogenerated key (type name, lowercased).
133///
134/// [Key]: https://docs.rs/opentelemetry/latest/opentelemetry/struct.Key.html
135pub use opentelemetry_derive_impl::Key;
136
137/// Derive conversion into [KeyValue].
138///
139/// [KeyValue]: https://docs.rs/opentelemetry/latest/opentelemetry/struct.KeyValue.html
140pub use opentelemetry_derive_impl::KeyValue;
141
142/// Derive conversion into [StringValue].
143///
144/// [StringValue]: https://docs.rs/opentelemetry/latest/opentelemetry/struct.StringValue.html
145pub use opentelemetry_derive_impl::StringValue;
146
147/// Derive conversion into [Value].
148///
149/// The mandatory `variant` attribute is the intermediate type, into which your value will be converted
150/// (e.g. [StringValue]
151/// if your type should be represented as a string, or [i64]).
152/// This variant should itself be one of the types than can be implicitly converted to [Value].
153///
154/// [StringValue]: https://docs.rs/opentelemetry/latest/opentelemetry/struct.StringValue.html
155/// [Value]: https://docs.rs/opentelemetry/latest/opentelemetry/enum.Value.html
156pub use opentelemetry_derive_impl::Value;
157
158#[cfg(test)]
159mod tests {
160 extern crate self as opentelemetry_derive;
161
162 use std::fmt;
163
164 use opentelemetry::{Key, KeyValue, StringValue, Value};
165
166 use crate::{Key, KeyValue, StringValue, Value};
167
168 #[test]
169 fn test_key() {
170 #[derive(Key)]
171 struct Auto;
172
173 assert_eq!(Key::from(Auto).as_str(), "auto");
174 assert_eq!(Key::from(&Auto).as_str(), "auto");
175
176 #[derive(Key)]
177 #[otel(key = "custom")]
178 struct Overriden;
179
180 assert_eq!(Key::from(Overriden).as_str(), "custom");
181 assert_eq!(Key::from(&Overriden).as_str(), "custom");
182 }
183
184 #[test]
185 fn test_value() {
186 #[derive(Value)]
187 #[otel(variant = i64)]
188 struct Counter {
189 count: i64,
190 }
191
192 impl From<&Counter> for i64 {
193 fn from(value: &Counter) -> Self {
194 value.count
195 }
196 }
197
198 let count = 3;
199 let counter = Counter { count };
200
201 assert_eq!(Value::from(&counter).as_str(), count.to_string());
202 assert_eq!(Value::from(counter).as_str(), count.to_string());
203 }
204
205 #[test]
206 fn test_string_value() {
207 #[derive(StringValue)]
208 enum Method {
209 Get,
210 Post,
211 }
212
213 impl fmt::Display for Method {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(
216 f,
217 "{}",
218 match self {
219 Self::Get => "get",
220 Self::Post => "post",
221 }
222 )
223 }
224 }
225
226 assert_eq!(
227 StringValue::from(&Method::Get).as_str(),
228 Method::Get.to_string()
229 );
230 assert_eq!(
231 StringValue::from(Method::Post).as_str(),
232 Method::Post.to_string()
233 );
234 }
235
236 #[test]
237 fn test_key_value() {
238 #[derive(KeyValue)]
239 struct Config {
240 value: bool,
241 }
242
243 const KEY: &str = "config";
244
245 impl From<&Config> for Key {
246 fn from(_: &Config) -> Self {
247 Self::from(KEY)
248 }
249 }
250
251 impl From<&Config> for Value {
252 fn from(value: &Config) -> Self {
253 Value::from(value.value)
254 }
255 }
256
257 let value = true;
258 let config = Config { value };
259
260 assert_eq!(KeyValue::from(&config), KeyValue::new(KEY, value));
261 assert_eq!(KeyValue::from(config), KeyValue::new(KEY, value));
262 }
263
264 #[test]
265 fn test_all() {
266 #[derive(Key, KeyValue, StringValue, Value)]
267 #[otel(key = "req", variant = StringValue)]
268 struct Request {
269 query: String,
270 }
271
272 impl fmt::Display for Request {
273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 write!(f, "{}", self.query)
275 }
276 }
277
278 let query = "foo=bar";
279 let request = Request {
280 query: query.to_string(),
281 };
282
283 assert_eq!(KeyValue::from(&request), KeyValue::new("req", query));
284 assert_eq!(KeyValue::from(request), KeyValue::new("req", query));
285 }
286}