Skip to content

Commit

Permalink
clean up and better document MartinObservability
Browse files Browse the repository at this point in the history
  • Loading branch information
CommanderStorm committed Mar 8, 2025
1 parent 434ba90 commit ae69b9b
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 13 deletions.
2 changes: 1 addition & 1 deletion martin-observability-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
readme.workspace = true
readme = "README.md"
homepage.workspace = true

[dependencies]
Expand Down
24 changes: 24 additions & 0 deletions martin-observability-utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# martin-observability-utils

[![docs.rs docs](https://docs.rs/martin-observability-utils/badge.svg)](https://docs.rs/martin-observability-utils)
[![](https://img.shields.io/badge/Slack-%23maplibre--martin-blueviolet?logo=slack)](https://slack.openstreetmap.us/)
[![GitHub](https://img.shields.io/badge/github-maplibre/martin-8da0cb?logo=github)](https://github.com/maplibre/martin)
[![crates.io version](https://img.shields.io/crates/v/martin-observability-utils.svg)](https://crates.io/crates/martin-observability-utils)
[![CI build](https://github.com/maplibre/martin/actions/workflows/ci.yml/badge.svg)](https://github.com/maplibre/martin-observability-utils/actions)

A library to help tile servers like [Martin](https://maplibre.org/martin) do observability.

## License

Licensed under either of

* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the
Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
54 changes: 42 additions & 12 deletions martin-observability-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
#![doc = include_str!("../README.md")]

#[derive(Default)]
pub struct MartinObservability {
log_format: LogFormat,
log_level: LogLevel,
}
impl MartinObservability {
/// Set the log format for the application
#[must_use]
pub fn with_log_format(mut self, log_format: LogFormat) -> Self {
self.log_format = log_format;
self
}
/// Set the log level for the application
#[must_use]
pub fn with_log_level(mut self, log_level: LogLevel) -> Self {
self.log_level = log_level;
self
}
/// transform [`log`](https://docs.rs/log) records into [`tracing`](https://docs.rs/tracing) [`Event`](tracing::Event)s.
///
/// # Errors
/// # Panics
/// This function will panic if the global `log`-logger cannot be set.
/// This only happens if the global `log`-logger has already been set.
#[must_use]
pub fn with_initialised_log_tracing(self) -> Self {
tracing_log::LogTracer::builder()
.with_interest_cache(tracing_log::InterestCacheConfig::default())
Expand All @@ -28,34 +33,55 @@ impl MartinObservability {
}
/// Set the global subscriber for the application.
///
/// # Errors
/// # Panics
/// This function will panic if the global subscriber cannot be set.
/// This only happens if the global subscriber has already been set.
pub fn set_global_subscriber(self) {
use tracing::subscriber::set_global_default;
use tracing_subscriber::fmt::Layer;
use tracing_subscriber::prelude::*;
let registry = tracing_subscriber::registry()
.with(tracing_subscriber::filter::EnvFilter::from(self.log_level))
.with((self.log_format == LogFormat::Json).then(|| Layer::default().json()))
.with((self.log_format == LogFormat::Pretty).then(|| Layer::default().pretty()))
.with((self.log_format == LogFormat::Compact).then(|| Layer::default().compact()));
tracing::subscriber::set_global_default(registry)
.expect("since martin has not set the global_default, no global default is set");
.with(tracing_subscriber::filter::EnvFilter::from(self.log_level));
match self.log_format {
LogFormat::Full => set_global_default(registry.with(Layer::default())),
LogFormat::Compact => set_global_default(registry.with(Layer::default().json())),
LogFormat::Pretty => set_global_default(registry.with(Layer::default().pretty())),
LogFormat::Json => set_global_default(registry.with(Layer::default().compact())),
}
.expect("since martin has not set the global_default, no global default is set");
}
}

#[derive(PartialEq, Eq, Clone, Copy, Default)]
pub enum LogFormat {
Json,
Pretty,
/// Emits human-readable, single-line logs for each event that occurs, with the current span context displayed before the formatted representation of the event.
/// See [here](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/format/struct.Full.html#example-output) for sample output.
Full,
/// A variant of [`LogFormat::Full`], optimized for short line lengths.
/// Fields from the current span context are appended to the fields of the formatted event.
/// See [here](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/format/struct.Compact.html#example-output) for sample output.
#[default]
Compact,
/// Emits excessively pretty, multi-line logs, optimized for human readability.
/// This is primarily intended to be used in local development and debugging, or for command-line applications, where automated analysis and compact storage of logs is less of a priority than readability and visual appeal.
/// See [here](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/format/struct.Pretty.html#example-output) for sample output.
Pretty,
/// Outputs newline-delimited JSON logs.
/// This is intended for production use with systems where structured logs are consumed as JSON by analysis and viewing tools.
/// The JSON output is not optimized for human readability.
/// See [here](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/format/struct.Json.html#example-output) for sample output.
Json,
}
impl LogFormat {
/// log format (how the logs are formatted on the cli) from an environment variable
///
/// Default: [`LogFormat::Compact`]
#[must_use]
pub fn from_env_var(key: &'static str) -> Self {
match std::env::var(key).unwrap_or_default().as_str() {
"json" | "jsonl" => LogFormat::Json,
"full" => LogFormat::Full,
"pretty" | "verbose" => LogFormat::Pretty,
"json" | "jsonl" => LogFormat::Json,
_ => LogFormat::Compact,
}
}
Expand All @@ -66,7 +92,10 @@ pub struct LogLevel {
level: tracing::Level,
}
impl LogLevel {
/// environment variable key for the log level
/// Get log level from an environment variable
///
/// Default: [`LogLevel::default`]
#[must_use]
pub fn from_env_var(key: &'static str) -> Self {
let mut level = Self::default();
if std::env::var(key).is_ok() {
Expand All @@ -75,6 +104,7 @@ impl LogLevel {
level
}
/// Sets the environment variable key for the log level if it exsts
#[must_use]
pub fn or_default(mut self, level: tracing::Level) -> Self {
self.level = level;
self
Expand Down

0 comments on commit ae69b9b

Please sign in to comment.