tracing_serde_structured/
lib.rs

1//! # tracing-serde-structured
2//!
3//! An alternative, structured, adapter for serializing [`tracing`] types using [`serde`].
4//!
5//! [![Documentation][docs-badge]][docs-url]
6//!
7//! [docs-badge]: https://docs.rs/tracing-serde-structured/badge.svg
8//! [docs-url]: https://docs.rs/tracing-serde-structured
9//!
10//! ## Overview
11//!
12//! [`tracing`] is a framework for instrumenting Rust programs to collect
13//! scoped, structured, and async-aware diagnostics.`tracing-serde-structured` enables
14//! serializing `tracing` types using [`serde`].
15//!
16//! Traditional logging is based on human-readable text messages.
17//! `tracing` gives us machine-readable structured diagnostic
18//! information. This lets us interact with diagnostic data
19//! programmatically. With `tracing-serde-structured`, you can implement a
20//! `Subscriber` to serialize your `tracing` types and make use of the
21//! existing ecosystem of `serde` serializers to talk with distributed
22//! tracing systems.
23//!
24//! Serializing diagnostic information allows us to do more with our logged
25//! values. For instance, when working with logging data in JSON gives us
26//! pretty-print when we're debugging in development and you can emit JSON
27//! and tracing data to monitor your services in production.
28//!
29//! The `tracing` crate provides the APIs necessary for instrumenting
30//! libraries and applications to emit trace data.
31//!
32//! ## Differences with the `tracing-serde` crate
33//!
34//! Unlike the upstream [`tracing-serde`] crate, `tracing-serde-structured` does this serialization
35//! in a structured manner, making the data compatible with binary formats such as [`postcard`],
36//! while also allowing deserialization of the data.
37//!
38//! `tracing-serde-structured` is still compatible with serialization and deserialization to/from
39//! JSON, though it does change the format of the JSON data, meaning it is not a 100% drop-in replacement.
40//!
41//! [`tracing-serde`]: https://docs.rs/tracing-serde
42//! [`postcard`]: https://docs.rs/postcard
43//!
44//! ## Usage
45//!
46//! First, add this to your `Cargo.toml`:
47//!
48//! ```toml
49//! [dependencies]
50//! tracing = "0.1"
51//! tracing-serde-structured = "0.1"
52//! ```
53//!
54//! Next, add this to your crate:
55//!
56//! ```rust
57//! use tracing_serde_structured::AsSerde;
58//! ```
59//!
60//! Please read the [`tracing` documentation](https://docs.rs/tracing/latest/tracing/index.html)
61//! for more information on how to create trace data.
62//!
63//! This crate provides the `as_serde` function, via the `AsSerde` trait,
64//! which enables serializing the `Attributes`, `Event`, `Id`, `Metadata`,
65//! and `Record` `tracing` values.
66//!
67//! Implement a `Subscriber` to format the serialization of `tracing`
68//! types how you'd like.
69//!
70//! ```rust
71//! # use tracing_core::{Subscriber, Metadata, Event};
72//! # use tracing_core::span::{Attributes, Id, Record};
73//! # use std::sync::atomic::{AtomicUsize, Ordering};
74//! use tracing_serde_structured::AsSerde;
75//! use serde_json::json;
76//!
77//! pub struct JsonSubscriber {
78//!     next_id: AtomicUsize, // you need to assign span IDs, so you need a counter
79//! }
80//!
81//! impl Subscriber for JsonSubscriber {
82//!
83//!     fn new_span(&self, attrs: &Attributes<'_>) -> Id {
84//!         let id = self.next_id.fetch_add(1, Ordering::Relaxed);
85//!         let id = Id::from_u64(id as u64);
86//!         let json = json!({
87//!         "new_span": {
88//!             "attributes": attrs.as_serde(),
89//!             "id": id.as_serde(),
90//!         }});
91//!         println!("{}", json);
92//!         id
93//!     }
94//!
95//!     fn event(&self, event: &Event<'_>) {
96//!         let json = json!({
97//!            "event": event.as_serde(),
98//!         });
99//!         println!("{}", json);
100//!     }
101//!
102//!     // ...
103//!     # fn enabled(&self, _: &Metadata<'_>) -> bool { false }
104//!     # fn enter(&self, _: &Id) {}
105//!     # fn exit(&self, _: &Id) {}
106//!     # fn record(&self, _: &Id, _: &Record<'_>) {}
107//!     # fn record_follows_from(&self, _: &Id, _: &Id) {}
108//! }
109//! ```
110//!
111//! After you implement your `Subscriber`, you can use your `tracing`
112//! subscriber (`JsonSubscriber` in the above example) to record serialized
113//! trace data.
114//!
115//! ##  Crate Feature Flags
116//!
117//! The following crate feature flags are available:
118//!
119//! * `std`: Depend on the Rust standard library (enabled by default).
120//!
121//!   `no_std` users may disable this feature with `default-features = false`:
122//!
123//!   ```toml
124//!   [dependencies]
125//!   tracing-serde = { version = "0.2", default-features = false }
126//!   ```
127//!
128//! ### Unstable Features
129//!
130//! These feature flags enable **unstable** features. The public API may break in 0.1.x
131//! releases. To enable these features, the `--cfg tracing_unstable` must be passed to
132//! `rustc` when compiling.
133//!
134//! The following unstable feature flags are currently available:
135//!
136//! * `valuable`: Enables [`Visit::record_value`] implementations, for
137//!   serializing values recorded using the [`valuable`] crate.
138//!
139//! #### Enabling Unstable Features
140//!
141//! The easiest way to set the `tracing_unstable` cfg is to use the `RUSTFLAGS`
142//! env variable when running `cargo` commands:
143//!
144//! ```shell
145//! RUSTFLAGS="--cfg tracing_unstable" cargo build
146//! ```
147//! Alternatively, the following can be added to the `.cargo/config` file in a
148//! project to automatically enable the cfg flag for that project:
149//!
150//! ```toml
151//! [build]
152//! rustflags = ["--cfg", "tracing_unstable"]
153//! ```
154//!
155//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
156//! [`valuable`]: https://crates.io/crates/valuable
157//!
158//! ## Provenance
159//!
160//! This crate is a fork of the [`tracing-serde`] library, as provided by the Tokio project.
161//!
162//! ## License
163//!
164//! This project is licensed under the [MIT license](LICENSE).
165//!
166//! ### Contribution
167//!
168//! Unless you explicitly state otherwise, any contribution intentionally submitted
169//! for inclusion in this project by you, shall be licensed as MIT, without any additional
170//! terms or conditions.
171//!
172//! [`tracing`]: https://crates.io/crates/tracing
173//! [`serde`]: https://crates.io/crates/serde
174#![doc(html_root_url = "https://docs.rs/tracing-serde-structured/0.1.3")]
175#![doc(
176    html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
177    html_favicon_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/favicon.ico",
178    issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
179)]
180#![cfg_attr(docsrs, feature(doc_cfg))]
181#![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
182#![warn(
183    missing_debug_implementations,
184    // missing_docs, // TODO: add documentation
185    rust_2018_idioms,
186    unreachable_pub,
187    bad_style,
188    dead_code,
189    improper_ctypes,
190    non_shorthand_field_patterns,
191    no_mangle_generic_items,
192    overflowing_literals,
193    path_statements,
194    patterns_in_fns_without_body,
195    // private_in_public,
196    unconditional_recursion,
197    unused,
198    unused_allocation,
199    unused_comparisons,
200    unused_parens,
201    while_true
202)]
203// Support using tracing-serde without the standard library!
204#![cfg_attr(not(feature = "std"), no_std)]
205
206use core::fmt;
207use core::fmt::Arguments;
208use core::hash::Hash;
209use core::num::NonZeroU64;
210use core::ops::Deref;
211
212use serde::{
213    ser::{SerializeMap, SerializeSeq, Serializer},
214    Deserialize, Serialize,
215};
216
217use tracing_core::{
218    event::Event,
219    field::{Field, FieldSet, Visit},
220    metadata::{Level, Metadata},
221    span::{Attributes, Id, Record},
222};
223
224#[cfg(feature = "postcard-schema")]
225impl<'a> postcard_schema::Schema for CowString<'a> {
226    const SCHEMA: &'static postcard_schema::schema::NamedType =
227        &postcard_schema::schema::NamedType {
228            name: "CowString",
229            ty: <&str>::SCHEMA.ty,
230        };
231}
232
233#[derive(Debug, Deserialize, Eq, PartialOrd, Ord)]
234#[serde(from = "&'a str")]
235pub enum CowString<'a> {
236    Borrowed(&'a str),
237    #[cfg(feature = "std")]
238    Owned(String),
239}
240
241impl<'a> Deref for CowString<'a> {
242    type Target = str;
243
244    fn deref(&self) -> &Self::Target {
245        self.as_str()
246    }
247}
248
249impl<'a> CowString<'a> {
250    pub fn as_str(&'a self) -> &'a str {
251        match self {
252            CowString::Borrowed(b) => b,
253            #[cfg(feature = "std")]
254            CowString::Owned(o) => o.as_str(),
255        }
256    }
257}
258
259#[cfg(feature = "std")]
260impl<'a> CowString<'a> {
261    pub fn to_owned(&'a self) -> CowString<'static> {
262        CowString::Owned(self.as_str().to_string())
263    }
264}
265
266impl<'a> Hash for CowString<'a> {
267    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
268        self.as_str().hash(state)
269    }
270}
271
272impl<'a> hash32::Hash for CowString<'a> {
273    fn hash<H>(&self, state: &mut H)
274    where
275        H: hash32::Hasher,
276    {
277        <str as hash32::Hash>::hash(self.as_str(), state)
278    }
279}
280
281impl<'a> PartialEq for CowString<'a> {
282    fn eq(&self, other: &Self) -> bool {
283        self.as_str().eq(other.as_str())
284    }
285}
286
287impl<'a> From<&'a str> for CowString<'a> {
288    fn from(other: &'a str) -> Self {
289        Self::Borrowed(other)
290    }
291}
292
293impl<'a> Serialize for CowString<'a> {
294    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
295    where
296        S: Serializer,
297    {
298        self.as_str().serialize(serializer)
299    }
300}
301
302#[cfg(not(feature = "std"))]
303type TracingVec<T> = heapless::Vec<T, 32>;
304
305#[cfg(not(feature = "std"))]
306type TracingMap<K, V> = heapless::FnvIndexMap<K, V, 32>;
307
308#[cfg(feature = "std")]
309type TracingVec<T> = std::vec::Vec<T>;
310
311#[cfg(feature = "std")]
312type TracingMap<K, V> = std::collections::BTreeMap<K, V>;
313
314#[derive(Debug, Deserialize)]
315#[serde(from = "TracingVec<CowString<'a>>")]
316pub enum SerializeFieldSet<'a> {
317    Ser(&'a FieldSet),
318    #[serde(borrow)]
319    De(TracingVec<CowString<'a>>),
320}
321
322impl<'a> Serialize for SerializeFieldSet<'a> {
323    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
324    where
325        S: Serializer,
326    {
327        match self {
328            SerializeFieldSet::Ser(sfs) => {
329                let mut seq = serializer.serialize_seq(Some(sfs.len()))?;
330                for element in sfs.iter() {
331                    seq.serialize_element(element.name())?;
332                }
333                seq.end()
334            }
335            SerializeFieldSet::De(dfs) => dfs.serialize(serializer),
336        }
337    }
338}
339
340impl<'a> From<TracingVec<CowString<'a>>> for SerializeFieldSet<'a> {
341    fn from(other: TracingVec<CowString<'a>>) -> Self {
342        SerializeFieldSet::De(other)
343    }
344}
345
346#[cfg(feature = "postcard-schema")]
347impl<'a> postcard_schema::Schema for SerializeFieldSet<'a> {
348    const SCHEMA: &'static postcard_schema::schema::NamedType =
349        &postcard_schema::schema::NamedType {
350            name: "SerializeFieldSet",
351            ty: &postcard_schema::schema::DataModelType::Seq(CowString::SCHEMA),
352        };
353}
354
355#[repr(usize)]
356#[cfg_attr(
357    feature = "postcard-schema",
358    derive(postcard_schema::Schema)
359)]
360#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
361#[serde(rename_all = "UPPERCASE")]
362pub enum SerializeLevel {
363    /// The "trace" level.
364    ///
365    /// Designates very low priority, often extremely verbose, information.
366    Trace = 0,
367    /// The "debug" level.
368    ///
369    /// Designates lower priority information.
370    Debug = 1,
371    /// The "info" level.
372    ///
373    /// Designates useful information.
374    Info = 2,
375    /// The "warn" level.
376    ///
377    /// Designates hazardous situations.
378    Warn = 3,
379    /// The "error" level.
380    ///
381    /// Designates very serious errors.
382    Error = 4,
383}
384
385#[derive(Debug, Serialize, Deserialize, Clone)]
386#[cfg_attr(
387    feature = "postcard-schema",
388    derive(postcard_schema::Schema)
389)]
390pub struct SerializeId {
391    pub id: NonZeroU64,
392}
393
394#[derive(Debug, Serialize, Deserialize)]
395#[cfg_attr(
396    feature = "postcard-schema",
397    derive(postcard_schema::Schema)
398)]
399pub struct SerializeMetadata<'a> {
400    #[serde(borrow)]
401    pub name: CowString<'a>,
402    pub target: CowString<'a>,
403    pub level: SerializeLevel,
404    pub module_path: Option<CowString<'a>>,
405    pub file: Option<CowString<'a>>,
406    pub line: Option<u32>,
407    pub fields: SerializeFieldSet<'a>,
408    pub is_span: bool,
409    pub is_event: bool,
410}
411
412/// Implements `serde::Serialize` to write `Event` data to a serializer.
413#[derive(Debug, Serialize, Deserialize)]
414#[cfg_attr(
415    feature = "postcard-schema",
416    derive(postcard_schema::Schema)
417)]
418pub struct SerializeEvent<'a> {
419    #[serde(borrow)]
420    pub fields: SerializeRecordFields<'a>,
421    pub metadata: SerializeMetadata<'a>,
422    pub parent: Option<SerializeId>,
423}
424
425/// Implements `serde::Serialize` to write `Attributes` data to a serializer.
426#[derive(Debug, Serialize, Deserialize)]
427#[cfg_attr(
428    feature = "postcard-schema",
429    derive(postcard_schema::Schema)
430)]
431pub struct SerializeAttributes<'a> {
432    #[serde(borrow)]
433    pub metadata: SerializeMetadata<'a>,
434    pub parent: Option<SerializeId>,
435    pub is_root: bool,
436}
437
438type RecordMap<'a> = TracingMap<CowString<'a>, SerializeValue<'a>>;
439
440/// Implements `serde::Serialize` to write `Record` data to a serializer.
441#[derive(Debug, Deserialize)]
442#[serde(from = "RecordMap<'a>")]
443pub enum SerializeRecord<'a> {
444    #[serde(borrow)]
445    Ser(&'a Record<'a>),
446    De(RecordMap<'a>),
447}
448
449impl<'a> Serialize for SerializeRecord<'a> {
450    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
451    where
452        S: Serializer,
453    {
454        match self {
455            SerializeRecord::Ser(serf) => {
456                let items = serf.len();
457
458                let serializer = serializer.serialize_map(Some(items))?;
459                let mut ssv = SerdeMapVisitor::new(serializer);
460                serf.record(&mut ssv);
461                ssv.finish()
462            }
463            SerializeRecord::De(derf) => derf.serialize(serializer),
464        }
465    }
466}
467
468impl<'a> From<RecordMap<'a>> for SerializeRecord<'a> {
469    fn from(other: RecordMap<'a>) -> Self {
470        Self::De(other)
471    }
472}
473
474#[cfg(feature = "postcard-schema")]
475impl<'a> postcard_schema::Schema for SerializeRecord<'a> {
476    const SCHEMA: &'static postcard_schema::schema::NamedType =
477        &postcard_schema::schema::NamedType {
478            name: "SerializeRecord",
479            ty: &postcard_schema::schema::DataModelType::Map {
480                key: CowString::SCHEMA,
481                val: SerializeValue::SCHEMA,
482            },
483        };
484}
485
486#[derive(Debug, Serialize, Deserialize)]
487#[non_exhaustive]
488#[cfg_attr(
489    feature = "postcard-schema",
490    derive(postcard_schema::Schema)
491)]
492pub enum SerializeValue<'a> {
493    #[serde(borrow)]
494    Debug(DebugRecord<'a>),
495    Str(CowString<'a>),
496    F64(f64),
497    I64(i64),
498    U64(u64),
499    Bool(bool),
500}
501
502#[derive(Debug, Deserialize)]
503#[serde(from = "CowString<'a>")]
504pub enum DebugRecord<'a> {
505    #[serde(borrow)]
506    Ser(&'a Arguments<'a>),
507    De(CowString<'a>),
508}
509
510impl<'a> From<CowString<'a>> for DebugRecord<'a> {
511    fn from(other: CowString<'a>) -> Self {
512        Self::De(other)
513    }
514}
515
516impl<'a> Serialize for DebugRecord<'a> {
517    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
518    where
519        S: Serializer,
520    {
521        match self {
522            DebugRecord::Ser(args) => args.serialize(serializer),
523            DebugRecord::De(msg) => msg.serialize(serializer),
524        }
525    }
526}
527
528#[cfg(feature = "postcard-schema")]
529impl<'a> postcard_schema::Schema for DebugRecord<'a> {
530    const SCHEMA: &'static postcard_schema::schema::NamedType =
531        &postcard_schema::schema::NamedType {
532            name: "DebugRecord",
533            ty: CowString::SCHEMA.ty,
534        };
535}
536
537#[derive(Debug, Deserialize)]
538#[serde(from = "RecordMap<'a>")]
539pub enum SerializeRecordFields<'a> {
540    #[serde(borrow)]
541    Ser(&'a Event<'a>),
542    De(RecordMap<'a>),
543}
544
545impl<'a> From<RecordMap<'a>> for SerializeRecordFields<'a> {
546    fn from(other: RecordMap<'a>) -> Self {
547        Self::De(other)
548    }
549}
550
551impl<'a> Serialize for SerializeRecordFields<'a> {
552    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
553    where
554        S: Serializer,
555    {
556        match self {
557            SerializeRecordFields::Ser(serf) => {
558                let items = serf.fields().count();
559
560                let serializer = serializer.serialize_map(Some(items))?;
561                let mut ssv = SerdeMapVisitor::new(serializer);
562                serf.record(&mut ssv);
563                ssv.finish()
564            }
565            SerializeRecordFields::De(derf) => derf.serialize(serializer),
566        }
567    }
568}
569
570#[cfg(feature = "postcard-schema")]
571impl<'a> postcard_schema::Schema for SerializeRecordFields<'a> {
572    const SCHEMA: &'static postcard_schema::schema::NamedType =
573        &postcard_schema::schema::NamedType {
574            name: "SerializeRecordFields",
575            ty: &postcard_schema::schema::DataModelType::Map {
576                key: CowString::SCHEMA,
577                val: SerializeValue::SCHEMA,
578            },
579        };
580}
581
582/// Implements `tracing_core::field::Visit` for some `serde::ser::SerializeMap`.
583#[derive(Debug)]
584pub struct SerdeMapVisitor<S: SerializeMap> {
585    serializer: S,
586    state: Result<(), S::Error>,
587}
588
589impl<S> SerdeMapVisitor<S>
590where
591    S: SerializeMap,
592{
593    /// Create a new map visitor.
594    pub fn new(serializer: S) -> Self {
595        Self {
596            serializer,
597            state: Ok(()),
598        }
599    }
600
601    /// Completes serializing the visited object, returning `Ok(())` if all
602    /// fields were serialized correctly, or `Error(S::Error)` if a field could
603    /// not be serialized.
604    pub fn finish(self) -> Result<S::Ok, S::Error> {
605        self.state?;
606        self.serializer.end()
607    }
608
609    /// Completes serializing the visited object, returning ownership of the underlying serializer
610    /// if all fields were serialized correctly, or `Err(S::Error)` if a field could not be
611    /// serialized.
612    pub fn take_serializer(self) -> Result<S, S::Error> {
613        self.state?;
614        Ok(self.serializer)
615    }
616}
617
618impl<S> Visit for SerdeMapVisitor<S>
619where
620    S: SerializeMap,
621{
622    #[cfg(all(tracing_unstable, feature = "valuable"))]
623    #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
624    fn record_value(&mut self, field: &Field, value: valuable_crate::Value<'_>) {
625        if self.state.is_ok() {
626            self.state = self
627                .serializer
628                .serialize_entry(field.name(), &valuable_serde::Serializable::new(value));
629        }
630    }
631
632    fn record_bool(&mut self, field: &Field, value: bool) {
633        // If previous fields serialized successfully, continue serializing,
634        // otherwise, short-circuit and do nothing.
635        if self.state.is_ok() {
636            self.state = self
637                .serializer
638                .serialize_entry(field.name(), &SerializeValue::Bool(value))
639        }
640    }
641
642    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
643        if self.state.is_ok() {
644            self.state = self.serializer.serialize_entry(
645                field.name(),
646                &SerializeValue::Debug(DebugRecord::Ser(&format_args!("{:?}", value))),
647            )
648        }
649    }
650
651    fn record_u64(&mut self, field: &Field, value: u64) {
652        if self.state.is_ok() {
653            self.state = self
654                .serializer
655                .serialize_entry(field.name(), &SerializeValue::U64(value))
656        }
657    }
658
659    fn record_i64(&mut self, field: &Field, value: i64) {
660        if self.state.is_ok() {
661            self.state = self
662                .serializer
663                .serialize_entry(field.name(), &SerializeValue::I64(value))
664        }
665    }
666
667    fn record_f64(&mut self, field: &Field, value: f64) {
668        if self.state.is_ok() {
669            self.state = self
670                .serializer
671                .serialize_entry(field.name(), &SerializeValue::F64(value))
672        }
673    }
674
675    fn record_str(&mut self, field: &Field, value: &str) {
676        if self.state.is_ok() {
677            self.state = self
678                .serializer
679                .serialize_entry(field.name(), &SerializeValue::Str(value.into()))
680        }
681    }
682}
683
684pub trait AsSerde<'a>: self::sealed::Sealed {
685    type Serializable: serde::Serialize + 'a;
686
687    /// `as_serde` borrows a `tracing` value and returns the serialized value.
688    fn as_serde(&'a self) -> Self::Serializable;
689}
690
691impl<'a> AsSerde<'a> for tracing_core::Metadata<'a> {
692    type Serializable = SerializeMetadata<'a>;
693
694    fn as_serde(&'a self) -> Self::Serializable {
695        SerializeMetadata {
696            name: self.name().into(),
697            target: self.target().into(),
698            level: self.level().as_serde(),
699            module_path: self.module_path().map(Into::into),
700            file: self.file().map(Into::into),
701            line: self.line(),
702            fields: SerializeFieldSet::Ser(self.fields()),
703            is_span: self.is_span(),
704            is_event: self.is_event(),
705        }
706    }
707}
708
709/// SAFETY: If all data is 'static and/or owned, it is safe
710/// to send between threads.
711unsafe impl Send for SerializeFieldSet<'static> {}
712
713#[cfg(feature = "std")]
714impl<'a> SerializeFieldSet<'a> {
715    pub fn to_owned(&self) -> SerializeFieldSet<'static> {
716        match self {
717            SerializeFieldSet::Ser(sfs) => SerializeFieldSet::De(
718                sfs.iter()
719                    .map(|i| CowString::from(i.name()).to_owned())
720                    .collect(),
721            ),
722            SerializeFieldSet::De(dfs) => {
723                SerializeFieldSet::De(dfs.iter().map(CowString::to_owned).collect())
724            }
725        }
726    }
727}
728
729/// SAFETY: If all data is 'static and/or owned, it is safe
730/// to send between threads.
731unsafe impl Send for SerializeMetadata<'static> {}
732
733#[cfg(feature = "std")]
734impl<'a> SerializeMetadata<'a> {
735    pub fn to_owned(&self) -> SerializeMetadata<'static> {
736        SerializeMetadata {
737            name: self.name.to_owned(),
738            target: self.target.to_owned(),
739            level: self.level,
740            module_path: self.module_path.as_ref().map(CowString::to_owned),
741            file: self.file.as_ref().map(CowString::to_owned),
742            line: self.line,
743            fields: self.fields.to_owned(),
744            is_span: self.is_span,
745            is_event: self.is_event,
746        }
747    }
748}
749
750impl<'a> AsSerde<'a> for tracing_core::Event<'a> {
751    type Serializable = SerializeEvent<'a>;
752
753    fn as_serde(&'a self) -> Self::Serializable {
754        SerializeEvent {
755            fields: SerializeRecordFields::Ser(self),
756            metadata: self.metadata().as_serde(),
757            parent: self.parent().map(|p| p.as_serde()),
758        }
759    }
760}
761
762/// SAFETY: If all data is 'static and/or owned, it is safe
763/// to send between threads.
764unsafe impl Send for DebugRecord<'static> {}
765
766#[cfg(feature = "std")]
767impl<'a> DebugRecord<'a> {
768    pub fn to_owned(&self) -> DebugRecord<'static> {
769        match self {
770            DebugRecord::Ser(args) => DebugRecord::De(CowString::Owned(args.to_string())),
771            DebugRecord::De(d) => DebugRecord::De(d.to_owned()),
772        }
773    }
774}
775
776/// SAFETY: If all data is 'static and/or owned, it is safe
777/// to send between threads.
778unsafe impl Send for SerializeValue<'static> {}
779
780#[cfg(feature = "std")]
781impl<'a> SerializeValue<'a> {
782    pub fn to_owned(&self) -> SerializeValue<'static> {
783        match self {
784            SerializeValue::Debug(dr) => SerializeValue::Debug(dr.to_owned()),
785            SerializeValue::Str(s) => SerializeValue::Str(s.to_owned()),
786            SerializeValue::F64(x) => SerializeValue::F64(*x),
787            SerializeValue::I64(x) => SerializeValue::I64(*x),
788            SerializeValue::U64(x) => SerializeValue::U64(*x),
789            SerializeValue::Bool(x) => SerializeValue::Bool(*x),
790        }
791    }
792}
793
794#[cfg(feature = "std")]
795struct HashVisit(std::collections::BTreeMap<CowString<'static>, SerializeValue<'static>>);
796
797#[cfg(feature = "std")]
798impl Visit for HashVisit {
799    fn record_bool(&mut self, field: &Field, value: bool) {
800        self.0.insert(
801            CowString::Owned(field.name().to_string()),
802            SerializeValue::Bool(value),
803        );
804    }
805
806    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
807        self.0.insert(
808            CowString::Owned(field.name().to_string()),
809            SerializeValue::Debug(DebugRecord::De(CowString::Owned(format!("{:?}", value)))),
810        );
811    }
812
813    fn record_u64(&mut self, field: &Field, value: u64) {
814        self.0.insert(
815            CowString::Owned(field.name().to_string()),
816            SerializeValue::U64(value),
817        );
818    }
819
820    fn record_i64(&mut self, field: &Field, value: i64) {
821        self.0.insert(
822            CowString::Owned(field.name().to_string()),
823            SerializeValue::I64(value),
824        );
825    }
826
827    fn record_f64(&mut self, field: &Field, value: f64) {
828        self.0.insert(
829            CowString::Owned(field.name().to_string()),
830            SerializeValue::F64(value),
831        );
832    }
833
834    fn record_str(&mut self, field: &Field, value: &str) {
835        self.0.insert(
836            CowString::Owned(field.name().to_string()),
837            SerializeValue::Str(CowString::Owned(value.to_string())),
838        );
839    }
840}
841
842/// SAFETY: If all data is 'static and/or owned, it is safe
843/// to send between threads.
844unsafe impl Send for SerializeRecordFields<'static> {}
845
846#[cfg(feature = "std")]
847impl<'a> SerializeRecordFields<'a> {
848    pub fn to_owned(&self) -> SerializeRecordFields<'static> {
849        match self {
850            SerializeRecordFields::Ser(e) => {
851                let mut hv = HashVisit(std::collections::BTreeMap::new());
852                e.record(&mut hv);
853                SerializeRecordFields::De(hv.0)
854            }
855            SerializeRecordFields::De(dsrf) => SerializeRecordFields::De(
856                dsrf.iter()
857                    .map(|(k, v)| (k.to_owned(), v.to_owned()))
858                    .collect(),
859            ),
860        }
861    }
862}
863
864/// SAFETY: If all data is 'static and/or owned, it is safe
865/// to send between threads.
866unsafe impl Send for SerializeEvent<'static> {}
867
868#[cfg(feature = "std")]
869impl<'a> SerializeEvent<'a> {
870    pub fn to_owned(&self) -> SerializeEvent<'static> {
871        SerializeEvent {
872            fields: self.fields.to_owned(),
873            metadata: self.metadata.to_owned(),
874            parent: self.parent.clone(),
875        }
876    }
877}
878
879impl<'a> AsSerde<'a> for tracing_core::span::Attributes<'a> {
880    type Serializable = SerializeAttributes<'a>;
881
882    fn as_serde(&'a self) -> Self::Serializable {
883        SerializeAttributes {
884            metadata: self.metadata().as_serde(),
885            parent: self.parent().map(|p| p.as_serde()),
886            is_root: self.is_root(),
887        }
888    }
889}
890
891/// SAFETY: If all data is 'static and/or owned, it is safe
892/// to send between threads.
893unsafe impl Send for SerializeAttributes<'static> {}
894
895#[cfg(feature = "std")]
896impl<'a> SerializeAttributes<'a> {
897    pub fn to_owned(&self) -> SerializeAttributes<'static> {
898        SerializeAttributes {
899            metadata: self.metadata.to_owned(),
900            parent: self.parent.clone(),
901            is_root: self.is_root,
902        }
903    }
904}
905
906impl<'a> AsSerde<'a> for tracing_core::span::Id {
907    type Serializable = SerializeId;
908
909    fn as_serde(&'a self) -> Self::Serializable {
910        SerializeId {
911            id: self.into_non_zero_u64(),
912        }
913    }
914}
915
916#[cfg(feature = "std")]
917impl SerializeId {
918    pub fn to_owned(&self) -> Self {
919        self.clone()
920    }
921}
922
923impl<'a> AsSerde<'a> for tracing_core::span::Record<'a> {
924    type Serializable = SerializeRecord<'a>;
925
926    fn as_serde(&'a self) -> Self::Serializable {
927        SerializeRecord::Ser(self)
928    }
929}
930
931/// SAFETY: If all data is 'static and/or owned, it is safe
932/// to send between threads.
933unsafe impl Send for SerializeRecord<'static> {}
934
935#[cfg(feature = "std")]
936impl<'a> SerializeRecord<'a> {
937    pub fn to_owned(&self) -> SerializeRecord<'static> {
938        match self {
939            SerializeRecord::Ser(s) => {
940                let mut hv = HashVisit(std::collections::BTreeMap::new());
941                s.record(&mut hv);
942                SerializeRecord::De(hv.0)
943            }
944            SerializeRecord::De(d) => SerializeRecord::De(
945                d.iter()
946                    .map(|(k, v)| (k.to_owned(), v.to_owned()))
947                    .collect(),
948            ),
949        }
950    }
951}
952
953impl<'a> AsSerde<'a> for Level {
954    type Serializable = SerializeLevel;
955
956    fn as_serde(&'a self) -> Self::Serializable {
957        match *self {
958            Level::ERROR => SerializeLevel::Error,
959            Level::WARN => SerializeLevel::Warn,
960            Level::INFO => SerializeLevel::Info,
961            Level::DEBUG => SerializeLevel::Debug,
962            Level::TRACE => SerializeLevel::Trace,
963        }
964    }
965}
966
967#[cfg(feature = "std")]
968impl SerializeLevel {
969    pub fn to_owned(&self) -> Self {
970        *self
971    }
972}
973
974impl<'a> self::sealed::Sealed for Event<'a> {}
975
976impl<'a> self::sealed::Sealed for Attributes<'a> {}
977
978impl self::sealed::Sealed for Id {}
979
980impl self::sealed::Sealed for Level {}
981
982impl<'a> self::sealed::Sealed for Record<'a> {}
983
984impl<'a> self::sealed::Sealed for Metadata<'a> {}
985
986mod sealed {
987    pub trait Sealed {}
988}