logberg — удобный структурированный логгер для Rust с минимальным API и “правильной” эргономикой:
- Макросы уровней:
trace!,debug!,info!,warn!,error! - Structured fields (поля) прямо в макросах:
info!("user login"; user_id = 42, ip = "127.0.0.1") - Scoped context (контекст на блок):
with_fields! { request_id = "req-1" => { ... } }
Все логи внутри блока автоматически получают эти поля. - Форматы: Pretty (читаемый) и JSON
- Фильтрация уровней через
RUST_LOG(какenv_logger) - Опционально: timestamp (feature
time), ANSI-раскраска (featureansi), файл (featurefile)
Идея: быстро подключить логирование в приложении без “тяжелой” экосистемы, но сохранить structured-логи и контекст.
use logberg::{Logberg, Format};
fn main() {
Logberg::builder()
.format(Format::Pretty)
.level_from_env("RUST_LOG")
.init()
.expect("logger init");
logberg::info!("hello"; user_id = 42, action = "login");
}Запуск с фильтром:
RUST_LOG=info,my_app=debug cargo runuse logberg::{Logberg, Format};
Logberg::builder()
.format(Format::Pretty) // или Format::Json
.level_from_env("RUST_LOG") // читает env-filter выражение
.include_file_line(true) // (опционально) file:line
.include_thread(true) // (опционально) имя/ID потока
.include_target(true) // (опционально) record.target()
.include_module(false) // (опционально) module_path
.use_stderr_for_errors(true) // error -> stderr, остальное -> stdout
.init()
.unwrap();logberg::Logberg::init().unwrap();Дефолты:
- формат:
Pretty - уровень:
info stderrдля ошибок: включеноtarget: включен- timestamp зависит от feature
time
logberg::info!("service started");
logberg::warn!("cache miss");
logberg::error!("db unavailable");Синтаксис:
level!("message"; key = value, key2 = value2, ...)
logberg::info!("user login";
user_id = 42,
ip = "127.0.0.1",
ok = true,
);Правила:
key— идентификатор (напримерuser_id,request_id)value— любое выражение, форматируется черезDisplay(format!("{}", value))
Если тебе нужно “красиво печатать” сложные структуры, обычно удобно передавать заранее подготовленную строку (например, через
format!("{:?}", x)).
Иногда нужно добавить одни и те же поля ко всем логам внутри обработки запроса.
logberg::with_fields! { request_id = "req-123", user_id = 42 =>
{
logberg::debug!("handling request"; path = "/v1/items");
logberg::warn!("slow query"; ms = 317);
}
}Контекст:
- работает в текущем потоке (thread-local)
- вложенные
with_fields!накапливают поля (внутренний блок добавляет свои)
Пример:
2026-04-12T10:20:30Z INFO {my_app}: user login | user_id=42 ip=127.0.0.1 ok=true
Опционально можно включить:
include_thread(true)→ добавляет[thread]include_file_line(true)→ добавляет(file.rs:123)include_module(true)→ добавляетmodule_path
Пример:
{
"ts":"2026-04-12T10:20:30Z",
"level":"INFO",
"msg":"user login",
"target":"my_app",
"fields":{"user_id":"42","ip":"127.0.0.1","ok":"true"}
}JSON удобен для сборщиков логов (ELK/Datadog/Loki и т.п.).
logberg использует формат, совместимый по духу с env_logger:
RUST_LOG=info cargo run
RUST_LOG=debug,my_app=trace cargo run
RUST_LOG=warn,hyper=error cargo runВ Cargo.toml:
logberg = { version = "0.1", features = ["time", "ansi"] }Доступные фичи:
time— добавляет timestamp RFC3339 (UTC)ansi— раскраска уровней в Pretty-форматеfile— (опционально) запись в файл (если включено в реализации крейта)
Если в твоей версии крейта
filefeature включен: см. раздел “Лог в файл”.
Cargo.toml:
logberg = { version = "0.1", features = ["file"] }Код:
use logberg::{Format, Logberg};
Logberg::builder()
.format(Format::Json)
.level_from_env("RUST_LOG")
.file("app.log")
.init()
.unwrap();Поведение:
- логи пишутся в stdout/stderr (по правилам) и дополнительно в файл
- файл открывается в режиме append, создается при отсутствии
logberg является backend’ом для стандартного crate log, поэтому:
- макросы
log::info!и т.п. тоже будут работать - можно использовать сторонние библиотеки, которые логируют через
log
- Structured fields хранятся как строки (
Display), то есть типы не сохраняются как “настоящие JSON-числа/boolean”.
Это сделано ради простоты и стабильности API. Если нужно типизированное JSON — скажи, добавим режим “typed json”. - Scoped context — thread-local, т.е. не переносится автоматически между потоками и задачами async runtime.
Для async-мира можно сделать интеграцию черезtracing/Span-подобный контекст или через явную передачу контекста.
Logberg::builder()
.use_stderr_for_errors(true)
.init()
.unwrap();let mut b = logberg::Logberg::builder()
.level_from_env("RUST_LOG");
if cfg!(debug_assertions) {
b = b.include_file_line(true);
}
b.init().unwrap();MIT OR Apache-2.0