Skip to content
/ byre Public

A set of libs for quickly bootstrapping a new Rust server project

Notifications You must be signed in to change notification settings

halzy/byre

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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"

About

A set of libs for quickly bootstrapping a new Rust server project

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages