@@ -26,6 +26,10 @@ pub const DISABLE_OTEL_METRICS: &str = "DISABLE_OTEL_METRICS";
26
26
/// Set to "1" to disable the recorder output.
27
27
pub const DISABLE_RECORDER_TRACING : & str = "DISABLE_RECORDER_TRACING" ;
28
28
29
+ /// Environment variable to additionally enable stderr logging in Local environment.
30
+ /// Set to "1" to also dump logs to stderr when running in Local environment.
31
+ pub const MONARCH_DEBUG : & str = "MONARCH_DEBUG" ;
32
+
29
33
#[ cfg( fbcode_build) ]
30
34
mod meta;
31
35
mod otel;
@@ -57,6 +61,11 @@ use tracing_subscriber::Layer;
57
61
use tracing_subscriber:: filter:: LevelFilter ;
58
62
use tracing_subscriber:: filter:: Targets ;
59
63
use tracing_subscriber:: fmt;
64
+ use tracing_subscriber:: fmt:: FormatEvent ;
65
+ use tracing_subscriber:: fmt:: FormatFields ;
66
+ use tracing_subscriber:: fmt:: format:: Format ;
67
+ use tracing_subscriber:: fmt:: format:: Writer ;
68
+ use tracing_subscriber:: registry:: LookupSpan ;
60
69
61
70
use crate :: recorder:: Recorder ;
62
71
@@ -77,27 +86,30 @@ impl TelemetryClock for DefaultTelemetryClock {
77
86
}
78
87
}
79
88
80
- // Need to keep this around so that the tracing subscriber doesn't drop the writer.
89
+ fn file_appender ( dir : & str , filename : & str ) -> Box < dyn Write + Send > {
90
+ match RollingFileAppender :: builder ( )
91
+ . rotation ( Rotation :: DAILY )
92
+ . filename_prefix ( filename)
93
+ . filename_suffix ( "log" )
94
+ . build ( dir)
95
+ {
96
+ Ok ( file) => Box :: new ( file) ,
97
+ Err ( e) => {
98
+ tracing:: warn!( "unable to create custom log file: {}" , e) ;
99
+ Box :: new ( std:: io:: stderr ( ) )
100
+ }
101
+ }
102
+ }
103
+
104
+ fn writer ( ) -> Box < dyn Write + Send > {
105
+ match env:: Env :: current ( ) {
106
+ env:: Env :: Test | env:: Env :: MastEmulator => Box :: new ( std:: io:: stderr ( ) ) ,
107
+ env:: Env :: Local => file_appender ( "/tmp/" , "monarch_log" ) ,
108
+ env:: Env :: Mast => file_appender ( "/logs/" , "dedicated_log_monarch" ) ,
109
+ }
110
+ }
111
+
81
112
lazy_static ! {
82
- static ref FILE_WRITER_GUARD : Arc <( NonBlocking , WorkerGuard ) > = {
83
- let writer: Box <dyn Write + Send > = match RollingFileAppender :: builder( )
84
- . rotation( Rotation :: DAILY )
85
- . filename_prefix( "dedicated_log_monarch" )
86
- . filename_suffix( "log" )
87
- . build( "/logs/" )
88
- {
89
- Ok ( file) => Box :: new( file) ,
90
- Err ( e) => {
91
- tracing:: warn!( "unable to create custom log file: {}" , e) ;
92
- Box :: new( std:: io:: stderr( ) )
93
- }
94
- } ;
95
- return Arc :: new(
96
- tracing_appender:: non_blocking:: NonBlockingBuilder :: default ( )
97
- . lossy( false )
98
- . finish( writer) ,
99
- ) ;
100
- } ;
101
113
static ref TELEMETRY_CLOCK : Arc <Mutex <Box <dyn TelemetryClock + Send >>> =
102
114
{ Arc :: new( Mutex :: new( Box :: new( DefaultTelemetryClock { } ) ) ) } ;
103
115
}
@@ -406,6 +418,60 @@ macro_rules! declare_static_histogram {
406
418
} ;
407
419
}
408
420
421
+ static FILE_WRITER_GUARD : std:: sync:: OnceLock < Arc < ( NonBlocking , WorkerGuard ) > > =
422
+ std:: sync:: OnceLock :: new ( ) ;
423
+
424
+ /// A custom formatter that prepends prefix from env_var to log messages.
425
+ /// Uses either Glog formatter or default formatter based on environment.
426
+ struct PrefixedFormatter {
427
+ formatter : FormatterType ,
428
+ prefix_env_var : Option < String > ,
429
+ }
430
+
431
+ enum FormatterType {
432
+ Glog ( Glog < LocalTime > ) ,
433
+ Default ( Format < tracing_subscriber:: fmt:: format:: Full , ( ) > ) ,
434
+ }
435
+
436
+ impl PrefixedFormatter {
437
+ fn new ( formatter : FormatterType , prefix_env_var : Option < String > ) -> Self {
438
+ Self {
439
+ formatter,
440
+ prefix_env_var,
441
+ }
442
+ }
443
+ }
444
+
445
+ impl < S , N > FormatEvent < S , N > for PrefixedFormatter
446
+ where
447
+ S : tracing:: Subscriber + for < ' a > LookupSpan < ' a > ,
448
+ N : for < ' a > FormatFields < ' a > + ' static ,
449
+ {
450
+ fn format_event (
451
+ & self ,
452
+ ctx : & tracing_subscriber:: fmt:: FmtContext < ' _ , S , N > ,
453
+ mut writer : Writer < ' _ > ,
454
+ event : & tracing:: Event < ' _ > ,
455
+ ) -> std:: fmt:: Result {
456
+ let prefix: String = if self . prefix_env_var . is_some ( ) {
457
+ std:: env:: var ( self . prefix_env_var . clone ( ) . unwrap ( ) ) . unwrap_or_default ( )
458
+ } else {
459
+ "" . to_string ( )
460
+ } ;
461
+
462
+ if prefix. is_empty ( ) {
463
+ write ! ( writer, "[-]" ) ?;
464
+ } else {
465
+ write ! ( writer, "[{}]" , prefix) ?;
466
+ }
467
+
468
+ match & self . formatter {
469
+ FormatterType :: Glog ( inner) => inner. format_event ( ctx, writer, event) ,
470
+ FormatterType :: Default ( inner) => inner. format_event ( ctx, writer, event) ,
471
+ }
472
+ }
473
+ }
474
+
409
475
/// Set up logging based on the given execution environment. We specialize logging based on how the
410
476
/// logs are consumed. The destination scuba table is specialized based on the execution environment.
411
477
/// mast -> monarch_tracing/prod
@@ -414,18 +480,33 @@ macro_rules! declare_static_histogram {
414
480
/// scuba logging won't normally be enabled for a unit test unless we are specifically testing logging, so
415
481
/// you don't need to worry about your tests being flakey due to scuba logging. You have to manually call initialize_logging()
416
482
/// to get this behavior.
417
- pub fn initialize_logging ( clock : impl TelemetryClock + Send + ' static ) {
483
+ pub fn initialize_logging (
484
+ clock : impl TelemetryClock + Send + ' static ,
485
+ prefix_env_var : Option < String > ,
486
+ ) {
418
487
swap_telemetry_clock ( clock) ;
419
488
let file_log_level = match env:: Env :: current ( ) {
420
489
env:: Env :: Local => "info" ,
421
490
env:: Env :: MastEmulator => "info" ,
422
491
env:: Env :: Mast => "info" ,
423
492
env:: Env :: Test => "debug" ,
424
493
} ;
425
- let file_writer: & NonBlocking = & FILE_WRITER_GUARD . 0 ;
494
+ let ( non_blocking, guard) = tracing_appender:: non_blocking:: NonBlockingBuilder :: default ( )
495
+ . lossy ( false )
496
+ . finish ( writer ( ) ) ;
497
+ let writer_guard = Arc :: new ( ( non_blocking, guard) ) ;
498
+ let _ = FILE_WRITER_GUARD . set ( writer_guard. clone ( ) ) ;
499
+
500
+ let file_formatter = match env:: Env :: current ( ) {
501
+ env:: Env :: Mast => FormatterType :: Glog ( Glog :: default ( ) . with_timer ( LocalTime :: default ( ) ) ) ,
502
+ _ => FormatterType :: Default ( Format :: default ( ) . without_time ( ) . with_target ( false ) ) ,
503
+ } ;
426
504
let file_layer = fmt:: Layer :: default ( )
427
- . with_writer ( file_writer. clone ( ) )
428
- . event_format ( Glog :: default ( ) . with_timer ( LocalTime :: default ( ) ) )
505
+ . with_writer ( writer_guard. 0 . clone ( ) )
506
+ . event_format ( PrefixedFormatter :: new (
507
+ file_formatter,
508
+ prefix_env_var. clone ( ) ,
509
+ ) )
429
510
. fmt_fields ( GlogFields :: default ( ) . compact ( ) )
430
511
. with_ansi ( false )
431
512
. with_filter (
@@ -447,7 +528,10 @@ pub fn initialize_logging(clock: impl TelemetryClock + Send + 'static) {
447
528
} ;
448
529
let stderr_layer = fmt:: Layer :: default ( )
449
530
. with_writer ( std:: io:: stderr)
450
- . event_format ( Glog :: default ( ) . with_timer ( LocalTime :: default ( ) ) )
531
+ . event_format ( PrefixedFormatter :: new (
532
+ FormatterType :: Default ( Format :: default ( ) . without_time ( ) . with_target ( false ) ) ,
533
+ prefix_env_var,
534
+ ) )
451
535
. fmt_fields ( GlogFields :: default ( ) . compact ( ) )
452
536
. with_ansi ( std:: io:: stderr ( ) . is_terminal ( ) )
453
537
. with_filter (
@@ -478,13 +562,17 @@ pub fn initialize_logging(clock: impl TelemetryClock + Send + 'static) {
478
562
} else {
479
563
None
480
564
} )
565
+ . with ( if is_layer_enabled ( MONARCH_DEBUG ) {
566
+ Some ( stderr_layer)
567
+ } else {
568
+ None
569
+ } )
481
570
. with ( if is_layer_enabled ( DISABLE_RECORDER_TRACING ) {
482
571
Some ( recorder ( ) . layer ( ) )
483
572
} else {
484
573
None
485
574
} )
486
575
. with ( file_layer)
487
- . with ( stderr_layer)
488
576
. try_init ( )
489
577
{
490
578
tracing:: debug!( "logging already initialized for this process: {}" , err) ;
0 commit comments