diff --git a/.github/workflows/check_msrv.yml b/.github/workflows/check_msrv.yml index be257bfd30..9130711a21 100644 --- a/.github/workflows/check_msrv.yml +++ b/.github/workflows/check_msrv.yml @@ -43,7 +43,24 @@ jobs: uses: actions-rs/cargo@v1 with: command: check - args: --all --exclude=tracing-appender + args: --all --exclude=tracing-appender --exclude=tracing-serde + + # TODO: remove this once tracing's MSRV is bumped. + check-msrv-serde: + # Run `cargo check` on our minimum supported Rust version (1.53.0). + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + - uses: actions-rs/toolchain@v1 + with: + toolchain: 1.51.0 + profile: minimal + override: true + - name: Check + uses: actions-rs/cargo@v1 + with: + command: check + args: --lib=tracing-serde # TODO: remove this once tracing's MSRV is bumped. check-msrv-appender: @@ -60,4 +77,4 @@ jobs: uses: actions-rs/cargo@v1 with: command: check - args: --lib=tracing-appender \ No newline at end of file + args: --lib=tracing-appender diff --git a/tracing-core/src/field.rs b/tracing-core/src/field.rs index 39979ab2af..2dabcef755 100644 --- a/tracing-core/src/field.rs +++ b/tracing-core/src/field.rs @@ -808,6 +808,19 @@ impl<'a> ValueSet<'a> { } } + /// Returns the number of fields in this `ValueSet` that would be visited + /// by a given [visitor] to the [`ValueSet::record()`] method. + /// + /// [visitor]: Visit + /// [`ValueSet::record()`]: ValueSet::record() + pub fn record_len(&self) -> usize { + let my_callsite = self.callsite(); + self.values + .iter() + .filter(|(field, _)| field.callsite() == my_callsite) + .count() + } + /// Returns `true` if this `ValueSet` contains a value for the given `Field`. pub(crate) fn contains(&self, field: &Field) -> bool { field.callsite() == self.callsite() diff --git a/tracing-core/src/span.rs b/tracing-core/src/span.rs index 1113eabe39..eaf588cb4d 100644 --- a/tracing-core/src/span.rs +++ b/tracing-core/src/span.rs @@ -221,11 +221,19 @@ impl<'a> Record<'a> { /// Records all the fields in this `Record` with the provided [Visitor]. /// - /// [visitor]: super::field::Visit + /// [Visitor]: super::field::Visit pub fn record(&self, visitor: &mut dyn field::Visit) { self.values.record(visitor) } + /// Returns the number of fields that would be visited from this `Record` + /// when [`Record::record()`] is called + /// + /// [`Record::record()`]: Record::record() + pub fn record_len(&self) -> usize { + self.values.record_len() + } + /// Returns `true` if this `Record` contains a value for the given `Field`. pub fn contains(&self, field: &field::Field) -> bool { self.values.contains(field) diff --git a/tracing-serde/Cargo.toml b/tracing-serde/Cargo.toml index b2b02baa71..8e2e1e9a77 100644 --- a/tracing-serde/Cargo.toml +++ b/tracing-serde/Cargo.toml @@ -16,15 +16,17 @@ categories = [ "encoding", ] keywords = ["logging", "tracing", "serialization"] -rust-version = "1.49.0" +rust-version = "1.51.0" [features] default = ["std"] std = ["serde/std", "tracing-core/std"] [dependencies] -serde = { version = "1", default-features = false, features = ["alloc"] } +serde = { version = "1", default-features = false, features = ["alloc", "derive"] } tracing-core = { path = "../tracing-core", version = "0.2", default-features = false } +heapless = { version = "0.7.10", features = ["serde"] } +hash32 = "0.2.1" [dev-dependencies] serde_json = "1" diff --git a/tracing-serde/src/fields.rs b/tracing-serde/src/fields.rs deleted file mode 100644 index eedc72d6b1..0000000000 --- a/tracing-serde/src/fields.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Support for serializing fields as `serde` structs or maps. -use super::*; - -#[derive(Debug)] -pub struct SerializeFieldMap<'a, T>(&'a T); - -pub trait AsMap: Sized + sealed::Sealed { - fn field_map(&self) -> SerializeFieldMap<'_, Self> { - SerializeFieldMap(self) - } -} - -impl<'a> AsMap for Event<'a> {} -impl<'a> AsMap for Attributes<'a> {} -impl<'a> AsMap for Record<'a> {} - -// === impl SerializeFieldMap === - -impl<'a> Serialize for SerializeFieldMap<'a, Event<'_>> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let len = self.0.fields().count(); - let serializer = serializer.serialize_map(Some(len))?; - let mut visitor = SerdeMapVisitor::new(serializer); - self.0.record(&mut visitor); - visitor.finish() - } -} - -impl<'a> Serialize for SerializeFieldMap<'a, Attributes<'_>> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let len = self.0.metadata().fields().len(); - let serializer = serializer.serialize_map(Some(len))?; - let mut visitor = SerdeMapVisitor::new(serializer); - self.0.record(&mut visitor); - visitor.finish() - } -} - -impl<'a> Serialize for SerializeFieldMap<'a, Record<'_>> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let serializer = serializer.serialize_map(None)?; - let mut visitor = SerdeMapVisitor::new(serializer); - self.0.record(&mut visitor); - visitor.finish() - } -} diff --git a/tracing-serde/src/lib.rs b/tracing-serde/src/lib.rs index 5a90ee5fa5..0dc137c3c8 100644 --- a/tracing-serde/src/lib.rs +++ b/tracing-serde/src/lib.rs @@ -173,10 +173,14 @@ #![cfg_attr(not(feature = "std"), no_std)] use core::fmt; +use core::fmt::Arguments; +use core::hash::Hash; +use core::num::NonZeroU64; +use core::ops::Deref; use serde::{ - ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTupleStruct, Serializer}, - Serialize, + ser::{SerializeMap, SerializeSeq, Serializer}, + Deserialize, Serialize, }; use tracing_core::{ @@ -186,152 +190,286 @@ use tracing_core::{ span::{Attributes, Id, Record}, }; -pub mod fields; +#[derive(Debug, Deserialize, Eq)] +#[serde(from = "&'a str")] +pub enum CowString<'a> { + Borrowed(&'a str), + #[cfg(feature = "std")] + Owned(String), +} -#[derive(Debug)] -pub struct SerializeField(Field); +impl<'a> Deref for CowString<'a> { + type Target = str; -impl Serialize for SerializeField { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(self.0.name()) + fn deref(&self) -> &Self::Target { + self.as_str() } } -#[derive(Debug)] -pub struct SerializeFieldSet<'a>(&'a FieldSet); - -impl<'a> Serialize for SerializeFieldSet<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(Some(self.0.len()))?; - for element in self.0 { - seq.serialize_element(element.name())?; +impl<'a> CowString<'a> { + pub fn as_str(&'a self) -> &'a str { + match self { + CowString::Borrowed(b) => b, + #[cfg(feature = "std")] + CowString::Owned(o) => o.as_str(), } - seq.end() } } -#[derive(Debug)] -pub struct SerializeLevel<'a>(&'a Level); +#[cfg(feature = "std")] +impl<'a> CowString<'a> { + pub fn to_owned(&'a self) -> CowString<'static> { + CowString::Owned(self.as_str().to_string()) + } +} -impl<'a> Serialize for SerializeLevel<'a> { - fn serialize(&self, serializer: S) -> Result +impl<'a> Hash for CowString<'a> { + fn hash(&self, state: &mut H) { + self.as_str().hash(state) + } +} + +impl<'a> hash32::Hash for CowString<'a> { + fn hash(&self, state: &mut H) where - S: Serializer, + H: hash32::Hasher { - if self.0 == &Level::ERROR { - serializer.serialize_str("ERROR") - } else if self.0 == &Level::WARN { - serializer.serialize_str("WARN") - } else if self.0 == &Level::INFO { - serializer.serialize_str("INFO") - } else if self.0 == &Level::DEBUG { - serializer.serialize_str("DEBUG") - } else if self.0 == &Level::TRACE { - serializer.serialize_str("TRACE") - } else { - unreachable!() - } + ::hash(self.as_str(), state) } } -#[derive(Debug)] -pub struct SerializeId<'a>(&'a Id); +impl<'a> PartialEq for CowString<'a> { + fn eq(&self, other: &Self) -> bool { + self.as_str().eq(other.as_str()) + } +} + +impl<'a> From<&'a str> for CowString<'a> { + fn from(other: &'a str) -> Self { + Self::Borrowed(other) + } +} -impl<'a> Serialize for SerializeId<'a> { +impl<'a> Serialize for CowString<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - let mut state = serializer.serialize_tuple_struct("Id", 1)?; - state.serialize_field(&self.0.into_u64())?; - state.end() + self.as_str().serialize(serializer) } } -#[derive(Debug)] -pub struct SerializeMetadata<'a>(&'a Metadata<'a>); +#[cfg(not(feature = "std"))] +type TracingVec = heapless::Vec; -impl<'a> Serialize for SerializeMetadata<'a> { +#[cfg(not(feature = "std"))] +type TracingMap = heapless::FnvIndexMap; + +#[cfg(feature = "std")] +type TracingVec = std::vec::Vec; + +#[cfg(feature = "std")] +type TracingMap = std::collections::HashMap; + +#[derive(Debug, Deserialize)] +#[serde(from = "TracingVec>")] +pub enum SerializeFieldSet<'a> { + Ser(&'a FieldSet), + #[serde(borrow)] + De(TracingVec>), +} + +impl<'a> Serialize for SerializeFieldSet<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - let mut state = serializer.serialize_struct("Metadata", 9)?; - state.serialize_field("name", self.0.name())?; - state.serialize_field("target", self.0.target())?; - state.serialize_field("level", &SerializeLevel(self.0.level()))?; - state.serialize_field("module_path", &self.0.module_path())?; - state.serialize_field("file", &self.0.file())?; - state.serialize_field("line", &self.0.line())?; - state.serialize_field("fields", &SerializeFieldSet(self.0.fields()))?; - state.serialize_field("is_span", &self.0.is_span())?; - state.serialize_field("is_event", &self.0.is_event())?; - state.end() + match self { + SerializeFieldSet::Ser(sfs) => { + let mut seq = serializer.serialize_seq(Some(sfs.len()))?; + for element in sfs.iter() { + seq.serialize_element(element.name())?; + } + seq.end() + } + SerializeFieldSet::De(dfs) => dfs.serialize(serializer), + } + } +} + +impl<'a> From>> for SerializeFieldSet<'a> { + fn from(other: TracingVec>) -> Self { + SerializeFieldSet::De(other) } } +#[repr(usize)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub enum SerializeLevel { + /// The "trace" level. + /// + /// Designates very low priority, often extremely verbose, information. + Trace = 0, + /// The "debug" level. + /// + /// Designates lower priority information. + Debug = 1, + /// The "info" level. + /// + /// Designates useful information. + Info = 2, + /// The "warn" level. + /// + /// Designates hazardous situations. + Warn = 3, + /// The "error" level. + /// + /// Designates very serious errors. + Error = 4, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SerializeId { + pub id: NonZeroU64, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SerializeMetadata<'a> { + #[serde(borrow)] + pub name: CowString<'a>, + pub target: CowString<'a>, + pub level: SerializeLevel, + pub module_path: Option>, + pub file: Option>, + pub line: Option, + pub fields: SerializeFieldSet<'a>, + pub is_span: bool, + pub is_event: bool, +} + /// Implements `serde::Serialize` to write `Event` data to a serializer. -#[derive(Debug)] -pub struct SerializeEvent<'a>(&'a Event<'a>); +#[derive(Debug, Serialize, Deserialize)] +pub struct SerializeEvent<'a> { + #[serde(borrow)] + pub fields: SerializeRecordFields<'a>, + pub metadata: SerializeMetadata<'a>, + pub parent: Option, +} + +/// Implements `serde::Serialize` to write `Attributes` data to a serializer. +#[derive(Debug, Serialize, Deserialize)] +pub struct SerializeAttributes<'a> { + #[serde(borrow)] + pub metadata: SerializeMetadata<'a>, + pub parent: Option, + pub is_root: bool, +} + +type RecordMap<'a> = TracingMap, SerializeValue<'a>>; + +/// Implements `serde::Serialize` to write `Record` data to a serializer. +#[derive(Debug, Deserialize)] +#[serde(from = "RecordMap<'a>")] +pub enum SerializeRecord<'a> { + #[serde(borrow)] + Ser(&'a Record<'a>), + De(RecordMap<'a>), +} -impl<'a> Serialize for SerializeEvent<'a> { +impl<'a> Serialize for SerializeRecord<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - let mut serializer = serializer.serialize_struct("Event", 2)?; - serializer.serialize_field("metadata", &SerializeMetadata(self.0.metadata()))?; - let mut visitor = SerdeStructVisitor { - serializer, - state: Ok(()), - }; - self.0.record(&mut visitor); - visitor.finish() + match self { + SerializeRecord::Ser(serf) => { + let items = serf.record_len(); + + let serializer = serializer.serialize_map(Some(items))?; + let mut ssv = SerdeMapVisitor::new(serializer); + serf.record(&mut ssv); + ssv.finish() + } + SerializeRecord::De(derf) => derf.serialize(serializer), + } } } -/// Implements `serde::Serialize` to write `Attributes` data to a serializer. -#[derive(Debug)] -pub struct SerializeAttributes<'a>(&'a Attributes<'a>); +impl<'a> From> for SerializeRecord<'a> { + fn from(other: RecordMap<'a>) -> Self { + Self::De(other) + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum SerializeValue<'a> { + #[serde(borrow)] + Debug(DebugRecord<'a>), + Str(CowString<'a>), + F64(f64), + I64(i64), + U64(u64), + Bool(bool), +} + +#[derive(Debug, Deserialize)] +#[serde(from = "CowString<'a>")] +pub enum DebugRecord<'a> { + #[serde(borrow)] + Ser(&'a Arguments<'a>), + De(CowString<'a>), +} + +impl<'a> From> for DebugRecord<'a> { + fn from(other: CowString<'a>) -> Self { + Self::De(other) + } +} -impl<'a> Serialize for SerializeAttributes<'a> { +impl<'a> Serialize for DebugRecord<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - let mut serializer = serializer.serialize_struct("Attributes", 3)?; - serializer.serialize_field("metadata", &SerializeMetadata(self.0.metadata()))?; - serializer.serialize_field("parent", &self.0.parent().map(SerializeId))?; - serializer.serialize_field("is_root", &self.0.is_root())?; - - let mut visitor = SerdeStructVisitor { - serializer, - state: Ok(()), - }; - self.0.record(&mut visitor); - visitor.finish() + match self { + DebugRecord::Ser(args) => args.serialize(serializer), + DebugRecord::De(msg) => msg.serialize(serializer), + } } } -/// Implements `serde::Serialize` to write `Record` data to a serializer. -#[derive(Debug)] -pub struct SerializeRecord<'a>(&'a Record<'a>); +#[derive(Debug, Deserialize)] +#[serde(from = "RecordMap<'a>")] +pub enum SerializeRecordFields<'a> { + #[serde(borrow)] + Ser(&'a Event<'a>), + De(RecordMap<'a>), +} -impl<'a> Serialize for SerializeRecord<'a> { +impl<'a> From> for SerializeRecordFields<'a> { + fn from(other: RecordMap<'a>) -> Self { + Self::De(other) + } +} + +impl<'a> Serialize for SerializeRecordFields<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - let serializer = serializer.serialize_map(None)?; - let mut visitor = SerdeMapVisitor::new(serializer); - self.0.record(&mut visitor); - visitor.finish() + match self { + SerializeRecordFields::Ser(serf) => { + let items = serf.fields().count(); + + let serializer = serializer.serialize_map(Some(items))?; + let mut ssv = SerdeMapVisitor::new(serializer); + serf.record(&mut ssv); + ssv.finish() + } + SerializeRecordFields::De(derf) => derf.serialize(serializer), + } } } @@ -379,125 +517,246 @@ where // If previous fields serialized successfully, continue serializing, // otherwise, short-circuit and do nothing. if self.state.is_ok() { - self.state = self.serializer.serialize_entry(field.name(), &value) + self.state = self + .serializer + .serialize_entry(field.name(), &SerializeValue::Bool(value)) } } fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { if self.state.is_ok() { - self.state = self - .serializer - .serialize_entry(field.name(), &format_args!("{:?}", value)) + self.state = self.serializer.serialize_entry( + field.name(), + &SerializeValue::Debug(DebugRecord::Ser(&format_args!("{:?}", value))), + ) } } fn record_u64(&mut self, field: &Field, value: u64) { if self.state.is_ok() { - self.state = self.serializer.serialize_entry(field.name(), &value) + self.state = self + .serializer + .serialize_entry(field.name(), &SerializeValue::U64(value)) } } fn record_i64(&mut self, field: &Field, value: i64) { if self.state.is_ok() { - self.state = self.serializer.serialize_entry(field.name(), &value) + self.state = self + .serializer + .serialize_entry(field.name(), &SerializeValue::I64(value)) } } fn record_f64(&mut self, field: &Field, value: f64) { if self.state.is_ok() { - self.state = self.serializer.serialize_entry(field.name(), &value) + self.state = self + .serializer + .serialize_entry(field.name(), &SerializeValue::F64(value)) } } fn record_str(&mut self, field: &Field, value: &str) { if self.state.is_ok() { - self.state = self.serializer.serialize_entry(field.name(), &value) + self.state = self + .serializer + .serialize_entry(field.name(), &SerializeValue::Str(value.into())) } } } -/// Implements `tracing_core::field::Visit` for some `serde::ser::SerializeStruct`. -#[derive(Debug)] -pub struct SerdeStructVisitor { - serializer: S, - state: Result<(), S::Error>, +pub trait AsSerde<'a>: self::sealed::Sealed { + type Serializable: serde::Serialize + 'a; + + /// `as_serde` borrows a `tracing` value and returns the serialized value. + fn as_serde(&'a self) -> Self::Serializable; } -impl Visit for SerdeStructVisitor -where - S: SerializeStruct, -{ - fn record_bool(&mut self, field: &Field, value: bool) { - // If previous fields serialized successfully, continue serializing, - // otherwise, short-circuit and do nothing. - if self.state.is_ok() { - self.state = self.serializer.serialize_field(field.name(), &value) +impl<'a> AsSerde<'a> for tracing_core::Metadata<'a> { + type Serializable = SerializeMetadata<'a>; + + fn as_serde(&'a self) -> Self::Serializable { + SerializeMetadata { + name: self.name().into(), + target: self.target().into(), + level: self.level().as_serde(), + module_path: self.module_path().map(Into::into), + file: self.file().map(Into::into), + line: self.line(), + fields: SerializeFieldSet::Ser(self.fields()), + is_span: self.is_span(), + is_event: self.is_event(), } } +} - fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { - if self.state.is_ok() { - self.state = self - .serializer - .serialize_field(field.name(), &format_args!("{:?}", value)) +/// SAFETY: If all data is 'static and/or owned, it is safe +/// to send between threads. +unsafe impl Send for SerializeFieldSet<'static> {} + +#[cfg(feature = "std")] +impl<'a> SerializeFieldSet<'a> { + pub fn to_owned(&self) -> SerializeFieldSet<'static> { + match self { + SerializeFieldSet::Ser(sfs) => SerializeFieldSet::De( + sfs.iter() + .map(|i| CowString::from(i.name()).to_owned()) + .collect(), + ), + SerializeFieldSet::De(dfs) => { + SerializeFieldSet::De(dfs.iter().map(CowString::to_owned).collect()) + } } } +} - fn record_u64(&mut self, field: &Field, value: u64) { - if self.state.is_ok() { - self.state = self.serializer.serialize_field(field.name(), &value) +/// SAFETY: If all data is 'static and/or owned, it is safe +/// to send between threads. +unsafe impl Send for SerializeMetadata<'static> {} + +#[cfg(feature = "std")] +impl<'a> SerializeMetadata<'a> { + pub fn to_owned(&self) -> SerializeMetadata<'static> { + SerializeMetadata { + name: self.name.to_owned(), + target: self.target.to_owned(), + level: self.level, + module_path: self.module_path.as_ref().map(CowString::to_owned), + file: self.file.as_ref().map(CowString::to_owned), + line: self.line, + fields: self.fields.to_owned(), + is_span: self.is_span, + is_event: self.is_event, } } +} - fn record_i64(&mut self, field: &Field, value: i64) { - if self.state.is_ok() { - self.state = self.serializer.serialize_field(field.name(), &value) +impl<'a> AsSerde<'a> for tracing_core::Event<'a> { + type Serializable = SerializeEvent<'a>; + + fn as_serde(&'a self) -> Self::Serializable { + SerializeEvent { + fields: SerializeRecordFields::Ser(self), + metadata: self.metadata().as_serde(), + parent: self.parent().map(|p| p.as_serde()), } } +} - fn record_f64(&mut self, field: &Field, value: f64) { - if self.state.is_ok() { - self.state = self.serializer.serialize_field(field.name(), &value) +/// SAFETY: If all data is 'static and/or owned, it is safe +/// to send between threads. +unsafe impl Send for DebugRecord<'static> {} + +#[cfg(feature = "std")] +impl<'a> DebugRecord<'a> { + pub fn to_owned(&self) -> DebugRecord<'static> { + match self { + DebugRecord::Ser(args) => DebugRecord::De(CowString::Owned(args.to_string())), + DebugRecord::De(d) => DebugRecord::De(d.to_owned()), } } +} - fn record_str(&mut self, field: &Field, value: &str) { - if self.state.is_ok() { - self.state = self.serializer.serialize_field(field.name(), &value) +/// SAFETY: If all data is 'static and/or owned, it is safe +/// to send between threads. +unsafe impl Send for SerializeValue<'static> {} + +#[cfg(feature = "std")] +impl<'a> SerializeValue<'a> { + pub fn to_owned(&self) -> SerializeValue<'static> { + match self { + SerializeValue::Debug(dr) => SerializeValue::Debug(dr.to_owned()), + SerializeValue::Str(s) => SerializeValue::Str(s.to_owned()), + SerializeValue::F64(x) => SerializeValue::F64(*x), + SerializeValue::I64(x) => SerializeValue::I64(*x), + SerializeValue::U64(x) => SerializeValue::U64(*x), + SerializeValue::Bool(x) => SerializeValue::Bool(*x), } } } -impl SerdeStructVisitor { - /// Completes serializing the visited object, returning `Ok(())` if all - /// fields were serialized correctly, or `Error(S::Error)` if a field could - /// not be serialized. - pub fn finish(self) -> Result { - self.state?; - self.serializer.end() +#[cfg(feature = "std")] +struct HashVisit(std::collections::HashMap, SerializeValue<'static>>); + +#[cfg(feature = "std")] +impl Visit for HashVisit { + fn record_bool(&mut self, field: &Field, value: bool) { + self.0.insert( + CowString::Owned(field.name().to_string()), + SerializeValue::Bool(value), + ); } -} -pub trait AsSerde<'a>: self::sealed::Sealed { - type Serializable: serde::Serialize + 'a; + fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { + self.0.insert( + CowString::Owned(field.name().to_string()), + SerializeValue::Debug(DebugRecord::De(CowString::Owned(format!("{:?}", value)))), + ); + } - /// `as_serde` borrows a `tracing` value and returns the serialized value. - fn as_serde(&'a self) -> Self::Serializable; -} + fn record_u64(&mut self, field: &Field, value: u64) { + self.0.insert( + CowString::Owned(field.name().to_string()), + SerializeValue::U64(value), + ); + } -impl<'a> AsSerde<'a> for tracing_core::Metadata<'a> { - type Serializable = SerializeMetadata<'a>; + fn record_i64(&mut self, field: &Field, value: i64) { + self.0.insert( + CowString::Owned(field.name().to_string()), + SerializeValue::I64(value), + ); + } - fn as_serde(&'a self) -> Self::Serializable { - SerializeMetadata(self) + fn record_f64(&mut self, field: &Field, value: f64) { + self.0.insert( + CowString::Owned(field.name().to_string()), + SerializeValue::F64(value), + ); + } + + fn record_str(&mut self, field: &Field, value: &str) { + self.0.insert( + CowString::Owned(field.name().to_string()), + SerializeValue::Str(CowString::Owned(value.to_string())), + ); } } -impl<'a> AsSerde<'a> for tracing_core::Event<'a> { - type Serializable = SerializeEvent<'a>; +/// SAFETY: If all data is 'static and/or owned, it is safe +/// to send between threads. +unsafe impl Send for SerializeRecordFields<'static> {} + +#[cfg(feature = "std")] +impl<'a> SerializeRecordFields<'a> { + pub fn to_owned(&self) -> SerializeRecordFields<'static> { + match self { + SerializeRecordFields::Ser(e) => { + let mut hv = HashVisit(std::collections::HashMap::new()); + e.record(&mut hv); + SerializeRecordFields::De(hv.0) + } + SerializeRecordFields::De(dsrf) => SerializeRecordFields::De( + dsrf.iter() + .map(|(k, v)| (k.to_owned(), v.to_owned())) + .collect(), + ), + } + } +} - fn as_serde(&'a self) -> Self::Serializable { - SerializeEvent(self) +/// SAFETY: If all data is 'static and/or owned, it is safe +/// to send between threads. +unsafe impl Send for SerializeEvent<'static> {} + +#[cfg(feature = "std")] +impl<'a> SerializeEvent<'a> { + pub fn to_owned(&self) -> SerializeEvent<'static> { + SerializeEvent { + fields: self.fields.to_owned(), + metadata: self.metadata.to_owned(), + parent: self.parent.clone(), + } } } @@ -505,15 +764,43 @@ impl<'a> AsSerde<'a> for tracing_core::span::Attributes<'a> { type Serializable = SerializeAttributes<'a>; fn as_serde(&'a self) -> Self::Serializable { - SerializeAttributes(self) + SerializeAttributes { + metadata: self.metadata().as_serde(), + parent: self.parent().map(|p| p.as_serde()), + is_root: self.is_root(), + } + } +} + +/// SAFETY: If all data is 'static and/or owned, it is safe +/// to send between threads. +unsafe impl Send for SerializeAttributes<'static> {} + +#[cfg(feature = "std")] +impl<'a> SerializeAttributes<'a> { + pub fn to_owned(&self) -> SerializeAttributes<'static> { + SerializeAttributes { + metadata: self.metadata.to_owned(), + parent: self.parent.clone(), + is_root: self.is_root, + } } } impl<'a> AsSerde<'a> for tracing_core::span::Id { - type Serializable = SerializeId<'a>; + type Serializable = SerializeId; fn as_serde(&'a self) -> Self::Serializable { - SerializeId(self) + SerializeId { + id: self.into_non_zero_u64(), + } + } +} + +#[cfg(feature = "std")] +impl SerializeId { + pub fn to_owned(&self) -> Self { + self.clone() } } @@ -521,15 +808,50 @@ impl<'a> AsSerde<'a> for tracing_core::span::Record<'a> { type Serializable = SerializeRecord<'a>; fn as_serde(&'a self) -> Self::Serializable { - SerializeRecord(self) + SerializeRecord::Ser(self) + } +} + +/// SAFETY: If all data is 'static and/or owned, it is safe +/// to send between threads. +unsafe impl Send for SerializeRecord<'static> {} + +#[cfg(feature = "std")] +impl<'a> SerializeRecord<'a> { + pub fn to_owned(&self) -> SerializeRecord<'static> { + match self { + SerializeRecord::Ser(s) => { + let mut hv = HashVisit(std::collections::HashMap::new()); + s.record(&mut hv); + SerializeRecord::De(hv.0) + }, + SerializeRecord::De(d) => { + SerializeRecord::De( + d.iter().map(|(k, v)| (k.to_owned(), v.to_owned())).collect() + ) + }, + } } } impl<'a> AsSerde<'a> for Level { - type Serializable = SerializeLevel<'a>; + type Serializable = SerializeLevel; fn as_serde(&'a self) -> Self::Serializable { - SerializeLevel(self) + match self { + &Level::ERROR => SerializeLevel::Error, + &Level::WARN => SerializeLevel::Warn, + &Level::INFO => SerializeLevel::Info, + &Level::DEBUG => SerializeLevel::Debug, + &Level::TRACE => SerializeLevel::Trace, + } + } +} + +#[cfg(feature = "std")] +impl SerializeLevel { + pub fn to_owned(&self) -> Self { + self.clone() } }