Skip to content

ifeanyi-ugwu/logform_rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

logform

Crates.io Rust

A flexible log formatting library designed for chaining and composing log transformations in Rust.

Overview

logform provides a powerful, extensible system to transform structured log messages via composable formatters called Formats. Each format implements a common Format trait, enabling flexible composition and transformation pipelines.

Quick Start

use logform::{timestamp, colorize, align, Format, LogInfo};

fn main() {
    // Compose multiple formats using chaining
    let formatter = timestamp()
        .chain(colorize())
        .chain(align());

    let info = LogInfo::new("info", "Hello, logform!");

    // Apply the composed formatter
    if let Some(transformed) = formatter.transform(info) {
        println!("{}", transformed.message);
    }
}

LogInfo — Structured Log Data

At the core is the LogInfo struct representing a single log message:

pub struct LogInfo {
    pub level: String,
    pub message: String,
    pub meta: std::collections::HashMap<String, serde_json::Value>,
}

Common usage

  • Create a new LogInfo:

    let info = LogInfo::new("info", "User logged in");
  • Add metadata fields:

    let info = info.with_meta("user_id", 12345)
                   .with_meta("session_id", "abcde12345");
  • Remove metadata:

    let info = info.without_meta("session_id");
  • Access metadata:

    if let Some(serde_json::Value::Number(id)) = info.meta.get("user_id") {
            // use id...
    }

The Format Trait

Formats implement the Format trait to transform log messages:

pub trait Format {
    type Input;

    /// Transforms the input log message, returning:
    /// - `Some(LogInfo)` for transformed logs
    /// - `None` to filter out the log (skip it)
    fn transform(&self, input: Self::Input) -> Option<LogInfo>;

    /// Chain two formats, applying one after another
    fn chain<F>(self, next: F) -> ChainedFormat<Self, F>
    where
        Self: Sized,
        F: Format<Input = Self::Input>,
    {
        ChainedFormat { first: self, next }
    }
}
  • Transform: Modify or produce a new log from input.
  • Filter (return None): Skip processing or output for certain logs.
  • Chaining: Compose formats easily in sequence.

Composing Formats

You can chain multiple formats using the chain method:

let combined = timestamp().chain(json()).chain(colorize());

Or use the chain! macro for succinct chaining of multiple formats:

use logform::chain;

let combined = chain!(timestamp(), json(), colorize());

Chaining stops early when any format returns None (useful for filtering logs).

Available Formats

timestamp

Adds a timestamp to the log metadata.

Builder methods:

  • .with_format(&str) — Customize timestamp display format (uses chrono formatting).
  • .with_alias(&str) — Add an alias field for the timestamp.
let ts = timestamp()
    .with_format("%Y-%m-%d %H:%M:%S")
    .with_alias("time");

simple

A minimal text formatter producing output like:

level:    message { ...metadata... }

Respects padding stored in meta under "padding" to align levels nicely.

json

Serializes the log info into a JSON string:

{ "level": "info", "message": "User logged in", "user_id": 12345 }

align

Adds a tab character before the message, useful for aligned output.

cli

Combines colorizing and padding:

  • Colors the level and/or message.
  • Pads messages for neat CLI output.
  • Configurable via builder methods like .with_levels(), .with_colors(), .with_filler(), and .with_all().

Example:

let cli_format = cli()
    .with_filler("*")
    .with_all(true);

let out = cli_format.transform(info).unwrap();

colorize

Provides colorization for levels and messages via colored crate.

Configurable options include:

  • .with_all(bool)
  • .with_level(bool)
  • .with_message(bool)
  • .with_colors(...) to specify colors for levels.

uncolorize

Strips ANSI color codes from level and/or message.

label

Adds a label either as a prefix to the message or into metadata.

Builder:

  • .with_label("MY_LABEL")
  • .with_message(true|false) — if true, prefix message; else add to meta.

logstash

Transforms the log info into a Logstash-compatible JSON string with fields like @timestamp, @message, and @fields.

metadata

Collects metadata keys into a single key.

Builder methods:

  • .with_key(&str) — metadata container key (default: "metadata").
  • .with_fill_except(Vec<&str>) — exclude keys.
  • .with_fill_with(Vec<&str>) — include only these keys.

ms

Adds time elapsed since the previous log message in milliseconds in the meta key "ms".

pad_levels

Pads the message to align levels uniformly.

Configurable:

  • .with_levels(...)
  • .with_filler(...)

pretty_print

Prettifies log output in a human-friendly format, optionally colorized.

Builder:

  • .with_colorize(bool)

printf

Customize the output with any formatting closure:

let printf_format = printf(|info| {
    format!("{} - {}: {}",
        info.level,
        info.message,
        serde_json::to_string(&info.meta).unwrap()
    )
});

Filtering Logs

A format can filter out unwanted logs by returning None from transform.

Example:

struct IgnorePrivate;

impl Format for IgnorePrivate {
    type Input = LogInfo;

    fn transform(&self, info: LogInfo) -> Option<LogInfo> {
        if let Some(private) = info.meta.get("private") {
            use serde_json::Value;
            if matches!(private, Value::Bool(true)) || private == "true" {
                return None;
            }
        }
        Some(info)
    }
}

When chained, subsequent formats will not run if any upstream returns None.

Extending logform

Implement Format for custom transformations over any input type:

struct UpperCase;

impl Format for UpperCase {
    type Input = String;

    fn transform(&self, input: String) -> Option<String> {
        if input.is_empty() {
            None
        } else {
            Some(input.to_uppercase())
        }
    }
}

Then chain with other formats for composable log processing.

Installation

Add to your Cargo.toml:

[dependencies]
logform = "0.5"

Or use cargo:

cargo add logform

License

This project is licensed under the MIT License.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages