add dumb logging

This commit is contained in:
Aleksandr 2025-10-07 03:33:54 +03:00
parent 8015bcc99f
commit 04ff3853e6
7 changed files with 195 additions and 22 deletions

View file

@ -16,8 +16,12 @@ cli = [
"figment/yaml",
"figment/json",
"figment/toml",
"figment/env"
"figment/env",
"logforth",
"dep:fastrace"
]
enable-tracing = ["fastrace/enable"]
logforth = ["dep:logforth", "dep:opentelemetry-otlp"]
tokio = ["dep:tokio"]
# Very long running.
get_time_test = []
@ -63,3 +67,8 @@ eyre = { version = "0.6.12" }
num_cpus = { version = "1.17.0", optional = true }
either = "1.15.0"
humantime = "2.3.0"
log = { version = "0.4.28", features = ["kv", "kv_serde", "std", "serde"] }
logforth = { version = "0.28.1", default-features = false, features = ["append-fastrace", "append-file", "bridge-log", "layout-text", "layout-json", "append-async", "append-opentelemetry", "diagnostic-fastrace", "rustls"], optional = true }
opentelemetry-otlp = { version = "0.31.0", default-features = false, features = ["logs", "metrics", "http-proto", "http-json"], optional = true }
fastrace = { version = "0.7.14", optional = true }

View file

@ -149,6 +149,8 @@ impl App {
}
let component_configs = ComponentConfigs::new(map);
crate::logging::logforth::setup(component_configs.get());
let rt_config = component_configs.get::<rt::RtConfig>();
let rt = match rt_config.flavor {
@ -184,5 +186,6 @@ impl Default for App {
};
this.optional::<rt::RtConfig>("system.rt")
.optional::<crate::logging::logforth::Config>("system.logging")
}
}

View file

@ -1,8 +1,8 @@
use crate::{collections::HashMap, str::CompactString, trait_set};
use std::{
mem,
any::{Any, TypeId},
fmt, mem,
ops::Deref,
sync::{
Arc, Mutex,
@ -91,11 +91,21 @@ pub struct ComponentConfig<T> {
handle: Arc<ConfigHandle>,
}
impl<T: fmt::Debug> fmt::Debug for ComponentConfig<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Debug>::fmt(&**self, f)
}
}
impl<T: IsComponentConfig> ComponentConfig<T> {
pub fn section(&self) -> &str {
&self.handle.section
}
pub fn outdated(&self) -> bool {
self.generation != self.handle.generation.load(Ordering::Relaxed)
}
/// Update component config. Returns previous config if something's changed.
pub fn try_update(&mut self) -> Option<T> {
let generation = self.handle.generation.load(Ordering::Relaxed);

View file

@ -28,6 +28,8 @@ pub use trait_set::trait_set;
#[cfg(feature = "cli")]
pub mod cli;
pub mod logging;
pub mod array;
pub mod error;
pub mod utils;

137
src/logging/logforth.rs Normal file
View file

@ -0,0 +1,137 @@
use std::{collections::HashMap, fmt, path::PathBuf};
use logforth::{
Filter,
filter::FilterResult,
layout::JsonLayout,
record::{LevelFilter, Metadata},
};
use opentelemetry_otlp::WithExportConfig as _;
use crate::{component_configs::ComponentConfig, data};
#[data(crate = crate, copy)]
#[derive(Default)]
pub enum LogLevel {
Debug,
Warn,
Error,
#[default]
Info,
Trace,
}
impl From<LogLevel> for log::Level {
fn from(value: LogLevel) -> Self {
use LogLevel::*;
use log::Level as D;
match value {
Info => D::Info,
Warn => D::Warn,
Trace => D::Trace,
Error => D::Error,
Debug => D::Debug,
}
}
}
#[data(crate = crate)]
pub enum Append {
File {
base_dir: PathBuf,
file_name: String,
},
Otel {
name: String,
endpoint: String,
#[serde(default)]
labels: HashMap<String, String>,
},
Stderr,
Stdout,
}
impl Append {
pub fn to_appender(&self) -> Box<dyn logforth::Append> {
use logforth::append;
match self {
Self::File {
base_dir,
file_name,
} => Box::new(
append::file::FileBuilder::new(base_dir.clone(), file_name.clone())
.filename_suffix("log")
.layout(JsonLayout::default())
.build()
.unwrap(),
),
Self::Otel {
name,
endpoint,
labels,
} => {
let log_exporter = opentelemetry_otlp::LogExporter::builder()
.with_http()
.with_endpoint(endpoint.as_str())
.build()
.unwrap();
Box::new(
append::opentelemetry::OpentelemetryLogBuilder::new(name.clone(), log_exporter)
.labels(labels.iter().map(|(k, v)| (k.clone(), v.clone())))
.build(),
)
}
Self::Stderr => Box::new(append::Stderr::default()),
Self::Stdout => Box::new(append::Stdout::default()),
}
}
}
#[data(crate = crate)]
pub struct Config {
#[serde(default)]
pub default_level: LogLevel,
#[serde(default)]
pub levels: HashMap<String, LogLevel>,
#[serde(default = "Config::default_append")]
pub append: Vec<Append>,
}
impl Config {
fn default_append() -> Vec<Append> {
vec![Append::Stderr]
}
}
impl Default for Config {
fn default() -> Self {
Self {
default_level: LogLevel::default(),
levels: HashMap::default(),
append: Self::default_append(),
}
}
}
pub fn setup(cfg: ComponentConfig<Config>) {
use logforth::{
append::{self, asynchronous as async_},
diagnostic,
};
logforth::starter_log::builder()
.dispatch(move |d| {
let mut appenders = async_::AsyncBuilder::new("system.logger");
for appender in cfg.append.iter() {
appenders = appenders.append(appender.to_appender());
}
d.diagnostic(diagnostic::FastraceDiagnostic::default())
.append(append::FastraceEvent::default())
.append(appenders.build())
})
.apply();
}

4
src/logging/mod.rs Normal file
View file

@ -0,0 +1,4 @@
pub use log::{debug, error, info, log, log_enabled, trace, warn};
#[cfg(feature = "logforth")]
pub mod logforth;

View file

@ -1,5 +1,6 @@
use compact_str::ToCompactString;
use eyre::eyre;
use fastrace::{Span, future::FutureExt, prelude::SpanContext};
use tokio::{sync::mpsc, task::JoinSet};
use crate::{
@ -82,6 +83,7 @@ where
}
pub struct Supervisor {
span: Span,
set: JoinSet<eyre::Result<()>>,
handles: HashMap<CompactString, Handle>,
configs: ComponentConfigs,
@ -90,6 +92,7 @@ pub struct Supervisor {
impl Supervisor {
pub fn new(configs: ComponentConfigs) -> Self {
Self {
span: Span::root("supervisor", SpanContext::random()),
set: JoinSet::new(),
handles: HashMap::default(),
configs,
@ -108,35 +111,38 @@ impl Supervisor {
let config = self.configs.get::<T>();
let name = config.section().to_compact_string();
self.set.spawn(async move {
let fut = f(config, slave_rx);
tokio::pin!(fut);
loop {
tokio::select! {
res = &mut fut => {
break res;
}
self.set.spawn(
async move {
let fut = f(config, slave_rx);
tokio::pin!(fut);
loop {
tokio::select! {
res = &mut fut => {
break res;
}
cmd = rx.recv(), if !rx.is_closed() => {
let Some(cmd) = cmd else {
continue;
};
cmd = rx.recv(), if !rx.is_closed() => {
let Some(cmd) = cmd else {
continue;
};
match cmd {
SupervisorCommand::Ping { pong } => {
pong.wake();
}
match cmd {
SupervisorCommand::Ping { pong } => {
pong.wake();
}
SupervisorCommand::User(u) => {
if stx.send(u).await.is_err() {
rx.close();
SupervisorCommand::User(u) => {
if stx.send(u).await.is_err() {
rx.close();
}
}
}
}
}
}
}
});
.in_span(Span::enter_with_parent(name.clone(), &self.span)),
);
let hash_map::Entry::Vacant(vac) = self.handles.entry(name.clone()) else {
panic!("{name:?} already exists")
@ -169,6 +175,8 @@ impl Supervisor {
}
}
fastrace::flush();
Ok(())
}
}