// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

// Package logging provides the logging library used by Pion
package logging import ( ) // Use this abstraction to ensure thread-safe access to the logger's io.Writer. // (which could change at runtime). type loggerWriter struct { sync.RWMutex output io.Writer } func ( *loggerWriter) ( io.Writer) { .Lock() defer .Unlock() .output = } func ( *loggerWriter) ( []byte) (int, error) { .RLock() defer .RUnlock() return .output.Write() } // DefaultLeveledLogger encapsulates functionality for providing logging at. // user-defined levels. type DefaultLeveledLogger struct { level LogLevel writer *loggerWriter trace *log.Logger debug *log.Logger info *log.Logger warn *log.Logger err *log.Logger } // WithTraceLogger is a chainable configuration function which sets the // Trace-level logger. func ( *DefaultLeveledLogger) ( *log.Logger) *DefaultLeveledLogger { .trace = return } // WithDebugLogger is a chainable configuration function which sets the // Debug-level logger. func ( *DefaultLeveledLogger) ( *log.Logger) *DefaultLeveledLogger { .debug = return } // WithInfoLogger is a chainable configuration function which sets the // Info-level logger. func ( *DefaultLeveledLogger) ( *log.Logger) *DefaultLeveledLogger { .info = return } // WithWarnLogger is a chainable configuration function which sets the // Warn-level logger. func ( *DefaultLeveledLogger) ( *log.Logger) *DefaultLeveledLogger { .warn = return } // WithErrorLogger is a chainable configuration function which sets the // Error-level logger. func ( *DefaultLeveledLogger) ( *log.Logger) *DefaultLeveledLogger { .err = return } // WithOutput is a chainable configuration function which sets the logger's // logging output to the supplied io.Writer. func ( *DefaultLeveledLogger) ( io.Writer) *DefaultLeveledLogger { .writer.SetOutput() return } func ( *DefaultLeveledLogger) ( *log.Logger, LogLevel, string, ...interface{}) { if .level.Get() < { return } := 3 // this frame + wrapper func + caller := fmt.Sprintf(, ...) if := .Output(, ); != nil { fmt.Fprintf(os.Stderr, "Unable to log: %s", ) } } // SetLevel sets the logger's logging level. func ( *DefaultLeveledLogger) ( LogLevel) { .level.Set() } // Trace emits the preformatted message if the logger is at or below LogLevelTrace. func ( *DefaultLeveledLogger) ( string) { .logf(.trace, LogLevelTrace, ) // nolint: govet } // Tracef formats and emits a message if the logger is at or below LogLevelTrace. func ( *DefaultLeveledLogger) ( string, ...interface{}) { .logf(.trace, LogLevelTrace, , ...) } // Debug emits the preformatted message if the logger is at or below LogLevelDebug. func ( *DefaultLeveledLogger) ( string) { .logf(.debug, LogLevelDebug, ) // nolint: govet } // Debugf formats and emits a message if the logger is at or below LogLevelDebug. func ( *DefaultLeveledLogger) ( string, ...interface{}) { .logf(.debug, LogLevelDebug, , ...) } // Info emits the preformatted message if the logger is at or below LogLevelInfo. func ( *DefaultLeveledLogger) ( string) { .logf(.info, LogLevelInfo, ) // nolint: govet } // Infof formats and emits a message if the logger is at or below LogLevelInfo. func ( *DefaultLeveledLogger) ( string, ...interface{}) { .logf(.info, LogLevelInfo, , ...) } // Warn emits the preformatted message if the logger is at or below LogLevelWarn. func ( *DefaultLeveledLogger) ( string) { .logf(.warn, LogLevelWarn, ) // nolint: govet } // Warnf formats and emits a message if the logger is at or below LogLevelWarn. func ( *DefaultLeveledLogger) ( string, ...interface{}) { .logf(.warn, LogLevelWarn, , ...) } // Error emits the preformatted message if the logger is at or below LogLevelError. func ( *DefaultLeveledLogger) ( string) { .logf(.err, LogLevelError, ) // nolint: govet } // Errorf formats and emits a message if the logger is at or below LogLevelError. func ( *DefaultLeveledLogger) ( string, ...interface{}) { .logf(.err, LogLevelError, , ...) } // NewDefaultLeveledLoggerForScope returns a configured LeveledLogger. func ( string, LogLevel, io.Writer) *DefaultLeveledLogger { if == nil { = os.Stderr } := &DefaultLeveledLogger{ writer: &loggerWriter{output: }, level: , } return . WithTraceLogger(log.New(.writer, fmt.Sprintf("%s TRACE: ", ), log.Lmicroseconds|log.Lshortfile)). WithDebugLogger(log.New(.writer, fmt.Sprintf("%s DEBUG: ", ), log.Lmicroseconds|log.Lshortfile)). WithInfoLogger(log.New(.writer, fmt.Sprintf("%s INFO: ", ), log.LstdFlags)). WithWarnLogger(log.New(.writer, fmt.Sprintf("%s WARNING: ", ), log.LstdFlags)). WithErrorLogger(log.New(.writer, fmt.Sprintf("%s ERROR: ", ), log.LstdFlags)) } // DefaultLoggerFactory define levels by scopes and creates new DefaultLeveledLogger. type DefaultLoggerFactory struct { Writer io.Writer DefaultLogLevel LogLevel ScopeLevels map[string]LogLevel } // NewDefaultLoggerFactory creates a new DefaultLoggerFactory. func () *DefaultLoggerFactory { := DefaultLoggerFactory{} .DefaultLogLevel = LogLevelError .ScopeLevels = make(map[string]LogLevel) .Writer = os.Stderr := map[string]LogLevel{ "DISABLE": LogLevelDisabled, "ERROR": LogLevelError, "WARN": LogLevelWarn, "INFO": LogLevelInfo, "DEBUG": LogLevelDebug, "TRACE": LogLevelTrace, } for , := range { := os.Getenv(fmt.Sprintf("PION_LOG_%s", )) if == "" { = os.Getenv(fmt.Sprintf("PIONS_LOG_%s", )) } if == "" { continue } if strings.ToLower() == "all" { if .DefaultLogLevel < { .DefaultLogLevel = } continue } := strings.Split(strings.ToLower(), ",") for , := range { .ScopeLevels[] = } } return & } // NewLogger returns a configured LeveledLogger for the given, argsscope. func ( *DefaultLoggerFactory) ( string) LeveledLogger { := .DefaultLogLevel if .ScopeLevels != nil { , := .ScopeLevels[] if { = } } return NewDefaultLeveledLoggerForScope(, , .Writer) }