@@ -142,6 +142,31 @@ impl Config {
142142 nlog. format = nformat;
143143 }
144144
145+ if let Some ( file_config) = log. file
146+ // directory must be configured for file logging
147+ && let Some ( directory) = file_config. directory
148+ {
149+ let mut nfile = LogFileConfig :: new ( directory) ;
150+ if let Some ( rotation) = file_config. rotation {
151+ nfile. rotation = match rotation. as_str ( ) {
152+ "never" => tracing_appender:: rolling:: Rotation :: NEVER ,
153+ "hourly" => tracing_appender:: rolling:: Rotation :: HOURLY ,
154+ "daily" => tracing_appender:: rolling:: Rotation :: DAILY ,
155+ _ => return Err ( ConfigError :: InvalidValue ( rotation) ) ,
156+ } ;
157+ }
158+ if let Some ( prefix) = file_config. prefix {
159+ nfile. prefix = Some ( prefix) ;
160+ }
161+ if let Some ( suffix) = file_config. suffix {
162+ nfile. suffix = Some ( suffix) ;
163+ }
164+ if let Some ( max_files) = file_config. max_files {
165+ nfile. max_files = Some ( max_files) ;
166+ }
167+ nlog. file = Some ( nfile) ;
168+ }
169+
145170 if let Some ( config_path) = log. config_path {
146171 nlog. config_path = Some ( PathBuf :: from ( config_path) ) ;
147172 }
@@ -210,6 +235,8 @@ pub struct LogConfig {
210235 pub level : u32 ,
211236 /// Default logger format configuration
212237 pub format : LogFormatConfig ,
238+ /// File appender configuration
239+ pub file : Option < LogFileConfig > ,
213240 /// Logging configuration file path
214241 pub config_path : Option < PathBuf > ,
215242}
@@ -221,6 +248,35 @@ pub struct LogFormatConfig {
221248 pub without_time : bool ,
222249}
223250
251+ /// File appender configuration for logging
252+ #[ cfg( feature = "logging" ) ]
253+ #[ derive( Debug , Clone ) ]
254+ pub struct LogFileConfig {
255+ /// Directory to store log files
256+ pub directory : PathBuf ,
257+ /// Rotation strategy for log files. Default is `Rotation::NEVER`.
258+ pub rotation : tracing_appender:: rolling:: Rotation ,
259+ /// Prefix for log file names. Default is the binary name.
260+ pub prefix : Option < String > ,
261+ /// Suffix for log file names. Default is "log".
262+ pub suffix : Option < String > ,
263+ /// Maximum number of log files to keep. Default is `None`, meaning no limit.
264+ pub max_files : Option < usize > ,
265+ }
266+
267+ #[ cfg( feature = "logging" ) ]
268+ impl LogFileConfig {
269+ fn new ( directory : impl Into < PathBuf > ) -> Self {
270+ Self {
271+ directory : directory. into ( ) ,
272+ rotation : tracing_appender:: rolling:: Rotation :: NEVER ,
273+ prefix : None ,
274+ suffix : None ,
275+ max_files : None ,
276+ }
277+ }
278+ }
279+
224280/// Runtime mode (Tokio)
225281#[ derive( Debug , Clone , Copy , Default ) ]
226282pub enum RuntimeMode {
@@ -272,6 +328,7 @@ struct SSConfig {
272328struct SSLogConfig {
273329 level : Option < u32 > ,
274330 format : Option < SSLogFormat > ,
331+ file : Option < SSLogFileConfig > ,
275332 config_path : Option < String > ,
276333}
277334
@@ -281,6 +338,16 @@ struct SSLogFormat {
281338 without_time : Option < bool > ,
282339}
283340
341+ #[ cfg( feature = "logging" ) ]
342+ #[ derive( Deserialize ) ]
343+ struct SSLogFileConfig {
344+ directory : Option < String > ,
345+ rotation : Option < String > ,
346+ prefix : Option < String > ,
347+ suffix : Option < String > ,
348+ max_files : Option < usize > ,
349+ }
350+
284351#[ derive( Deserialize ) ]
285352struct SSRuntimeConfig {
286353 #[ cfg( feature = "multi-threaded" ) ]
0 commit comments