Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow configuring the tracing log output format #275

Merged
merged 1 commit into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dotenvy = "0.15.5"

# Tracing
tracing = { workspace = true }
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
tracing-subscriber = { version = "0.3.17", features = ["env-filter", "json"] }
opentelemetry-semantic-conventions = "0.15.0"
opentelemetry = { version = "0.23.0", features = ["trace", "metrics", "logs"], optional = true }
opentelemetry_sdk = { version = "0.23.0", features = ["tokio", "rt-tokio", "metrics", "logs", "trace"], optional = true }
Expand Down
3 changes: 3 additions & 0 deletions config/development.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[tracing]
format = "pretty"

[auth.jwt]
secret = "secret-dev"

Expand Down
3 changes: 3 additions & 0 deletions config/test.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[tracing]
format = "pretty"

[auth.jwt]
secret = "secret-test"

Expand Down
3 changes: 3 additions & 0 deletions examples/full/config/development.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[tracing]
format = "pretty"

[auth.jwt]
secret = "secret-dev"

Expand Down
3 changes: 3 additions & 0 deletions examples/full/config/test.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[tracing]
format = "pretty"

[auth.jwt]
secret = "secret-test"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ required-claims = []

[tracing]
level = 'debug'
format = 'compact'
trace-propagation = true

[database]
Expand Down
1 change: 1 addition & 0 deletions src/config/tracing/default.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[tracing]
format = "compact"
trace-propagation = true
21 changes: 20 additions & 1 deletion src/config/tracing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use crate::util::serde_util::default_true;
use config::{FileFormat, FileSourceString};
use serde_derive::{Deserialize, Serialize};
use strum_macros::{EnumString, IntoStaticStr};
#[cfg(feature = "otel")]
use url::Url;
use validator::Validate;
Expand All @@ -16,6 +17,9 @@ pub fn default_config() -> config::File<FileSourceString, FileFormat> {
pub struct Tracing {
pub level: String,

/// The format to use when printing traces to logs.
pub format: Format,

/// The name of the service to use for the OpenTelemetry `service.name` field. If not provided,
/// will use the [`App::name`][crate::config::app_config::App] config value, translated to `snake_case`.
#[cfg(feature = "otel")]
Expand All @@ -31,6 +35,17 @@ pub struct Tracing {
pub otlp_endpoint: Option<Url>,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, EnumString, IntoStaticStr)]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
#[non_exhaustive]
pub enum Format {
None,
Pretty,
Compact,
Json,
}

// To simplify testing, these are only run when all of the config fields are available
#[cfg(all(test, feature = "otel"))]
mod deserialize_tests {
Expand All @@ -49,28 +64,32 @@ mod deserialize_tests {
#[case(
r#"
level = "debug"
format = "compact"
"#
)]
#[case(
r#"
level = "info"
format = "json"
service-name = "foo"
"#
)]
#[case(
r#"
level = "error"
format = "pretty"
trace-propagation = false
"#
)]
#[case(
r#"
level = "debug"
format = "none"
otlp-endpoint = "https://example.com:1234"
"#
)]
#[cfg_attr(coverage_nightly, coverage(off))]
fn sidekiq(_case: TestCase, #[case] config: &str) {
fn tracing(_case: TestCase, #[case] config: &str) {
let tracing: Tracing = toml::from_str(config).unwrap();

assert_toml_snapshot!(tracing);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
source: src/config/tracing.rs
source: src/config/tracing/mod.rs
expression: tracing
---
level = 'debug'
format = 'compact'
trace-propagation = true
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
---
source: src/config/tracing.rs
source: src/config/tracing/mod.rs
expression: tracing
---
level = 'info'
format = 'json'
service-name = 'foo'
trace-propagation = true
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
source: src/config/tracing.rs
source: src/config/tracing/mod.rs
expression: tracing
---
level = 'error'
format = 'pretty'
trace-propagation = false
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
---
source: src/config/tracing.rs
source: src/config/tracing/mod.rs
expression: tracing
---
level = 'debug'
format = 'none'
trace-propagation = true
otlp-endpoint = 'https://example.com:1234/'
42 changes: 40 additions & 2 deletions src/tracing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;

use crate::config::app_config::AppConfig;
use crate::config::tracing::Format;
use crate::error::RoadsterResult;

// Todo: make this configurable
Expand All @@ -30,7 +31,42 @@ pub fn init_tracing(
metadata: &AppMetadata,
) -> RoadsterResult<()> {
// Stdout Layer
let stdout_layer = tracing_subscriber::fmt::layer();
// Each format results in a different type, so we can't use a `match` on the format enum.
// Instead, we need to create an optional layer of each type, and add all of them to the
// registry -- if a layer is `None`, it won't actually be added.
let compact_log_layer = if matches!(config.tracing.format, Format::Compact) {
Some(tracing_subscriber::fmt::layer().compact())
} else {
None
};
let pretty_log_layer = if matches!(config.tracing.format, Format::Pretty) {
Some(tracing_subscriber::fmt::layer().pretty())
} else {
None
};
let json_log_layer = if matches!(config.tracing.format, Format::Json) {
Some(tracing_subscriber::fmt::layer().json())
} else {
None
};
match config.tracing.format {
Format::None => {
assert!(
pretty_log_layer.is_none()
&& compact_log_layer.is_none()
&& json_log_layer.is_none()
)
}
Format::Pretty => {
assert!(pretty_log_layer.is_some())
}
Format::Compact => {
assert!(compact_log_layer.is_some())
}
Format::Json => {
assert!(json_log_layer.is_some())
}
}

#[cfg(feature = "otel")]
if config.tracing.trace_propagation {
Expand Down Expand Up @@ -104,7 +140,9 @@ pub fn init_tracing(

let registry = tracing_subscriber::Registry::default()
.with(env_filter)
.with(stdout_layer);
.with(compact_log_layer)
.with(pretty_log_layer)
.with(json_log_layer);

#[cfg(feature = "otel")]
let registry = { registry.with(oltp_traces_layer).with(otlp_metrics_layer) };
Expand Down