diff --git a/opentelemetry-contrib/src/trace/exporter/datadog/model/v03.rs b/opentelemetry-contrib/src/trace/exporter/datadog/model/v03.rs index fc99b5edcb..2542f4c200 100644 --- a/opentelemetry-contrib/src/trace/exporter/datadog/model/v03.rs +++ b/opentelemetry-contrib/src/trace/exporter/datadog/model/v03.rs @@ -63,9 +63,8 @@ pub(crate) fn encode(service_name: &str, spans: Vec) -> Result< rmp::encode::write_str(&mut encoded, "meta")?; rmp::encode::write_map_len(&mut encoded, span.attributes.len() as u32)?; for (key, value) in span.attributes.iter() { - let value_string: String = value.into(); rmp::encode::write_str(&mut encoded, key.as_str())?; - rmp::encode::write_str(&mut encoded, value_string.as_str())?; + rmp::encode::write_str(&mut encoded, value.as_str().as_ref())?; } } diff --git a/opentelemetry-contrib/src/trace/exporter/datadog/model/v05.rs b/opentelemetry-contrib/src/trace/exporter/datadog/model/v05.rs index fcd625935c..ecd15d899d 100644 --- a/opentelemetry-contrib/src/trace/exporter/datadog/model/v05.rs +++ b/opentelemetry-contrib/src/trace/exporter/datadog/model/v05.rs @@ -111,9 +111,8 @@ fn encode_spans( rmp::encode::write_i32(&mut encoded, span.status_code as i32)?; rmp::encode::write_map_len(&mut encoded, span.attributes.len() as u32)?; for (key, value) in span.attributes.iter() { - let value_string: String = value.into(); rmp::encode::write_u32(&mut encoded, interner.intern(key.as_str()))?; - rmp::encode::write_u32(&mut encoded, interner.intern(value_string.as_str()))?; + rmp::encode::write_u32(&mut encoded, interner.intern(value.as_str().as_ref()))?; } rmp::encode::write_map_len(&mut encoded, 0)?; rmp::encode::write_u32(&mut encoded, span_type)?; diff --git a/opentelemetry-jaeger/src/lib.rs b/opentelemetry-jaeger/src/lib.rs index 3ad0e5dcf5..d9f00acb2c 100644 --- a/opentelemetry-jaeger/src/lib.rs +++ b/opentelemetry-jaeger/src/lib.rs @@ -486,7 +486,7 @@ impl Into for KeyValue { Value::Bool(b) => jaeger::Tag::new(key.into(), jaeger::TagType::Bool, None, None, Some(b), None, None), Value::I64(i) => jaeger::Tag::new(key.into(), jaeger::TagType::Long, None, None, None, Some(i), None), // TODO: better Array handling, jaeger thrift doesn't support arrays - v @ Value::Array(_) => jaeger::Tag::new(key.into(), jaeger::TagType::String, Some(v.into()), None, None, None, None), + v @ Value::Array(_) => jaeger::Tag::new(key.into(), jaeger::TagType::String, Some(v.to_string()), None, None, None, None), } } } diff --git a/opentelemetry-prometheus/src/lib.rs b/opentelemetry-prometheus/src/lib.rs index 902a03c3ae..7c68adbb63 100644 --- a/opentelemetry-prometheus/src/lib.rs +++ b/opentelemetry-prometheus/src/lib.rs @@ -394,7 +394,7 @@ fn build_histogram( fn build_label_pair(label: KeyValue) -> prometheus::proto::LabelPair { let mut lp = prometheus::proto::LabelPair::new(); lp.set_name(label.key.into()); - lp.set_value(label.value.into()); + lp.set_value(label.value.to_string()); lp } diff --git a/opentelemetry-zipkin/src/model/mod.rs b/opentelemetry-zipkin/src/model/mod.rs index d7d9049545..bae383276d 100644 --- a/opentelemetry-zipkin/src/model/mod.rs +++ b/opentelemetry-zipkin/src/model/mod.rs @@ -138,7 +138,7 @@ where { let mut map: HashMap = HashMap::new(); for kv in kvs { - map.insert(kv.key.into(), kv.value.into()); + map.insert(kv.key.into(), kv.value.to_string()); } map } diff --git a/opentelemetry/src/api/baggage.rs b/opentelemetry/src/api/baggage.rs index 7a6bde9a6d..9eac7ef9bd 100644 --- a/opentelemetry/src/api/baggage.rs +++ b/opentelemetry/src/api/baggage.rs @@ -211,8 +211,8 @@ impl Baggage { if !key.as_str().is_ascii() { return false; } - let value = String::from(value); - if key_value_metadata_bytes_size(key.as_str(), value.as_str(), metadata.as_str()) + let value = value.as_str(); + if key_value_metadata_bytes_size(key.as_str(), value.as_ref(), metadata.as_str()) < MAX_BYTES_FOR_ONE_PAIR { match self.inner.get(key) { @@ -234,7 +234,7 @@ impl Baggage { metadata.as_str().len() + value.len() + key.as_str().len() } Some((old_value, old_metadata)) => { - let old_value = String::from(old_value); + let old_value = old_value.as_str(); if self.kv_content_len - old_metadata.as_str().len() - old_value.len() + metadata.as_str().len() + value.len() diff --git a/opentelemetry/src/api/core.rs b/opentelemetry/src/api/core.rs index 7040128d34..6581388f48 100644 --- a/opentelemetry/src/api/core.rs +++ b/opentelemetry/src/api/core.rs @@ -87,6 +87,12 @@ impl From for String { } } +impl fmt::Display for Key { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(fmt) + } +} + /// Array of homogeneous values #[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))] #[derive(Clone, Debug, PartialEq)] @@ -180,6 +186,21 @@ pub enum Value { Array(Array), } +impl Value { + /// String representation of the `Value` + /// + /// This will allocate iff the underlying value is not a `String`. + pub fn as_str(&self) -> Cow<'_, str> { + match self { + Value::Bool(v) => format!("{}", v).into(), + Value::I64(v) => format!("{}", v).into(), + Value::F64(v) => format!("{}", v).into(), + Value::String(v) => Cow::Borrowed(v.as_ref()), + Value::Array(v) => format!("{}", v).into(), + } + } +} + macro_rules! from_values { ( $( @@ -217,30 +238,14 @@ impl From for Value { } } -impl From for String { - /// Convert `Value` types to `String` for use by exporters that only use - /// `String` values. - fn from(value: Value) -> Self { - match value { - Value::Bool(value) => value.to_string(), - Value::I64(value) => value.to_string(), - Value::F64(value) => value.to_string(), - Value::String(value) => value.into_owned(), - Value::Array(value) => value.to_string(), - } - } -} - -impl From<&Value> for String { - /// Convert `&Value` types to `String` for use by exporters that only use - /// `String` values. - fn from(value: &Value) -> Self { - match value { - Value::Bool(value) => value.to_string(), - Value::I64(value) => value.to_string(), - Value::F64(value) => value.to_string(), - Value::String(value) => value.to_string(), - Value::Array(value) => value.to_string(), +impl fmt::Display for Value { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Value::Bool(v) => fmt.write_fmt(format_args!("{}", v)), + Value::I64(v) => fmt.write_fmt(format_args!("{}", v)), + Value::F64(v) => fmt.write_fmt(format_args!("{}", v)), + Value::String(v) => fmt.write_fmt(format_args!("{}", v)), + Value::Array(v) => fmt.write_fmt(format_args!("{}", v)), } } } diff --git a/opentelemetry/src/api/labels/encoder.rs b/opentelemetry/src/api/labels/encoder.rs index 5119bf7b0e..1ded29e8d2 100644 --- a/opentelemetry/src/api/labels/encoder.rs +++ b/opentelemetry/src/api/labels/encoder.rs @@ -1,5 +1,5 @@ use crate::{Key, Value}; -use std::fmt; +use std::fmt::{self, Write}; use std::sync::atomic::{AtomicUsize, Ordering}; static ENCODER_ID_COUNTER: AtomicUsize = AtomicUsize::new(0); @@ -39,12 +39,22 @@ impl Encoder for DefaultLabelEncoder { labels .enumerate() .fold(String::new(), |mut acc, (idx, (key, value))| { + let offset = acc.len(); if idx > 0 { acc.push(',') } - acc.push_str(key.as_str()); + + if write!(acc, "{}", key).is_err() { + acc.truncate(offset); + return acc; + } + acc.push('='); - acc.push_str(String::from(value).as_str()); + if write!(acc, "{}", value).is_err() { + acc.truncate(offset); + return acc; + } + acc }) } diff --git a/opentelemetry/src/sdk/propagation/baggage.rs b/opentelemetry/src/sdk/propagation/baggage.rs index 1bb97429d3..553204d707 100644 --- a/opentelemetry/src/sdk/propagation/baggage.rs +++ b/opentelemetry/src/sdk/propagation/baggage.rs @@ -123,7 +123,7 @@ impl TextMapPropagator for BaggagePropagator { let metadata_prefix = if metadata_str.is_empty() { "" } else { ";" }; utf8_percent_encode(name.as_str().trim(), FRAGMENT) .chain(iter::once("=")) - .chain(utf8_percent_encode(String::from(value).trim(), FRAGMENT)) + .chain(utf8_percent_encode(value.as_str().trim(), FRAGMENT)) .chain(iter::once(metadata_prefix)) .chain(iter::once(metadata_str)) .collect()