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#343pull/24376/head
parent
38d17a3093
commit
760bcde3f0
|
@ -4579,6 +4579,7 @@ dependencies = [
|
|||
"opentelemetry-jaeger",
|
||||
"opentelemetry-otlp",
|
||||
"regex",
|
||||
"structopt",
|
||||
"synchronized-writer",
|
||||
"thiserror",
|
||||
"tracing-opentelemetry",
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue