-
Notifications
You must be signed in to change notification settings - Fork 0
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
14 implement logger initialization logic #15
Merged
Merged
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
cb952ac
add backend
archeoss f201390
post review fixes pt.1
archeoss 8ad4e43
post review fixes pt.2
archeoss b858a01
remove wrappers
archeoss 2932ae8
post review fixes (WIP)
archeoss 47a7769
change build flow + error handling
archeoss f6d9b15
log4rs add (WIP)
archeoss 654d24a
add loggers
archeoss c3d512e
clean up
archeoss ec05d75
remove dep
archeoss d2f95eb
remove stderr target
archeoss 4e09e19
delete stderr target + unify trace-level
archeoss 11a1fcd
delete redundant lock file
archeoss c621433
clean up
archeoss 64263a2
logger init rework
archeoss 0b2506c
post review fixes + error_stack errors
archeoss 41801c8
adjust fixes
archeoss 9042706
Merge branch 'main' into 14-implement-logger-initialization-logic
ikopylov 8325256
replace write check with is_empty check
archeoss 434d2fa
Update backend/src/config.rs
ikopylov 6dc1787
Update backend/src/config.rs
ikopylov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,160 @@ | ||
use cli::Config; | ||
use crate::prelude::*; | ||
use cli::{Config, LoggerConfig}; | ||
use file_rotate::{suffix::AppendTimestamp, ContentLimit, FileRotate}; | ||
use thiserror::Error; | ||
use tower_http::cors::CorsLayer; | ||
use tracing_appender::non_blocking::{NonBlocking, WorkerGuard}; | ||
use tracing_subscriber::{filter::LevelFilter, prelude::*, util::SubscriberInitExt}; | ||
|
||
#[allow(clippy::module_name_repetitions)] | ||
pub trait ConfigExt { | ||
/// Return either very permissive [`CORS`](`CorsLayer`) configuration | ||
/// or empty one based on `cors_allow_all` field | ||
fn get_cors_configuration(&self) -> CorsLayer; | ||
} | ||
|
||
pub trait LoggerExt { | ||
/// Initialize logger. | ||
/// | ||
/// Returns [`WorkerGuard`]s for off-thread writers. | ||
/// Should not be dropped. | ||
/// | ||
/// # Errors | ||
/// | ||
/// Function returns error if `init_file_rotate` fails | ||
fn init_logger(&self) -> Result<Vec<WorkerGuard>, LoggerError>; | ||
|
||
/// Returns [`std:io::Write`] object that rotates files on write | ||
/// | ||
/// # Errors | ||
/// | ||
/// Function returns error if `log_file` is not specified | ||
fn init_file_rotate(&self) -> Result<FileRotate<AppendTimestamp>, LoggerError>; | ||
|
||
/// Returns non-blocking file writer | ||
/// | ||
/// Also returns [`WorkerGuard`] for off-thread writing. | ||
/// Should not be dropped. | ||
/// | ||
/// # Errors | ||
/// | ||
/// This function will return an error if the file logger configuration is empty, file logging | ||
/// is disabled or logs filename is not specified | ||
fn non_blocking_file_writer(&self) -> Result<(NonBlocking, WorkerGuard), LoggerError>; | ||
|
||
/// Returns non-blocking stdout writer | ||
/// | ||
/// Also returns [`WorkerGuard`] for off-thread writing. | ||
/// Should not be dropped. | ||
/// | ||
/// # Errors | ||
/// | ||
/// This function will return an error if the stdout logger configuration is empty or stdout logging | ||
/// is disabled | ||
fn non_blocking_stdout_writer(&self) -> Result<(NonBlocking, WorkerGuard), LoggerError>; | ||
} | ||
|
||
impl ConfigExt for Config { | ||
fn get_cors_configuration(&self) -> CorsLayer { | ||
self.cors_allow_all | ||
.then_some(CorsLayer::very_permissive()) | ||
.unwrap_or_default() | ||
} | ||
} | ||
|
||
impl LoggerExt for LoggerConfig { | ||
fn init_logger(&self) -> Result<Vec<WorkerGuard>, LoggerError> { | ||
let mut guards = Vec::with_capacity(2); | ||
|
||
let file_writer = disable_on_error(self.non_blocking_file_writer())?; | ||
let stdout_writer = disable_on_error(self.non_blocking_stdout_writer())?; | ||
|
||
let mut layers_iter = | ||
[file_writer, stdout_writer] | ||
.into_iter() | ||
.flatten() | ||
.map(|(writer, guard)| { | ||
guards.push(guard); | ||
tracing_subscriber::fmt::layer() | ||
.with_writer(writer) | ||
.with_filter(LevelFilter::from_level(self.trace_level)) | ||
}); | ||
|
||
if let Some(first_layer) = layers_iter.next() { | ||
tracing_subscriber::registry() | ||
.with(layers_iter.fold(first_layer.boxed(), |layer, next_layer| { | ||
layer.and_then(next_layer).boxed() | ||
})) | ||
.init(); | ||
}; | ||
|
||
Ok(guards) | ||
} | ||
|
||
fn init_file_rotate(&self) -> Result<FileRotate<AppendTimestamp>, LoggerError> { | ||
let config = self.file.as_ref().ok_or(LoggerError::EmptyConfig)?; | ||
let log_file = config.log_file.as_ref().ok_or(LoggerError::NoFileName)?; | ||
log_file | ||
.as_os_str() | ||
.is_empty() | ||
.then(|| LoggerError::NoFileName) | ||
.map_or(Ok(()), Err)?; | ||
|
||
ikopylov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Ok(FileRotate::new( | ||
log_file, | ||
AppendTimestamp::default(file_rotate::suffix::FileLimit::MaxFiles(config.log_amount)), | ||
ContentLimit::BytesSurpassed(config.log_size), | ||
file_rotate::compression::Compression::OnRotate(1), | ||
None, | ||
)) | ||
} | ||
|
||
fn non_blocking_file_writer(&self) -> Result<(NonBlocking, WorkerGuard), LoggerError> { | ||
self.file.as_ref().map_or_else( | ||
|| Err(LoggerError::EmptyConfig.into()), | ||
|config| { | ||
if config.enabled { | ||
Ok(tracing_appender::non_blocking(self.init_file_rotate()?)) | ||
} else { | ||
Err(LoggerError::NotEnabled.into()) | ||
} | ||
}, | ||
) | ||
} | ||
|
||
fn non_blocking_stdout_writer(&self) -> Result<(NonBlocking, WorkerGuard), LoggerError> { | ||
self.stdout.as_ref().map_or_else( | ||
|| Err(LoggerError::EmptyConfig.into()), | ||
|config| { | ||
if config.enabled { | ||
Ok(tracing_appender::non_blocking(std::io::stdout())) | ||
} else { | ||
Err(LoggerError::NotEnabled.into()) | ||
} | ||
}, | ||
) | ||
} | ||
} | ||
|
||
#[derive(Debug, Error)] | ||
pub enum LoggerError { | ||
#[error("Empty logger configuration")] | ||
EmptyConfig, | ||
#[error("No filename specified")] | ||
NoFileName, | ||
#[error("This logger is not enabled")] | ||
NotEnabled, | ||
} | ||
|
||
/// Consume some errors to produce empty logger | ||
fn disable_on_error( | ||
logger: Result<(NonBlocking, WorkerGuard), LoggerError>, | ||
) -> Result<Option<(NonBlocking, WorkerGuard)>, LoggerError> { | ||
Ok(match logger { | ||
Ok(writer) => Some(writer), | ||
Err(e) => match e.current_context() { | ||
LoggerError::NotEnabled | LoggerError::EmptyConfig => None, | ||
_ => return Err(e), | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary complication of code readability. The code would be much clearer in this form: