feat: Factor out tracing/logging CLI options

This PR factors out the tracing/logging CLI optinos into the `trogging` utility crate,
so that multiple binaries from the IOx suite (such as conductor) can use the same (and quite complex)
logging/tracing configuration options (flags and env vars).

Closes influxdata/conductor#343
pull/24376/head
Marko Mikulicic 2021-06-16 00:11:04 +02:00
parent 38d17a3093
commit 760bcde3f0
No known key found for this signature in database
GPG Key ID: D02A41F91A687DB3
8 changed files with 388 additions and 293 deletions

1
Cargo.lock generated
View File

@ -4579,6 +4579,7 @@ dependencies = [
"opentelemetry-jaeger",
"opentelemetry-otlp",
"regex",
"structopt",
"synchronized-writer",
"thiserror",
"tracing-opentelemetry",

View File

@ -63,7 +63,7 @@ query = { path = "query" }
read_buffer = { path = "read_buffer" }
server = { path = "server" }
tracker = { path = "tracker" }
trogging = { path = "trogging" }
trogging = { path = "trogging", features = ["structopt"] }
# Crates.io dependencies, in alphabetical order
arrow = { version = "4.0", features = ["prettyprint"] }

View File

@ -1,13 +1,12 @@
//! Implementation of command line option for running server
use crate::commands::tracing;
use crate::influxdb_ioxd::{self, serving_readiness::ServingReadinessState};
use clap::arg_enum;
use core::num::NonZeroU16;
use data_types::server_id::ServerId;
use std::{net::SocketAddr, net::ToSocketAddrs, path::PathBuf};
use structopt::StructOpt;
use thiserror::Error;
use trogging::cli::TracingConfig;
/// The default bind address for the HTTP API.
pub const DEFAULT_API_BIND_ADDR: &str = "127.0.0.1:8080";
@ -43,233 +42,9 @@ Configuration is loaded from the following sources (highest precedence first):
- pre-configured default values"
)]
pub struct Config {
/// Logs: filter directive
///
/// Configures log severity level filter, by target.
///
/// Simplest options: error, warn, info, debug, trace
///
/// Levels for different modules can be specified. For example
/// `debug,hyper::proto::h1=info` specifies debug logging for all modules
/// except for the `hyper::proto::h1' module which will only display info
/// level logging.
///
/// Extended syntax provided by `tracing-subscriber` includes span/field
/// filters. See <https://docs.rs/tracing-subscriber/0.2.17/tracing_subscriber/filter/struct.EnvFilter.html> for more details.
#[structopt(long = "--log-filter", env = "LOG_FILTER", default_value = "warn")]
pub log_filter: String,
/// Logs: filter short-hand
///
/// Convenient way to set log severity level filter.
/// Overrides `--log-filter`.
///
/// -v 'info'
///
/// -vv 'debug,hyper::proto::h1=info,h2=info'
///
/// -vvv 'trace,hyper::proto::h1=info,h2=info'
#[structopt(
short = "-v",
long = "--verbose",
multiple = true,
takes_value = false,
parse(from_occurrences)
)]
pub log_verbose_count: u8,
#[rustfmt::skip]
/// Logs: message format
///
/// Can be one of:
///
/// full: human-readable, single line
///
/// Oct 24 12:55:47.815 ERROR shaving_yaks{yaks=3}: fmt::yak_shave: failed to shave yak yak=3 error=missing yak
/// Oct 24 12:55:47.815 TRACE shaving_yaks{yaks=3}: fmt::yak_shave: yaks_shaved=2
/// Oct 24 12:55:47.815 INFO fmt: yak shaving completed all_yaks_shaved=false
///
/// pretty: human-readable, multi line
///
/// Oct 24 12:57:29.387 fmt_pretty::yak_shave: failed to shave yak, yak: 3, error: missing yak
/// at examples/examples/fmt/yak_shave.rs:48 on main
/// in fmt_pretty::yak_shave::shaving_yaks with yaks: 3
///
/// Oct 24 12:57:29.387 fmt_pretty::yak_shave: yaks_shaved: 2
/// at examples/examples/fmt/yak_shave.rs:52 on main
/// in fmt_pretty::yak_shave::shaving_yaks with yaks: 3
///
/// Oct 24 12:57:29.387 fmt_pretty: yak shaving completed, all_yaks_shaved: false
/// at examples/examples/fmt-pretty.rs:19 on main
///
/// json: machine-parseable
///
/// {"timestamp":"Oct 24 13:00:00.875","level":"ERROR","fields":{"message":"failed to shave yak","yak":3,"error":"missing yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
/// {"timestamp":"Oct 24 13:00:00.875","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
/// {"timestamp":"Oct 24 13:00:00.875","level":"INFO","fields":{"message":"yak shaving completed","all_yaks_shaved":false},"target":"fmt_json"}
///
/// logfmt: human-readable and machine-parseable
///
/// level=info msg="This is an info message" target="logging" location="logfmt/tests/logging.rs:36" time=1612181556329599000
/// level=debug msg="This is a debug message" target="logging" location="logfmt/tests/logging.rs:37" time=1612181556329618000
/// level=trace msg="This is a trace message" target="logging" location="logfmt/tests/logging.rs:38" time=1612181556329634000
#[structopt(long = "--log-format", env = "LOG_FORMAT", default_value = "full", verbatim_doc_comment)]
pub log_format: tracing::LogFormat,
/// Logs: destination
///
/// Can be one of: stdout, stderr
//
// TODO(jacobmarble): consider adding file path, file rotation, syslog, ?
#[structopt(
long = "--log-destination",
env = "LOG_DESTINATION",
default_value = "stdout",
verbatim_doc_comment
)]
pub log_destination: tracing::LogDestination,
/// Tracing: exporter type
///
/// Can be one of: none, jaeger, otlp
///
/// When enabled, additional flags are considered (see flags related to OTLP
/// and Jaeger), and log output is disabled.
//
// TODO(jacobmarble): allow logs and traces simultaneously
#[structopt(
long = "--traces-exporter",
env = "TRACES_EXPORTER",
default_value = "none"
)]
pub traces_exporter: tracing::TracesExporter,
/// Tracing: filter directive
///
/// Configures traces severity level filter, by target.
///
/// Simplest options: error, warn, info, debug, trace
///
/// Levels for different modules can be specified. For example
/// `debug,hyper::proto::h1=info` specifies debug tracing for all modules
/// except for the `hyper::proto::h1` module which will only display info
/// level tracing.
///
/// Extended syntax provided by `tracing-subscriber` includes span/field
/// filters. See <https://docs.rs/tracing-subscriber/0.2.17/tracing_subscriber/filter/struct.EnvFilter.html> for more details.
///
/// No filter by default.
#[structopt(long = "--traces-filter", env = "TRACES_FILTER")]
pub traces_filter: Option<String>,
/// Tracing: sampler type
///
/// Can be one of:
/// always_on, always_off, traceidratio,
/// parentbased_always_on, parentbased_always_off, parentbased_traceidratio
///
/// These alternatives are described in detail at <https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/sdk-environment-variables.md#general-sdk-configuration>.
#[structopt(
long = "--traces-sampler",
env = "TRACES_SAMPLER",
default_value = "parentbased_traceidratio"
)]
pub traces_sampler: tracing::TracesSampler,
#[rustfmt::skip]
/// Tracing: sampler argument
///
/// Valid range: [0.0, 1.0].
///
/// Only used if `--traces-sampler` is set to
/// parentbased_traceidratio (default) or traceidratio.
///
/// With sample parentbased_traceidratio, the following rules apply:
/// - if parent is sampled, then all of its children are sampled
/// - else sample this portion of traces (0.5 = 50%)
///
/// More details about this sampling argument at <https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/sdk-environment-variables.md#general-sdk-configuration>.
#[structopt(
long = "--traces-sampler-arg",
env = "TRACES_SAMPLER_ARG",
default_value = "1.0",
verbatim_doc_comment
)]
pub traces_sampler_arg: f64,
/// Tracing: OTLP (eg OpenTelemetry collector) network hostname
///
/// Only used if `--traces-exporter` is "otlp".
///
/// Protocol is gRPC. HTTP is not supported.
#[structopt(
long = "--traces-exporter-otlp-host",
env = "TRACES_EXPORTER_OTLP_HOST",
default_value = "localhost"
)]
pub traces_exporter_otlp_host: String,
/// Tracing: OTLP (eg OpenTelemetry collector) network port
///
/// Only used if `--traces-exporter` is "otlp".
///
/// Protocol is gRPC. HTTP is not supported.
#[structopt(
long = "--traces-exporter-otlp-port",
env = "TRACES_EXPORTER_OTLP_PORT",
default_value = "4317"
)]
pub traces_exporter_otlp_port: NonZeroU16,
/// Tracing: Jaeger agent network hostname
///
/// Protocol is Thrift/Compact over UDP.
///
/// Only used if `--traces-exporter` is "jaeger".
#[structopt(
long = "--traces-exporter-jaeger-agent-host",
env = "TRACES_EXPORTER_JAEGER_AGENT_HOST",
default_value = "0.0.0.0"
)]
pub traces_exporter_jaeger_agent_host: String,
/// Tracing: Jaeger agent network port
///
/// Protocol is Thrift/Compact over UDP.
///
/// Only used if `--traces-exporter` is "jaeger".
#[structopt(
long = "--traces-exporter-jaeger-agent-port",
env = "TRACES_EXPORTER_JAEGER_AGENT_PORT",
default_value = "6831"
)]
pub traces_exporter_jaeger_agent_port: NonZeroU16,
/// Tracing: Jaeger service name.
///
/// Only used if `--traces-exporter` is "jaeger".
#[structopt(
long = "--traces-exporter-jaeger-service-name",
env = "TRACES_EXPORTER_JAEGER_SERVICE_NAME",
default_value = "iox"
)]
pub traces_exporter_jaeger_service_name: String,
/// Tracing: Jaeger max UDP packet size
///
/// Default to 1300, which is a safe MTU.
///
/// You can increase it to 65000 if the target is a jaeger collector
/// on localhost. If so, the batching exporter will be enabled for
/// extra efficiency. Otherwise an UDP packet will be sent for each exported span.
///
/// Only used if `--traces-exporter` is "jaeger".
#[structopt(
long = "--traces-exporter-jaeger-max-packet-size",
env = "TRACES_EXPORTER_JAEGER_MAX_PACKET_SIZE",
default_value = "1300"
)]
pub traces_exporter_jaeger_max_packet_size: usize,
// logging and tracing options
#[structopt(flatten)]
pub(crate) tracing_config: TracingConfig,
/// The identifier for the server.
///

View File

@ -1,8 +1,8 @@
//! Log and trace initialization and setup
use std::cmp::max;
pub use trogging::config::*;
pub use trogging::TracingGuard;
use trogging::{JaegerConfig, OtlpConfig};
/// Start simple logger. Panics on error.
pub fn init_simple_logs(log_verbose_count: u8) -> Result<TracingGuard, trogging::Error> {
@ -16,33 +16,11 @@ pub fn init_logs_and_tracing(
log_verbose_count: u8,
config: &crate::commands::run::Config,
) -> Result<TracingGuard, trogging::Error> {
let mut config = config.tracing_config.clone();
// Handle the case if -v/-vv is specified both before and after the server
// command
let log_verbose_count = if log_verbose_count > config.log_verbose_count {
log_verbose_count
} else {
config.log_verbose_count
};
config.log_verbose_count = max(config.log_verbose_count, log_verbose_count);
trogging::Builder::new()
.with_log_filter(&config.log_filter)
// with_verbose_count goes after with_log_filter because our CLI flag state
// that --v overrides --log-filter.
.with_log_verbose_count(log_verbose_count)
.with_log_destination(config.log_destination)
.with_log_format(config.log_format)
.with_traces_filter(&config.traces_filter)
.with_traces_exporter(config.traces_exporter)
.with_traces_sampler(config.traces_sampler, config.traces_sampler_arg)
.with_jaeger_config(JaegerConfig {
agent_host: config.traces_exporter_jaeger_agent_host.clone(),
agent_port: config.traces_exporter_jaeger_agent_port,
service_name: config.traces_exporter_jaeger_service_name.clone(),
max_packet_size: config.traces_exporter_jaeger_max_packet_size,
})
.with_oltp_config(OtlpConfig {
host: config.traces_exporter_otlp_host.clone(),
port: config.traces_exporter_otlp_port,
})
.install_global()
config.to_builder().install_global()
}

View File

@ -14,6 +14,7 @@ opentelemetry-jaeger = { version = "0.12", features = ["tokio"] }
opentelemetry-otlp = "0.6"
thiserror = "1.0.23"
tracing-opentelemetry = { version = "0.12", default-features = false }
structopt = { version = "0.3.21", optional = true }
[dev-dependencies]
synchronized-writer = "1"

337
trogging/src/cli.rs Normal file
View File

@ -0,0 +1,337 @@
///! Common CLI flags for logging and tracing
use crate::{config::*, Builder, Result, TracingGuard};
use observability_deps::tracing_subscriber::fmt::writer::BoxMakeWriter;
use std::num::NonZeroU16;
use structopt::StructOpt;
/// CLI config for the logging+tracing related subset of options.
#[derive(Debug, StructOpt, Clone)]
pub struct TracingConfig {
/// Logs: filter directive
///
/// Configures log severity level filter, by target.
///
/// Simplest options: error, warn, info, debug, trace
///
/// Levels for different modules can be specified. For example
/// `debug,hyper::proto::h1=info` specifies debug logging for all modules
/// except for the `hyper::proto::h1' module which will only display info
/// level logging.
///
/// Extended syntax provided by `tracing-subscriber` includes span/field
/// filters. See <https://docs.rs/tracing-subscriber/0.2.17/tracing_subscriber/filter/struct.EnvFilter.html> for more details.
#[structopt(long = "--log-filter", env = "LOG_FILTER", default_value = "warn")]
pub log_filter: String,
/// Logs: filter short-hand
///
/// Convenient way to set log severity level filter.
/// Overrides `--log-filter`.
///
/// -v 'info'
///
/// -vv 'debug,hyper::proto::h1=info,h2=info'
///
/// -vvv 'trace,hyper::proto::h1=info,h2=info'
#[structopt(
short = "-v",
long = "--verbose",
multiple = true,
takes_value = false,
parse(from_occurrences)
)]
pub log_verbose_count: u8,
/// Logs: destination
///
/// Can be one of: stdout, stderr
//
// TODO(jacobmarble): consider adding file path, file rotation, syslog, ?
#[structopt(
long = "--log-destination",
env = "LOG_DESTINATION",
default_value = "stdout",
verbatim_doc_comment
)]
pub log_destination: LogDestination,
#[rustfmt::skip]
/// Logs: message format
///
/// Can be one of:
///
/// full: human-readable, single line
///
/// Oct 24 12:55:47.815 ERROR shaving_yaks{yaks=3}: fmt::yak_shave: failed to shave yak yak=3 error=missing yak
/// Oct 24 12:55:47.815 TRACE shaving_yaks{yaks=3}: fmt::yak_shave: yaks_shaved=2
/// Oct 24 12:55:47.815 INFO fmt: yak shaving completed all_yaks_shaved=false
///
/// pretty: human-readable, multi line
///
/// Oct 24 12:57:29.387 fmt_pretty::yak_shave: failed to shave yak, yak: 3, error: missing yak
/// at examples/examples/fmt/yak_shave.rs:48 on main
/// in fmt_pretty::yak_shave::shaving_yaks with yaks: 3
///
/// Oct 24 12:57:29.387 fmt_pretty::yak_shave: yaks_shaved: 2
/// at examples/examples/fmt/yak_shave.rs:52 on main
/// in fmt_pretty::yak_shave::shaving_yaks with yaks: 3
///
/// Oct 24 12:57:29.387 fmt_pretty: yak shaving completed, all_yaks_shaved: false
/// at examples/examples/fmt-pretty.rs:19 on main
///
/// json: machine-parseable
///
/// {"timestamp":"Oct 24 13:00:00.875","level":"ERROR","fields":{"message":"failed to shave yak","yak":3,"error":"missing yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
/// {"timestamp":"Oct 24 13:00:00.875","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
/// {"timestamp":"Oct 24 13:00:00.875","level":"INFO","fields":{"message":"yak shaving completed","all_yaks_shaved":false},"target":"fmt_json"}
///
/// logfmt: human-readable and machine-parseable
///
/// level=info msg="This is an info message" target="logging" location="logfmt/tests/logging.rs:36" time=1612181556329599000
/// level=debug msg="This is a debug message" target="logging" location="logfmt/tests/logging.rs:37" time=1612181556329618000
/// level=trace msg="This is a trace message" target="logging" location="logfmt/tests/logging.rs:38" time=1612181556329634000
#[structopt(long = "--log-format", env = "LOG_FORMAT", default_value = "full", verbatim_doc_comment)]
pub log_format: LogFormat,
/// Tracing: exporter type
///
/// Can be one of: none, jaeger, otlp
///
/// When enabled, additional flags are considered (see flags related to OTLP
/// and Jaeger).
#[structopt(
long = "--traces-exporter",
env = "TRACES_EXPORTER",
default_value = "none"
)]
pub traces_exporter: TracesExporter,
/// Tracing: filter directive
///
/// Configures traces severity level filter, by target.
///
/// Simplest options: error, warn, info, debug, trace
///
/// Levels for different modules can be specified. For example
/// `debug,hyper::proto::h1=info` specifies debug tracing for all modules
/// except for the `hyper::proto::h1` module which will only display info
/// level tracing.
///
/// Extended syntax provided by `tracing-subscriber` includes span/field
/// filters. See <https://docs.rs/tracing-subscriber/0.2.17/tracing_subscriber/filter/struct.EnvFilter.html> for more details.
///
/// No filter by default.
#[structopt(long = "--traces-filter", env = "TRACES_FILTER")]
pub traces_filter: Option<String>,
/// Tracing: sampler type
///
/// Can be one of:
/// always_on, always_off, traceidratio,
/// parentbased_always_on, parentbased_always_off, parentbased_traceidratio
///
/// These alternatives are described in detail at <https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/sdk-environment-variables.md#general-sdk-configuration>.
#[structopt(
long = "--traces-sampler",
env = "TRACES_SAMPLER",
default_value = "parentbased_traceidratio"
)]
pub traces_sampler: TracesSampler,
#[rustfmt::skip]
/// Tracing: sampler argument
///
/// Valid range: [0.0, 1.0].
///
/// Only used if `--traces-sampler` is set to
/// parentbased_traceidratio (default) or traceidratio.
///
/// With sample parentbased_traceidratio, the following rules apply:
/// - if parent is sampled, then all of its children are sampled
/// - else sample this portion of traces (0.5 = 50%)
///
/// More details about this sampling argument at <https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/sdk-environment-variables.md#general-sdk-configuration>.
#[structopt(
long = "--traces-sampler-arg",
env = "TRACES_SAMPLER_ARG",
default_value = "1.0",
verbatim_doc_comment
)]
pub traces_sampler_arg: f64,
/// Tracing: OTLP (eg OpenTelemetry collector) network hostname
///
/// Only used if `--traces-exporter` is "otlp".
///
/// Protocol is gRPC. HTTP is not supported.
#[structopt(
long = "--traces-exporter-otlp-host",
env = "TRACES_EXPORTER_OTLP_HOST",
default_value = "localhost"
)]
pub traces_exporter_otlp_host: String,
/// Tracing: OTLP (eg OpenTelemetry collector) network port
///
/// Only used if `--traces-exporter` is "otlp".
///
/// Protocol is gRPC. HTTP is not supported.
#[structopt(
long = "--traces-exporter-otlp-port",
env = "TRACES_EXPORTER_OTLP_PORT",
default_value = "4317"
)]
pub traces_exporter_otlp_port: NonZeroU16,
/// Tracing: Jaeger agent network hostname
///
/// Protocol is Thrift/Compact over UDP.
///
/// Only used if `--traces-exporter` is "jaeger".
#[structopt(
long = "--traces-exporter-jaeger-agent-host",
env = "TRACES_EXPORTER_JAEGER_AGENT_HOST",
default_value = "0.0.0.0"
)]
pub traces_exporter_jaeger_agent_host: String,
/// Tracing: Jaeger agent network port
///
/// Protocol is Thrift/Compact over UDP.
///
/// Only used if `--traces-exporter` is "jaeger".
#[structopt(
long = "--traces-exporter-jaeger-agent-port",
env = "TRACES_EXPORTER_JAEGER_AGENT_PORT",
default_value = "6831"
)]
pub traces_exporter_jaeger_agent_port: NonZeroU16,
/// Tracing: Jaeger service name.
///
/// Only used if `--traces-exporter` is "jaeger".
#[structopt(
long = "--traces-exporter-jaeger-service-name",
env = "TRACES_EXPORTER_JAEGER_SERVICE_NAME",
default_value = "iox-conductor"
)]
pub traces_exporter_jaeger_service_name: String,
/// Tracing: Jaeger max UDP packet size
///
/// Default to 1300, which is a safe MTU.
///
/// You can increase it to 65000 if the target is a jaeger collector
/// on localhost. If so, the batching exporter will be enabled for
/// extra efficiency. Otherwise an UDP packet will be sent for each exported span.
///
/// Only used if `--traces-exporter` is "jaeger".
#[structopt(
long = "--traces-exporter-jaeger-max-packet-size",
env = "TRACES_EXPORTER_JAEGER_MAX_PACKET_SIZE",
default_value = "1300"
)]
pub traces_exporter_jaeger_max_packet_size: usize,
}
impl TracingConfig {
pub fn to_builder(&self) -> Builder<BoxMakeWriter> {
Builder::new()
.with_log_filter(&self.log_filter)
// with_verbose_count goes after with_log_filter because our CLI flag state
// that --v overrides --log-filter.
.with_log_verbose_count(self.log_verbose_count)
.with_log_destination(self.log_destination)
.with_log_format(self.log_format)
.with_traces_filter(&self.traces_filter)
.with_traces_exporter(self.traces_exporter)
.with_traces_sampler(self.traces_sampler, self.traces_sampler_arg)
.with_jaeger_config(JaegerConfig {
agent_host: self.traces_exporter_jaeger_agent_host.clone(),
agent_port: self.traces_exporter_jaeger_agent_port,
service_name: self.traces_exporter_jaeger_service_name.clone(),
max_packet_size: self.traces_exporter_jaeger_max_packet_size,
})
.with_oltp_config(OtlpConfig {
host: self.traces_exporter_otlp_host.clone(),
port: self.traces_exporter_otlp_port,
})
}
pub fn install_global_subscriber(&self) -> Result<TracingGuard> {
self.to_builder().install_global()
}
}
impl From<TracingConfig> for Builder<BoxMakeWriter> {
fn from(config: TracingConfig) -> Self {
config.to_builder()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::simple_test;
fn to_vec(v: &[&str]) -> Vec<String> {
v.iter().map(|s| s.to_string()).collect()
}
#[test]
fn test_log_verbose_count() {
let cfg = TracingConfig::from_iter_safe(to_vec(&["cli"])).unwrap();
assert_eq!(cfg.log_verbose_count, 0);
assert_eq!(
simple_test(cfg.into()).without_timestamps(),
r#"
ERROR foo
WARN woo
"#
.trim_start(),
);
let cfg = TracingConfig::from_iter_safe(to_vec(&["cli", "-v"])).unwrap();
assert_eq!(cfg.log_verbose_count, 1);
assert_eq!(
simple_test(cfg.into()).without_timestamps(),
r#"
ERROR foo
WARN woo
INFO bar
"#
.trim_start(),
);
let cfg = TracingConfig::from_iter_safe(to_vec(&["cli", "-vv"])).unwrap();
assert_eq!(cfg.log_verbose_count, 2);
assert_eq!(
simple_test(cfg.into()).without_timestamps(),
r#"
ERROR foo
WARN woo
INFO bar
DEBUG baz
"#
.trim_start(),
);
let cfg = TracingConfig::from_iter_safe(to_vec(&["cli", "-vvv"])).unwrap();
assert_eq!(cfg.log_verbose_count, 3);
assert_eq!(
simple_test(cfg.into()).without_timestamps(),
r#"
ERROR foo
WARN woo
INFO bar
DEBUG baz
TRACE trax
"#
.trim_start(),
);
}
}

View File

@ -1,3 +1,5 @@
use std::num::NonZeroU16;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LogFormat {
Full,
@ -135,3 +137,15 @@ impl std::fmt::Display for TracesSampler {
}
}
}
pub struct JaegerConfig {
pub agent_host: String,
pub agent_port: NonZeroU16,
pub service_name: String,
pub max_packet_size: usize,
}
pub struct OtlpConfig {
pub host: String,
pub port: NonZeroU16,
}

View File

@ -1,6 +1,9 @@
//! Log and trace initialization and setup
#[cfg(feature = "structopt")]
pub mod cli;
pub mod config;
pub use config::*;
use observability_deps::{
@ -17,7 +20,6 @@ use observability_deps::{
},
};
use std::io;
use std::num::NonZeroU16;
use thiserror::Error;
#[derive(Debug, Error)]
@ -32,7 +34,7 @@ pub enum Error {
SetGlobalDefaultError(#[from] tracing::dispatcher::SetGlobalDefaultError),
}
type Result<T, E = Error> = std::result::Result<T, E>;
pub type Result<T, E = Error> = std::result::Result<T, E>;
/// Builder for tracing and logging.
pub struct Builder<W = fn() -> io::Stdout> {
@ -49,18 +51,6 @@ pub struct Builder<W = fn() -> io::Stdout> {
otlp_config: Option<OtlpConfig>,
}
pub struct JaegerConfig {
pub agent_host: String,
pub agent_port: NonZeroU16,
pub service_name: String,
pub max_packet_size: usize,
}
pub struct OtlpConfig {
pub host: String,
pub port: NonZeroU16,
}
impl Default for Builder {
fn default() -> Self {
Self {
@ -451,19 +441,19 @@ pub mod test_util {
}
}
/// This is a test helper that creates a builder with a few test-friendly parameters
/// such as disabled ANSI escape sequences. The caller provides a function to further customize
/// the builder. This helper then emits a few logs of different verbosity levels and compares the output
/// with the provided `want` string.
pub fn simple_test<F, W>(setup: F, want: impl AsRef<str>)
/// This is a test helper that sets a few test-friendly parameters
/// such as disabled ANSI escape sequences on the provided builder.
/// This helper then emits a few logs of different verbosity levels
/// and returns the captured output.
pub fn simple_test<W>(builder: Builder<W>) -> Captured
where
F: FnOnce(Builder) -> Builder<W>,
W: MakeWriter + Send + Sync + 'static,
{
let (writer, output) = TestWriter::new();
let builder = Builder::new().with_target(false).with_ansi(false);
let subscriber = setup(builder)
let subscriber = builder
.with_writer(writer)
.with_target(false)
.with_ansi(false)
.build()
.expect("subscriber");
@ -475,8 +465,7 @@ pub mod test_util {
trace!("trax");
});
let want = want.as_ref();
assert_eq!(output.without_timestamps(), want);
output
}
}
@ -488,8 +477,8 @@ mod tests {
#[test]
fn simple_logging() {
simple_test(
|builder| builder,
assert_eq!(
simple_test(Builder::new()).without_timestamps(),
r#"
ERROR foo
WARN woo
@ -500,8 +489,8 @@ WARN woo
#[test]
fn simple_logging_logfmt() {
simple_test(
|builder| builder.with_log_format(LogFormat::Logfmt),
assert_eq!(
simple_test(Builder::new().with_log_format(LogFormat::Logfmt)).without_timestamps(),
r#"
level=error msg=foo
level=warn msg=woo
@ -512,8 +501,8 @@ level=warn msg=woo
#[test]
fn verbose_count() {
simple_test(
|builder| builder.with_log_verbose_count(0),
assert_eq!(
simple_test(Builder::new().with_log_verbose_count(0)).without_timestamps(),
r#"
ERROR foo
WARN woo
@ -521,8 +510,8 @@ WARN woo
.trim_start(),
);
simple_test(
|builder| builder.with_log_verbose_count(1),
assert_eq!(
simple_test(Builder::new().with_log_verbose_count(1)).without_timestamps(),
r#"
ERROR foo
WARN woo
@ -531,8 +520,8 @@ INFO bar
.trim_start(),
);
simple_test(
|builder| builder.with_log_verbose_count(2),
assert_eq!(
simple_test(Builder::new().with_log_verbose_count(2)).without_timestamps(),
r#"
ERROR foo
WARN woo
@ -542,8 +531,8 @@ DEBUG baz
.trim_start(),
);
simple_test(
|builder| builder.with_log_verbose_count(3),
assert_eq!(
simple_test(Builder::new().with_log_verbose_count(3)).without_timestamps(),
r#"
ERROR foo
WARN woo