relastic 0.4.8

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

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

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

## Purpose

<!-- What does the application do and why? What problem does it solve? -->

Log to Elastic from Rust applications

## Intended consumers

<!--  Who is the application intended for, and who can utilize its features? -->

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

## Main technologies

<!-- What are the main languages and frameworks are used in the project -->

- Rust
- NixShell

## Available at

<!-- If the application is live, mention where it can be 'viewed' and where it is deployed, e.g. OpenShift, Azure etc. -->
<!-- For libraries, this might also include what package repository it's available at -->
<!-- If the project is an API or a library, where can I find documentation for it? -->

crates.io (relastic)

## Requirements

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

## More documentation

- `cargo doc --open` or [docs.rs]https://docs.rs/relastic/latest/relastic/

## 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

```rs
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](https://rocket.rs)

```rs
#[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:

```rs
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.

```rs
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.