Skip to content

Commit

Permalink
feat: Enable ReqResLogging middleware by default, but disable in prod (
Browse files Browse the repository at this point in the history
…#307)

Update the default app config to allow different defaults per
environment, so ReqResLogging middleware can be enabled by default, but
disabled in prod.
  • Loading branch information
spencewenski authored Aug 1, 2024
1 parent 134e640 commit f4a5860
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 12 deletions.
18 changes: 13 additions & 5 deletions src/config/app_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ impl AppConfig {
} else {
Environment::new()?
};
let environment_str: &str = environment.into();
let environment_str: &str = environment.clone().into();

let config = Self::default_config()
let config = Self::default_config(environment)
// Todo: allow other file formats?
// Todo: allow splitting config into multiple files?
.add_source(config::File::with_name("config/default.toml"))
Expand All @@ -99,7 +99,7 @@ impl AppConfig {
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
pub(crate) fn test(config_str: Option<&str>) -> RoadsterResult<Self> {
let config = Self::default_config()
let config = Self::default_config(Environment::Test)
.add_source(config::File::from_str(
config_str.unwrap_or(
r#"
Expand Down Expand Up @@ -146,7 +146,9 @@ impl AppConfig {
}

#[allow(clippy::let_and_return)]
fn default_config() -> ConfigBuilder<DefaultState> {
fn default_config(
#[allow(unused_variables)] environment: Environment,
) -> ConfigBuilder<DefaultState> {
let config = Config::builder()
.add_source(config::File::from_str(
include_str!("default.toml"),
Expand All @@ -155,7 +157,13 @@ impl AppConfig {
.add_source(crate::config::tracing::default_config());

#[cfg(feature = "http")]
let config = config.add_source(crate::config::service::http::default_config());
let config = {
let config = config.add_source(crate::config::service::http::default_config());
let config = crate::config::service::http::default_config_per_env(environment)
.into_iter()
.fold(config, |config, source| config.add_source(source));
config
};

#[cfg(feature = "grpc")]
let config = config.add_source(crate::config::service::grpc::default_config());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ limit = "5 MB"
priority = -9950

[service.http.middleware.request-response-logging]
enable = false
priority = 0

# Initializers
Expand Down
2 changes: 2 additions & 0 deletions src/config/service/http/config/production.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[service.http.middleware.request-response-logging]
enable = false
13 changes: 12 additions & 1 deletion src/config/service/http/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::config::environment::Environment;
use crate::config::service::common::address::Address;
use crate::config::service::http::initializer::Initializer;
use crate::config::service::http::middleware::Middleware;
Expand All @@ -11,7 +12,17 @@ pub mod initializer;
pub mod middleware;

pub fn default_config() -> config::File<FileSourceString, FileFormat> {
config::File::from_str(include_str!("default.toml"), FileFormat::Toml)
config::File::from_str(include_str!("config/default.toml"), FileFormat::Toml)
}

pub(crate) fn default_config_per_env(
environment: Environment,
) -> Option<config::File<FileSourceString, FileFormat>> {
let config = match environment {
Environment::Production => Some(include_str!("config/production.toml")),
_ => None,
};
config.map(|c| config::File::from_str(c, FileFormat::Toml))
}

#[derive(Debug, Clone, Validate, Serialize, Deserialize)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ preset = 'restrictive'
max-age = 3600000

[service.http.middleware.request-response-logging]
enable = false
priority = 0

[service.http.initializer]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ expression: middleware
'propagate-request-id',
'request-body-size-limit',
'request-decompression',
'request-response-logging',
'sensitive-request-headers',
'sensitive-response-headers',
'set-request-id',
Expand Down
21 changes: 17 additions & 4 deletions src/service/http/middleware/tracing/req_res_logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,30 +64,43 @@ where
async fn log_req_res_bodies(request: Request, next: Next) -> Result<impl IntoResponse, Response> {
// Log the request body
let (parts, body) = request.into_parts();
let bytes = log_body(body, "request").await?;
let bytes = log_body(body, true).await?;
let request = Request::from_parts(parts, Body::from(bytes));

// Handle the request
let response = next.run(request).await;

// Log the response body
let (parts, body) = response.into_parts();
let bytes = log_body(body, "response").await?;
let bytes = log_body(body, false).await?;
let response = Response::from_parts(parts, Body::from(bytes));

// Return the response
Ok(response)
}

async fn log_body(body: Body, msg: &str) -> Result<Bytes, Response> {
const MAX: usize = 1000;

async fn log_body(body: Body, req: bool) -> Result<Bytes, Response> {
// This only works if the body is not a long-running stream
let bytes = body
.collect()
.await
.map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response())?
.to_bytes();

debug!(body = ?bytes, msg);
let body = if bytes.len() > MAX {
let slice = bytes.slice(0..MAX);
format!("{slice:?}...[truncated]")
} else {
format!("{bytes:?}")
};

if req {
debug!(body, "request");
} else {
debug!(body, "response");
}

Ok(bytes)
}
Expand Down

0 comments on commit f4a5860

Please sign in to comment.