Skip to main content

Macros

Procedural macros for ttlog — info!, debug!, warn!, error! with compile-time work and string interning.

The ttlog-macros crate provides the user-facing logging API. The procedural macros push as much work as possible to compile time.

Available Macros

One macro per standard log level:

  • trace!
  • debug!
  • info!
  • warn!
  • error!
  • fatal!

Usage

1. Message Only

Equivalent to println!.

use ttlog_macros::info;

info!("User successfully authenticated.");

2. Message with Structured Data (Key-Value Pairs)

Add context with key = value. The message is the last string literal in the argument list.

use ttlog_macros::warn;

let user_id = 123;
let attempt_count = 3;
warn!(user_id = user_id, attempts = attempt_count, "Failed login attempt");

3. Structured Data Only

Key-value pairs without a message.

use ttlog_macros::debug;

let db_latency_ms = 55;
let query = "SELECT * FROM users";
debug!(latency = db_latency_ms, query = query);

4. Event-Only Logging

Log an occurrence with no message or data.

use ttlog_macros::trace;

trace!("Entering critical section");
// ... some code ...
trace!(); // Log that we've entered the section

How It Works

The macros push work from runtime to compile time.

  1. Static string interning: arguments parse at compile time. The message and key names are known, so the macro emits code that interns them once per application lifetime via std::sync::OnceLock. Later calls to the same site are integer lookups.

  2. Static metadata: file path, module path, and line number come from file!(), module_path!(), and line!() — no runtime gathering.

  3. Value serialization: key-value pairs serialize to a compact binary format. Primitive integers (i64, u64) and floats (f32, f64) convert to strings directly, not through serde.

  4. Direct logger call: expanded code calls into the ttlog crate's GLOBAL_LOGGER with no intermediate abstraction.

Each info! call expands to code tailored to the arguments passed.