6060 isRunning bool
6161 onServerShutdown []func ()
6262
63- loggerMu sync.RWMutex
64- logger * slog.Logger
63+ globalMu sync.RWMutex
64+ // Set default values because to make Shutdown() idempotent
65+ globalCtx = context .TODO ()
66+ globalLogger = slog .Default ()
6567
6668 metrics Metrics = nullMetrics {}
6769
@@ -231,15 +233,25 @@ func Init(options ...Option) error {
231233 }
232234 }
233235
236+ globalMu .Lock ()
237+
238+ if opt .ctx == nil {
239+ globalCtx = context .Background ()
240+ } else {
241+ globalCtx = opt .ctx
242+ opt .ctx = nil
243+ }
244+
234245 if opt .logger == nil {
235- // set a default logger
236- // to disable logging, set the logger to slog.New(slog.DiscardHandler)
246+ // set a default globalLogger
247+ // to disable logging, set the globalLogger to slog.New(slog.DiscardHandler)
237248 opt .logger = slog .Default ()
249+ } else {
250+ globalLogger = opt .logger
251+ opt .logger = nil
238252 }
239253
240- loggerMu .Lock ()
241- logger = opt .logger
242- loggerMu .Unlock ()
254+ globalMu .Unlock ()
243255
244256 if opt .metrics != nil {
245257 metrics = opt .metrics
@@ -262,11 +274,16 @@ func Init(options ...Option) error {
262274
263275 if config .ZTS {
264276 if ! config .ZendMaxExecutionTimers && runtime .GOOS == "linux" {
265- logger .Warn (`Zend Max Execution Timers are not enabled, timeouts (e.g. "max_execution_time") are disabled, recompile PHP with the "--enable-zend-max-execution-timers" configuration option to fix this issue` )
277+ if globalLogger .Enabled (globalCtx , slog .LevelWarn ) {
278+ globalLogger .LogAttrs (globalCtx , slog .LevelWarn , `Zend Max Execution Timers are not enabled, timeouts (e.g. "max_execution_time") are disabled, recompile PHP with the "--enable-zend-max-execution-timers" configuration option to fix this issue` )
279+ }
266280 }
267281 } else {
268282 opt .numThreads = 1
269- logger .Warn (`ZTS is not enabled, only 1 thread will be available, recompile PHP using the "--enable-zts" configuration option or performance will be degraded` )
283+
284+ if globalLogger .Enabled (globalCtx , slog .LevelWarn ) {
285+ globalLogger .LogAttrs (globalCtx , slog .LevelWarn , `ZTS is not enabled, only 1 thread will be available, recompile PHP using the "--enable-zts" configuration option or performance will be degraded` )
286+ }
270287 }
271288
272289 mainThread , err := initPHPThreads (opt .numThreads , opt .maxThreads , opt .phpIni )
@@ -286,10 +303,12 @@ func Init(options ...Option) error {
286303
287304 initAutoScaling (mainThread )
288305
289- ctx := context .Background ()
290- logger .LogAttrs (ctx , slog .LevelInfo , "FrankenPHP started 🐘" , slog .String ("php_version" , Version ().Version ), slog .Int ("num_threads" , mainThread .numThreads ), slog .Int ("max_threads" , mainThread .maxThreads ))
291- if EmbeddedAppPath != "" {
292- logger .LogAttrs (ctx , slog .LevelInfo , "embedded PHP app 📦" , slog .String ("path" , EmbeddedAppPath ))
306+ if globalLogger .Enabled (globalCtx , slog .LevelInfo ) {
307+ globalLogger .LogAttrs (globalCtx , slog .LevelInfo , "FrankenPHP started 🐘" , slog .String ("php_version" , Version ().Version ), slog .Int ("num_threads" , mainThread .numThreads ), slog .Int ("max_threads" , mainThread .maxThreads ))
308+
309+ if EmbeddedAppPath != "" {
310+ globalLogger .LogAttrs (globalCtx , slog .LevelInfo , "embedded PHP app 📦" , slog .String ("path" , EmbeddedAppPath ))
311+ }
293312 }
294313
295314 // register the startup/shutdown hooks (mainly useful for extensions)
@@ -329,7 +348,15 @@ func Shutdown() {
329348 }
330349
331350 isRunning = false
332- logger .Debug ("FrankenPHP shut down" )
351+ if globalLogger .Enabled (globalCtx , slog .LevelDebug ) {
352+ globalLogger .LogAttrs (globalCtx , slog .LevelDebug , "FrankenPHP shut down" )
353+ }
354+
355+ globalMu .Lock ()
356+ globalCtx = context .TODO ()
357+ globalLogger = slog .Default ()
358+ workers = nil
359+ globalMu .Unlock ()
333360}
334361
335362// ServeHTTP executes a PHP script according to the given context.
@@ -420,8 +447,8 @@ func go_apache_request_headers(threadIndex C.uintptr_t) (*C.go_string, C.size_t)
420447 if fc .responseWriter == nil {
421448 // worker mode, not handling a request
422449
423- if logger .Enabled (ctx , slog .LevelDebug ) {
424- logger .LogAttrs (ctx , slog .LevelDebug , "apache_request_headers() called in non-HTTP context" , slog .String ("worker" , fc .worker .name ))
450+ if globalLogger .Enabled (ctx , slog .LevelDebug ) {
451+ globalLogger .LogAttrs (ctx , slog .LevelDebug , "apache_request_headers() called in non-HTTP context" , slog .String ("worker" , fc .worker .name ))
425452 }
426453
427454 return nil , 0
@@ -450,10 +477,13 @@ func go_apache_request_headers(threadIndex C.uintptr_t) (*C.go_string, C.size_t)
450477 return sd , C .size_t (len (fc .request .Header ))
451478}
452479
453- func addHeader (fc * frankenPHPContext , cString * C.char , length C.int ) {
480+ func addHeader (ctx context. Context , fc * frankenPHPContext , cString * C.char , length C.int ) {
454481 key , val := splitRawHeader (cString , int (length ))
455482 if key == "" {
456- fc .logger .LogAttrs (context .Background (), slog .LevelDebug , "invalid header" , slog .String ("header" , C .GoStringN (cString , length )))
483+ if fc .logger .Enabled (ctx , slog .LevelDebug ) {
484+ fc .logger .LogAttrs (ctx , slog .LevelDebug , "invalid header" , slog .String ("header" , C .GoStringN (cString , length )))
485+ }
486+
457487 return
458488 }
459489 fc .responseWriter .Header ().Add (key , val )
@@ -511,7 +541,7 @@ func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_lli
511541 for current != nil {
512542 h := (* C .sapi_header_struct )(unsafe .Pointer (& (current .data )))
513543
514- addHeader (fc , h .header , C .int (h .header_len ))
544+ addHeader (thread . context (), fc , h .header , C .int (h .header_len ))
515545 current = current .next
516546 }
517547
@@ -522,8 +552,8 @@ func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_lli
522552 if goStatus < 100 || goStatus > 999 {
523553 ctx := thread .context ()
524554
525- if logger .Enabled (ctx , slog .LevelWarn ) {
526- logger .LogAttrs (ctx , slog .LevelWarn , "Invalid response status code" , slog .Int ("status_code" , goStatus ))
555+ if globalLogger .Enabled (ctx , slog .LevelWarn ) {
556+ globalLogger .LogAttrs (ctx , slog .LevelWarn , "Invalid response status code" , slog .Int ("status_code" , goStatus ))
527557 }
528558
529559 goStatus = 500
@@ -561,8 +591,8 @@ func go_sapi_flush(threadIndex C.uintptr_t) bool {
561591 if err := http .NewResponseController (fc .responseWriter ).Flush (); err != nil {
562592 ctx := thread .context ()
563593
564- if logger .Enabled (ctx , slog .LevelWarn ) {
565- logger .LogAttrs (ctx , slog .LevelWarn , "the current responseWriter is not a flusher, if you are not using a custom build, please report this issue" , slog .Any ("error" , err ))
594+ if globalLogger .Enabled (ctx , slog .LevelWarn ) {
595+ globalLogger .LogAttrs (ctx , slog .LevelWarn , "the current responseWriter is not a flusher, if you are not using a custom build, please report this issue" , slog .Any ("error" , err ))
566596 }
567597 }
568598
@@ -608,7 +638,8 @@ func go_read_cookies(threadIndex C.uintptr_t) *C.char {
608638}
609639
610640//export go_log
611- func go_log (message * C.char , level C.int ) {
641+ func go_log (threadIndex C.uintptr_t , message * C.char , level C.int ) {
642+ ctx := phpThreads [threadIndex ].context ()
612643 m := C .GoString (message )
613644
614645 var le syslogLevel
@@ -620,15 +651,23 @@ func go_log(message *C.char, level C.int) {
620651
621652 switch le {
622653 case syslogLevelEmerg , syslogLevelAlert , syslogLevelCrit , syslogLevelErr :
623- logger .LogAttrs (context .Background (), slog .LevelError , m , slog .String ("syslog_level" , syslogLevel (level ).String ()))
654+ if globalLogger .Enabled (ctx , slog .LevelError ) {
655+ globalLogger .LogAttrs (ctx , slog .LevelError , m , slog .String ("syslog_level" , syslogLevel (level ).String ()))
656+ }
624657
625658 case syslogLevelWarn :
626- logger .LogAttrs (context .Background (), slog .LevelWarn , m , slog .String ("syslog_level" , syslogLevel (level ).String ()))
659+ if globalLogger .Enabled (ctx , slog .LevelWarn ) {
660+ globalLogger .LogAttrs (ctx , slog .LevelWarn , m , slog .String ("syslog_level" , syslogLevel (level ).String ()))
661+ }
627662 case syslogLevelDebug :
628- logger .LogAttrs (context .Background (), slog .LevelDebug , m , slog .String ("syslog_level" , syslogLevel (level ).String ()))
663+ if globalLogger .Enabled (ctx , slog .LevelDebug ) {
664+ globalLogger .LogAttrs (ctx , slog .LevelDebug , m , slog .String ("syslog_level" , syslogLevel (level ).String ()))
665+ }
629666
630667 default :
631- logger .LogAttrs (context .Background (), slog .LevelInfo , m , slog .String ("syslog_level" , syslogLevel (level ).String ()))
668+ if globalLogger .Enabled (ctx , slog .LevelInfo ) {
669+ globalLogger .LogAttrs (ctx , slog .LevelInfo , m , slog .String ("syslog_level" , syslogLevel (level ).String ()))
670+ }
632671 }
633672}
634673
0 commit comments