diff --git a/README.md b/README.md index 32dbf8a..546a478 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,57 @@ For some idea of what it can do, see the `tests/smoke-test` example. An event is a point of change in a system surfaced to an observer along with rationale describing it. Events are a model of your unique domain through the lens of significant interactions with it. +You can represent a lot of interesting observability signals using events. + +``` +emit::info!(extent: now, "A log record"); +``` + +``` +13:18:58.657 A log record +``` + +----- + +``` +emit::info!(extent: now..later, "A span"); +``` + +``` +13:19:03.657 5s A span +``` + +----- + +``` +emit::info!(extent: now, "An independent metric {metric_value: 1.0}"); +``` + +``` +13:18:58.657 An independent metric 1 +``` + +----- + +``` +emit::info!(extent: now..later, "A cumulative metric {metric_value: 4.0}"); +``` + +``` +13:19:03.657 5s A cumulative metric 4 +``` + +----- + +``` +emit::info!(extent: now..later, "A histogram metric {#[emit::as_serde] metric_value: [1.0, 3.0, 2.0, 5.0, 1.0]}"); +``` + +``` +13:19:03.657 5s A histogram metric (1, 3, 2, 5, 1) +▁▄▃▇▁ +``` + ## How is this different? `emit` takes a different path from `log` or `tracing` by abandoning `format_args!` as the basis of its instrumentation. diff --git a/core/src/value.rs b/core/src/value.rs index 74ecfb4..8c917da 100644 --- a/core/src/value.rs +++ b/core/src/value.rs @@ -290,21 +290,19 @@ pub use self::alloc_support::*; #[cfg(all(feature = "sval", not(feature = "serde")))] mod seq { + use core::marker::PhantomData; + use super::*; impl<'v> Value<'v> { pub(super) fn to_sequence Extend>>>( &self, ) -> Option { - if let Ok(seq) = sval_nested::stream_ref(Root(Default::default()), &self.0) { - Some(seq) - } else { - None - } + sval_nested::stream_ref(Root(Default::default()), &self.0).ok() } } - struct Root(C); + struct Root(PhantomData); struct Seq(C); @@ -315,7 +313,7 @@ mod seq { type Map = sval_nested::Unsupported; - type Tuple = sval_nested::Unsupported; + type Tuple = Seq; type Record = sval_nested::Unsupported; @@ -354,9 +352,9 @@ mod seq { _: Option, _: Option, _: Option, - _: Option, + num_entries: Option, ) -> sval_nested::Result { - Err(sval_nested::Error::invalid_value("not a sequence")) + self.seq_begin(num_entries) } fn record_begin( @@ -392,25 +390,40 @@ mod seq { Ok(self.0) } } + + impl<'sval, C: for<'a> Extend>>> sval_nested::StreamTuple<'sval> for Seq { + type Ok = C; + + fn value_computed( + &mut self, + tag: Option, + _: sval::Index, + value: V, + ) -> sval_nested::Result { + sval_nested::StreamSeq::value_computed(self, value) + } + + fn end(self) -> sval_nested::Result { + sval_nested::StreamSeq::end(self) + } + } } #[cfg(feature = "serde")] mod seq { + use core::marker::PhantomData; + use super::*; impl<'v> Value<'v> { pub(super) fn to_sequence Extend>>>( &self, ) -> Option { - if let Ok(seq) = serde::Serialize::serialize(&self.0, Root(Default::default())) { - Some(seq) - } else { - None - } + serde::Serialize::serialize(&self.0, Root(Default::default())).ok() } } - struct Root(C); + struct Root(PhantomData); struct Seq(C); @@ -441,7 +454,7 @@ mod seq { type SerializeSeq = Seq; - type SerializeTuple = serde::ser::Impossible; + type SerializeTuple = Seq; type SerializeTupleStruct = serde::ser::Impossible; @@ -565,8 +578,8 @@ mod seq { Ok(Seq(C::default())) } - fn serialize_tuple(self, _: usize) -> Result { - Err(Unsupported) + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) } fn serialize_tuple_struct( @@ -628,4 +641,21 @@ mod seq { Ok(self.0) } } + + impl Extend>>> serde::ser::SerializeTuple for Seq { + type Ok = C; + + type Error = Unsupported; + + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + serde::ser::SerializeSeq::end(self) + } + } }