log_loki

log_loki facilitates collecting and shipping your application's logs to a Loki instance. It does this by integrating with the log crate.

Please be advised that I do not consider this crate production ready at this time. I've verified that it "basically works," but I have yet to write comphrensive tests and optimize out any inefficiencies that may exist. Caveat emptor!

Installation

To add log_loki to your project, ensure the following two lines are present in your Cargo.toml:

toml log = "^0.4.17" log_loki = "^0.1.0"

Features

The crate supports the following features: - tls - Use rustls to support communicating with Loki over TLS. - tls-native-certs - Tell ureq, the underlying HTTP library, to use the system's certificate store instead of the webpki-roots store for TLS. - compress - Compress logs en route to Loki using GZIP (through the flate2 crate). - kv_unstable - Enable experimental support for the log crate's structured logging. - logfmt - Enable the logfmt formatter for logs.

The default features are tls, tls-native-certs, logfmt, and compress. By default, the logfmt feature is used to format logs. If the feature is disabled, you must provide your own LokiFormatter implementation.

## Usage

To log exclusively to an unauthenticated Loki instance, the following may be used:

```Rust use log::{info, logger}; use log_loki::LokiBuilder; use url::Url; use std::collections::HashMap;

fn main() { let mut labels = HashMap::new(); labels.insert("app", "myapp");

LokiBuilder::new(
    Url::parse("https://loki.example.com/loki/api/v1/push").unwrap(),
    labels,
).build().apply().unwrap();

info!("Hello, {}!", "world");

// The logger must be flushed before the application quits to ensure logs are not lost.
logger().flush();

} ``` Through the .addheader() and .tlsconfig() LokiBuilder methods, header and mTLS-based authentication schemes can be used.

If you'd like to log to Loki as well as other locations (such as a log file, console, etc), you can use a logging framework like Fern to combine log_loki with other logging implementations:

```Rust // Let loki be a Loki object let colors = ColoredLevelConfig::default();

fern::Dispatch::new() .level(log::LevelFilter::Trace) .chain(Box::new(loki) as Box) .chain(fern::Dispatch::new() .format(move |out, message, record| { out.finish(formatargs!("[{}] {}", colors.color(record.level()), message)) }) .chain(std::io::stdout()) .intoshared() ) .apply().unwrap();

info!("Test!");

// call somewhere before the program ends logger().flush(); ```

Flushing

For efficiency's sake, the logger buffers log messages internally and waits until either a certain amount of messages have been logged or a certain amount of time has passed. You can tweek the number of messages or the duration between auto-flushes using the max_logs() and max_log_lifetime() LokiBuilder methods respectively. It is also recommended that you arrange for all exit paths in your code to call logger().flush(); to minimize the risk of any logs being dropped.

License

```Rust /* Copyright (C) 2022 Aurora McGinnis

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

*/ ```