#elastic #logging #information #macro #relastic

relastic

Simple rust lib inspired by Serilog for application-wide logging to Elastic

16 releases

new 0.4.6 Apr 25, 2025
0.4.5 Aug 21, 2023
0.4.4 Jun 7, 2023
0.3.2 May 26, 2023
0.1.1 Nov 30, 2021

#122 in Debugging

Download history 1/week @ 2025-01-06 1/week @ 2025-01-13 2/week @ 2025-01-20 2/week @ 2025-01-27 5/week @ 2025-03-10 8/week @ 2025-03-17 24/week @ 2025-03-31 12/week @ 2025-04-07 2/week @ 2025-04-14 115/week @ 2025-04-21

155 downloads per month

MIT license

39KB
785 lines

Relastic

Simple rust lib inspired by Serilog for application-wide logging:

  • Application wide logs
  • Posting logs to Elastic to access them with Kibana

Purpose

Log to Elastic from Rust applications

Intended consumers

Everyone. Do not use in production without first assessing the risks involved.

Main technologies

  • Rust
  • NixShell

Available at

crates.io (relastic)

Requirements

  • Rust or Nix and Direnv (this will install rust for you)

More documentation

Testing locally

  • cargo test in the main folder to run tests

Known issues

  • Needs to explicitly wait before closing sender since sender is non-blocking.
  • No support for creating/updating templates from code
  • HashMaps for mapping values
  • We probably don't need to put sender behind RwLock (although the RwLock has no cap on readers)

Usage

fn main() {
    let elastic_config = match elastic_config::ElasticConfig::new() {
        Ok(x) => x,
        Err(err) => panic!("Elastic not/improperly configured: {:?}", err),
    };
    log::setup_elastic_log(
        elastic_config,
        100,
    );

    /* ... */

    log::flush();
}

Usage with Rocket.rs

Here's how you can setup relastic with Rocket

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
    let rocket = rocket::build()
        .attach(AdHoc::try_on_ignite("Services", |rocket| async {
            let elastic_config = match elastic_config::ElasticConfig::new() {
                Ok(x) => x,
                Err(err) => panic!("Elastic not/improperly configured: {:?}", err),
            };
            log::setup_elastic_log(
                elastic_config,
                100,
            );

            Ok(rocket)
        }))
        .attach(AdHoc::on_shutdown("Services", |rocket| {
            Box::pin(async {
                log_information!("Flushing logs", "");
                log::flush();
            })
        }))
        .mount("/", routes![index]);

    let result = match rocket.launch().await {
        Ok(_x) => Ok(()),
        Err(err) => Err(err),
    };
    result
}

This also makes it so that we don't have to rely on Rocket-specific dependencies.

Log to console in dev-environment

You may want to simplify logging while you're developing, by logging to console instead:

use intility_cloud_lib::env_tools::{get_env, get_env_enum, Error};
use relastic::log::{self, ElasticConfig, LogEnvironment};
use std::collections::HashMap;

fn load_if_prod(name: &str, env_type: &LogEnvironment) -> Result<String, Error> {
    match env_type {
        LogEnvironment::Development => Ok(String::with_capacity(0)),
        LogEnvironment::Production => get_env(name),
    }
}

pub fn get_config() -> Result<ElasticConfig, Error> {
    let env_type = get_env_enum::<LogEnvironment>("APPLICATION_ENVIRONMENT")?;
    let username = load_if_prod("ELASTIC_USERNAME", &env_type)?;
    let password = load_if_prod("ELASTIC_PASSWORD", &env_type)?;
    let url = load_if_prod("ELASTIC_URL", &env_type)?;
    let environment_string = get_env_enum::<LogEnvironment>("APPLICATION_ENVIRONMENT")?;
    let application_name = get_env("APPLICATION_NAME")?;

    Ok(ElasticConfig {
        username,
        password,
        url,
        environment: environment_string,
        application_name,
    })
}

pub fn get_config_or_log_and_panic() -> ElasticConfig {
    match get_config() {
        Ok(x) => x,
        Err(err) => {
            log_fatal!(
                "Elastic config is missing or is misconfigured: {err}",
                format!("{}", err)
            );
            panic!("{}", err)
        }
    }
}

fn main() {
    let elastic_config = get_config_or_log_and_panic();
    if elastic_config.environment == LogEnvironment::Production {
        log::setup_elastic_log(elastic_config.clone(), 100);
    } else {
        log::setup_console_log()
    }

    /* ... */

    log::flush();
}

This way you don't have to actually set any environment variables when working locally.

How to log

When logging you can either use the log functions directly, or you can use the included macros to reduce the amount of boilerplate code needed.

pub fn my_fn()
{
    // Logging with a macro
    log_information!("Got the following message: {message}", "Hello world");

    // Logging with a function:
    log::information(
        "Got the following message: {message}",
        HashMap::from([
            ("message", "Hello World!".to_string())
        ])
    );
}

Contributing

You are welcome to reports bugs, contribute code or open issues.

Dependencies

~5–19MB
~287K SLoC