Skip to content
Merged
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ jobs:
cargo run --features="starter-log" --example single_file
cargo run --features="starter-log,diagnostic-task-local" --example task_local
cargo run --features="starter-log,append-async" --example asynchronous
cargo run --features="starter-log,diagnostic-fastrace,layout-google-cloud-logging" --example google_cloud_logging
cargo run --features="starter-log,bridge-log-serde,diagnostic-fastrace,layout-google-cloud-logging" --example google_cloud_logging
cargo run --features="starter-log,append-fastrace,diagnostic-fastrace" --example fastrace

cargo test --features="starter-log" --example testing -- --show-output
Expand Down
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fasyslog = { version = "1.0.0" }
insta = { version = "1.43.2" }
jiff = { version = "0.2" }
libc = { version = "0.2.162" }
log = { version = "0.4.27", features = ["kv_std", "kv_sval"] }
log = { version = "0.4.27", default-features = false }
Comment thread
tisonkun marked this conversation as resolved.
oneshot = { version = "0.2.1", default-features = false, features = ["std"] }
opentelemetry = { version = "0.32.0", default-features = false }
opentelemetry-otlp = { version = "0.32.0", default-features = false }
Expand All @@ -73,7 +73,6 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
tempfile = { version = "3.16" }
tokio = { version = "1.47.1" }
value-bag = { version = "1.11.1", features = ["inline-i128", "owned", "sval"] }
which = { version = "8.0.0" }

[workspace.lints.rust]
Expand Down
2 changes: 1 addition & 1 deletion appenders/async/src/append.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl AsyncBuilder {
struct DiagnosticCollector<'a>(&'a mut Vec<(kv::KeyOwned, kv::ValueOwned)>);

impl<'a> Visitor for DiagnosticCollector<'a> {
fn visit(&mut self, key: kv::Key, value: kv::Value) -> Result<(), Error> {
fn visit(&mut self, key: kv::KeyView, value: kv::ValueView) -> Result<(), Error> {
self.0.push((key.to_owned(), value.to_owned()));
Ok(())
}
Expand Down
8 changes: 4 additions & 4 deletions appenders/async/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl Worker {
let diags: &[Box<dyn Diagnostic>] = if diags.is_empty() {
&[]
} else {
&[Box::new(OwnedDiagnostic(diags))]
&[Box::new(AsyncDiagnostic(diags))]
};

record.with(|record| {
Expand All @@ -80,12 +80,12 @@ impl Worker {
}

#[derive(Debug)]
struct OwnedDiagnostic(Vec<(kv::KeyOwned, kv::ValueOwned)>);
struct AsyncDiagnostic(Vec<(kv::KeyOwned, kv::ValueOwned)>);

impl Diagnostic for OwnedDiagnostic {
impl Diagnostic for AsyncDiagnostic {
fn visit(&self, visitor: &mut dyn Visitor) -> Result<(), Error> {
for (key, value) in &self.0 {
visitor.visit(key.by_ref(), value.by_ref())?;
visitor.visit(key.view(), value.view())?;
}
Ok(())
}
Expand Down
23 changes: 12 additions & 11 deletions appenders/fastrace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use jiff::Zoned;
use logforth_core::Diagnostic;
use logforth_core::Error;
use logforth_core::append::Append;
use logforth_core::kv::Key;
use logforth_core::kv::Value;
use logforth_core::kv::KeyView;
use logforth_core::kv::ValueView;
use logforth_core::kv::Visitor;
use logforth_core::record::Record;

Expand Down Expand Up @@ -68,12 +68,7 @@ impl Append for FastraceEvent {
(Cow::from("timestamp"), Cow::from(Zoned::now().to_string())),
]
.into_iter()
.chain(
collector
.kv
.into_iter()
.map(|(k, v)| (Cow::from(k), Cow::from(v))),
)
.chain(collector.kv)
},
));

Expand All @@ -87,12 +82,18 @@ impl Append for FastraceEvent {
}

struct KvCollector {
kv: Vec<(String, String)>,
kv: Vec<(Cow<'static, str>, Cow<'static, str>)>,
}

impl Visitor for KvCollector {
fn visit(&mut self, key: Key, value: Value) -> Result<(), Error> {
self.kv.push((key.to_string(), value.to_string()));
fn visit(&mut self, key: KeyView, value: ValueView) -> Result<(), Error> {
let k = key.to_cow();
let v = if let Some(s) = value.to_static_str() {
Cow::Borrowed(s)
} else {
Cow::Owned(value.to_string())
};
self.kv.push((k, v));
Ok(())
}
}
4 changes: 2 additions & 2 deletions appenders/journald/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use std::io::Write;

use logforth_core::kv::Value;
use logforth_core::kv::ValueView;

pub(super) enum FieldName<'a> {
WellFormed(&'a str),
Expand Down Expand Up @@ -90,7 +90,7 @@ impl PutAsFieldValue for std::fmt::Arguments<'_> {
}
}

impl PutAsFieldValue for Value<'_> {
impl PutAsFieldValue for ValueView<'_> {
fn put_field_value(self, buffer: &mut Vec<u8>) {
// SAFETY: no more than an allocate-less version
// buffer.extend_from_slice(format!("{}", self))
Expand Down
6 changes: 3 additions & 3 deletions appenders/journald/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use std::os::unix::net::UnixDatagram;
use logforth_core::Append;
use logforth_core::Diagnostic;
use logforth_core::Error;
use logforth_core::kv::Key;
use logforth_core::kv::Value;
use logforth_core::kv::KeyView;
use logforth_core::kv::ValueView;
use logforth_core::kv::Visitor;
use logforth_core::record::Level;
use logforth_core::record::Record;
Expand Down Expand Up @@ -237,7 +237,7 @@ impl Journald {
struct WriteKeyValues<'a>(&'a mut Vec<u8>);

impl Visitor for WriteKeyValues<'_> {
fn visit(&mut self, key: Key, value: Value) -> Result<(), Error> {
fn visit(&mut self, key: KeyView, value: ValueView) -> Result<(), Error> {
let key = key.as_str();
field::put_field_length_encoded(self.0, field::FieldName::WriteEscaped(key), value);
Ok(())
Expand Down
69 changes: 64 additions & 5 deletions appenders/opentelemetry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,21 @@
#![deny(missing_docs)]

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;
use std::time::SystemTime;

use logforth_core::Diagnostic;
use logforth_core::Error;
use logforth_core::Layout;
use logforth_core::append::Append;
use logforth_core::kv::Key;
use logforth_core::kv::Value;
use logforth_core::kv::KeyView;
use logforth_core::kv::ValueView;
use logforth_core::kv::Visitor;
use logforth_core::record::Level;
use logforth_core::record::Record;
use opentelemetry::InstrumentationScope;
use opentelemetry::Key;
use opentelemetry::logs::AnyValue;
use opentelemetry::logs::LogRecord;
use opentelemetry::logs::Logger;
Expand Down Expand Up @@ -361,10 +363,67 @@ struct KvExtractor<'a> {
}

impl Visitor for KvExtractor<'_> {
fn visit(&mut self, key: Key, value: Value) -> Result<(), Error> {
let key = key.to_cow();
let value = value.to_string();
fn visit(&mut self, key: KeyView, value: ValueView) -> Result<(), Error> {
let key = key_to_key(key);
let value = value_to_any_value(value);
self.record.add_attribute(key, value);
Ok(())
}
}

fn key_to_key(key: KeyView) -> Key {
Key::from(key.to_cow())
}

fn value_to_any_value(value: ValueView) -> AnyValue {
match value {
// TODO(@tisonkun): see https://github.com/open-telemetry/opentelemetry-rust/issues/3528
ValueView::None => AnyValue::String("null".into()),
ValueView::BorrowedStr(v) => AnyValue::String(v.to_string().into()),
ValueView::StaticStr(v) => AnyValue::String(v.into()),
ValueView::Char(v) => AnyValue::String(v.to_string().into()),
ValueView::Debug(v) => AnyValue::String(v.to_string().into()),
ValueView::Display(v) => AnyValue::String(v.to_string().into()),
ValueView::Bool(v) => AnyValue::Boolean(v),
ValueView::I64(v) => AnyValue::Int(v),
ValueView::F64(v) => AnyValue::Double(v),
// the following three integer transforms follow what `opentelemetry-appender-log` does:
// https://github.com/open-telemetry/opentelemetry-rust/blob/f7b0dd99/opentelemetry-appender-log/src/lib.rs#L259-L287
ValueView::U64(v) => {
if let Ok(i) = i64::try_from(v) {
AnyValue::Int(i)
} else {
AnyValue::String(v.to_string().into())
}
}
ValueView::I128(v) => {
if let Ok(i) = i64::try_from(v) {
AnyValue::Int(i)
} else {
AnyValue::String(v.to_string().into())
}
}
ValueView::U128(v) => {
if let Ok(i) = i64::try_from(v) {
AnyValue::Int(i)
} else {
AnyValue::String(v.to_string().into())
}
}
ValueView::List(v) => {
let mut l = Vec::new();
for item in v.iter() {
l.push(value_to_any_value(item));
}
AnyValue::ListAny(Box::new(l))
}
ValueView::Map(v) => {
let mut m = HashMap::new();
for (k, v) in v.iter() {
m.insert(key_to_key(k), value_to_any_value(v));
}
AnyValue::Map(Box::new(m))
}
v => AnyValue::String(v.to_string().into()),
}
}
9 changes: 8 additions & 1 deletion bridges/log/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,16 @@ rust-version.workspace = true
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = []
serde = ["dep:serde", "log/kv_serde", "logforth-core/serde"]

[dependencies]
log = { workspace = true }
log = { workspace = true, features = ["kv", "std"] }
logforth-core = { workspace = true }

# Optional dependencies
serde = { workspace = true, optional = true }

[lints]
workspace = true
Loading