add dumb logging
This commit is contained in:
parent
8015bcc99f
commit
04ff3853e6
7 changed files with 195 additions and 22 deletions
11
Cargo.toml
11
Cargo.toml
|
@ -16,8 +16,12 @@ cli = [
|
||||||
"figment/yaml",
|
"figment/yaml",
|
||||||
"figment/json",
|
"figment/json",
|
||||||
"figment/toml",
|
"figment/toml",
|
||||||
"figment/env"
|
"figment/env",
|
||||||
|
"logforth",
|
||||||
|
"dep:fastrace"
|
||||||
]
|
]
|
||||||
|
enable-tracing = ["fastrace/enable"]
|
||||||
|
logforth = ["dep:logforth", "dep:opentelemetry-otlp"]
|
||||||
tokio = ["dep:tokio"]
|
tokio = ["dep:tokio"]
|
||||||
# Very long running.
|
# Very long running.
|
||||||
get_time_test = []
|
get_time_test = []
|
||||||
|
@ -63,3 +67,8 @@ eyre = { version = "0.6.12" }
|
||||||
num_cpus = { version = "1.17.0", optional = true }
|
num_cpus = { version = "1.17.0", optional = true }
|
||||||
either = "1.15.0"
|
either = "1.15.0"
|
||||||
humantime = "2.3.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 }
|
||||||
|
|
|
@ -149,6 +149,8 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
let component_configs = ComponentConfigs::new(map);
|
let component_configs = ComponentConfigs::new(map);
|
||||||
|
crate::logging::logforth::setup(component_configs.get());
|
||||||
|
|
||||||
let rt_config = component_configs.get::<rt::RtConfig>();
|
let rt_config = component_configs.get::<rt::RtConfig>();
|
||||||
|
|
||||||
let rt = match rt_config.flavor {
|
let rt = match rt_config.flavor {
|
||||||
|
@ -184,5 +186,6 @@ impl Default for App {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.optional::<rt::RtConfig>("system.rt")
|
this.optional::<rt::RtConfig>("system.rt")
|
||||||
|
.optional::<crate::logging::logforth::Config>("system.logging")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{collections::HashMap, str::CompactString, trait_set};
|
use crate::{collections::HashMap, str::CompactString, trait_set};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
mem,
|
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
|
fmt, mem,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
sync::{
|
sync::{
|
||||||
Arc, Mutex,
|
Arc, Mutex,
|
||||||
|
@ -91,11 +91,21 @@ pub struct ComponentConfig<T> {
|
||||||
handle: Arc<ConfigHandle>,
|
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> {
|
impl<T: IsComponentConfig> ComponentConfig<T> {
|
||||||
pub fn section(&self) -> &str {
|
pub fn section(&self) -> &str {
|
||||||
&self.handle.section
|
&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.
|
/// Update component config. Returns previous config if something's changed.
|
||||||
pub fn try_update(&mut self) -> Option<T> {
|
pub fn try_update(&mut self) -> Option<T> {
|
||||||
let generation = self.handle.generation.load(Ordering::Relaxed);
|
let generation = self.handle.generation.load(Ordering::Relaxed);
|
||||||
|
|
|
@ -28,6 +28,8 @@ pub use trait_set::trait_set;
|
||||||
#[cfg(feature = "cli")]
|
#[cfg(feature = "cli")]
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
|
||||||
|
pub mod logging;
|
||||||
|
|
||||||
pub mod array;
|
pub mod array;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
137
src/logging/logforth.rs
Normal file
137
src/logging/logforth.rs
Normal 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
4
src/logging/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
pub use log::{debug, error, info, log, log_enabled, trace, warn};
|
||||||
|
|
||||||
|
#[cfg(feature = "logforth")]
|
||||||
|
pub mod logforth;
|
|
@ -1,5 +1,6 @@
|
||||||
use compact_str::ToCompactString;
|
use compact_str::ToCompactString;
|
||||||
use eyre::eyre;
|
use eyre::eyre;
|
||||||
|
use fastrace::{Span, future::FutureExt, prelude::SpanContext};
|
||||||
use tokio::{sync::mpsc, task::JoinSet};
|
use tokio::{sync::mpsc, task::JoinSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -82,6 +83,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Supervisor {
|
pub struct Supervisor {
|
||||||
|
span: Span,
|
||||||
set: JoinSet<eyre::Result<()>>,
|
set: JoinSet<eyre::Result<()>>,
|
||||||
handles: HashMap<CompactString, Handle>,
|
handles: HashMap<CompactString, Handle>,
|
||||||
configs: ComponentConfigs,
|
configs: ComponentConfigs,
|
||||||
|
@ -90,6 +92,7 @@ pub struct Supervisor {
|
||||||
impl Supervisor {
|
impl Supervisor {
|
||||||
pub fn new(configs: ComponentConfigs) -> Self {
|
pub fn new(configs: ComponentConfigs) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
span: Span::root("supervisor", SpanContext::random()),
|
||||||
set: JoinSet::new(),
|
set: JoinSet::new(),
|
||||||
handles: HashMap::default(),
|
handles: HashMap::default(),
|
||||||
configs,
|
configs,
|
||||||
|
@ -108,35 +111,38 @@ impl Supervisor {
|
||||||
let config = self.configs.get::<T>();
|
let config = self.configs.get::<T>();
|
||||||
let name = config.section().to_compact_string();
|
let name = config.section().to_compact_string();
|
||||||
|
|
||||||
self.set.spawn(async move {
|
self.set.spawn(
|
||||||
let fut = f(config, slave_rx);
|
async move {
|
||||||
tokio::pin!(fut);
|
let fut = f(config, slave_rx);
|
||||||
loop {
|
tokio::pin!(fut);
|
||||||
tokio::select! {
|
loop {
|
||||||
res = &mut fut => {
|
tokio::select! {
|
||||||
break res;
|
res = &mut fut => {
|
||||||
}
|
break res;
|
||||||
|
}
|
||||||
|
|
||||||
cmd = rx.recv(), if !rx.is_closed() => {
|
cmd = rx.recv(), if !rx.is_closed() => {
|
||||||
let Some(cmd) = cmd else {
|
let Some(cmd) = cmd else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
match cmd {
|
match cmd {
|
||||||
SupervisorCommand::Ping { pong } => {
|
SupervisorCommand::Ping { pong } => {
|
||||||
pong.wake();
|
pong.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
SupervisorCommand::User(u) => {
|
SupervisorCommand::User(u) => {
|
||||||
if stx.send(u).await.is_err() {
|
if stx.send(u).await.is_err() {
|
||||||
rx.close();
|
rx.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
.in_span(Span::enter_with_parent(name.clone(), &self.span)),
|
||||||
|
);
|
||||||
|
|
||||||
let hash_map::Entry::Vacant(vac) = self.handles.entry(name.clone()) else {
|
let hash_map::Entry::Vacant(vac) = self.handles.entry(name.clone()) else {
|
||||||
panic!("{name:?} already exists")
|
panic!("{name:?} already exists")
|
||||||
|
@ -169,6 +175,8 @@ impl Supervisor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fastrace::flush();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue