byre

Crates.iobyre
lib.rsbyre
version
sourcesrc
created_at2024-12-31 18:28:07.840513
updated_at2025-02-02 20:23:10.012046
descriptionA set of libs for quickly bootstrapping a project
homepage
repositoryhttps://github.com/halzy/byre
max_upload_size
id1500277
Cargo.toml error:TOML parse error at line 18, column 1 | 18 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include`
size0
Benjamin Halsted (halzy)

documentation

README

Byre

Byre is a toolbox for bootstrapping services quickly. Providing tracing, logging, configuration file generation and loading, and command line argument parsing.

Byre leans on tracing, opentelemetry, clap, doku, tokio and others.

Byre is a rough fork of Cloudflare Foundations with some bits copied directly and others used as inspiration. Byre differs from Foundations in the ecosystems that it draws from.

Build status Crates.io Docs.rs

Application Config Generation

Byre is opinionated about application configuration. Configuration generation MUST be available by running the application. The clap crate is used for the cli argument parsing and help display:

❯ ./data_archive --help
database archive service

Usage: data_archive [OPTIONS]

Options:
  -c, --config <config>      Specifies the toml config file to run the service with
  -g, --generate <generate>  Generates a new default toml config file for the service
  -h, --help                 Print help
  -V, --version              Print version

Config generation uses Doku. The following Settings struct will produce the toml below.

use std::path::PathBuf;

use doku::Document;
use serde::Deserialize;

/// Data Archive Settings
#[derive(Document, Deserialize)]
pub struct Settings {
    /// App Settings
    pub application: Application,

    /// Telemetry settings.
    pub telemetry: byre::telemetry::TelemetrySettings,
}

#[derive(Document, Deserialize)]
pub struct Application {
    /// Port to listen on for gRPC status requests
    #[doku(example = "8080")]
    pub listen_port: u16,

    /// Hostname to listen on for gRPC status requests
    #[doku(example = "localhost")]
    pub listen_host: String,

    /// Directory where the application databases are located
    #[doku(example = "/var/db/reverb")]
    pub application_db_dir: PathBuf,
}

The generated toml config file:

# App Settings
[application]
# Port to listen on for gRPC status requests
listen_port = 8080

# Hostname to listen on for gRPC status requests
listen_host = "localhost"

# Directory where the application databases are located
application_db_dir = "/var/db/reverb"

[telemetry.trace]
# Optional
endpoint = "http://localhost:4317"

[telemetry.log]
console_level = "debug,yourcrate=trace"
otel_level = "warn,yourcrate=debug"
# Optional
endpoint = "http://localhost:4317"

[telemetry.metric]
# Optional
endpoint = "http://localhost:4318/v1/metrics"

As you can see, the doc comments are written into the config, and the Doku example becomes the value.

Application start-up

Parsing CLI arguments, loading app config file, and setting up telemetry is done in approximately 4 lines (excluding the structs for the config), making it simple and consistent to use.

#[tokio::main]
async fn main() -> Result<(), Error> {
    // Parse command line arguments. Add additional command line option that allows checking
    // the config without running the server.
    let service_info = byre::service_info!();
    let cli = byre::cli::Cli::<settings::Settings>::new(&service_info, "APP_");

    let _telemetry = byre::telemetry::init(&service_info, &cli.config.telemetry)
        .with_context(|_| TelemetryInitSnafu {})?;

    // Find the SocketAddr that we should bind to
    let listen_port = cli.config.application.listen_port;
    let listen_hostname = cli.config.application.listen_host;

    // ...
}

Config overrides from the environment

Environment variables override the values parsed form the config file. In this example "APP_" is the common prefix. If you do not want a prefix, pass an empty string ("").

let cli = byre::cli::Cli::<settings::Settings>::new(&service_info, "APP_");

Overriding values in a nested structure is possible. For example, if we wanted to override the application.listen_port you would set an environment variable APP_APPLICATION__LISTEN_PORT. Notice the double underscore (__), it is used in place of a period (.).

OpenTelemetry

Setting up the connection to OpenTelemetry systems is done by calling init:

    let _telemetry = byre::telemetry::init(&service_info, &cli.config.telemetry)
        .with_context(|_| TelemetryInitSnafu {})?;

Logging, Telemetry, and Metrics are available. To disable sending traces, log, or metrics you can remove the optional endpoint. If you want to disable console logs set console_level to "off".

[telemetry.trace]
# Optional
endpoint = "http://localhost:4317"

[telemetry.log]
console_level = "debug,yourcrate=trace"
otel_level = "warn,yourcrate=debug"
# Optional
endpoint = "http://localhost:4317"

[telemetry.metric]
# Optional
endpoint = "http://localhost:4318/v1/metrics"
Commit count: 16

cargo fmt