2020-04-29 20:51:32 +00:00
package logger
import (
2020-12-08 18:16:25 +00:00
"fmt"
2020-11-25 06:55:13 +00:00
"io"
2020-04-29 20:51:32 +00:00
"os"
2020-12-02 20:58:17 +00:00
"path"
2020-04-29 20:51:32 +00:00
2020-11-25 06:55:13 +00:00
"github.com/rs/zerolog"
fallbacklog "github.com/rs/zerolog/log"
2020-11-15 01:49:44 +00:00
"github.com/urfave/cli/v2"
2020-12-02 20:58:17 +00:00
"gopkg.in/natefinch/lumberjack.v2"
2020-11-15 01:49:44 +00:00
)
const (
EnableTerminalLog = false
DisableTerminalLog = true
LogLevelFlag = "loglevel"
LogFileFlag = "logfile"
LogDirectoryFlag = "log-directory"
LogTransportLevelFlag = "transport-loglevel"
LogSSHDirectoryFlag = "log-directory"
LogSSHLevelFlag = "log-level"
2020-12-08 18:16:25 +00:00
dirPermMode = 0744 // rwxr--r--
filePermMode = 0644 // rw-r--r--
2020-04-29 20:51:32 +00:00
)
2020-12-02 20:58:17 +00:00
func fallbackLogger ( err error ) * zerolog . Logger {
failLog := fallbacklog . With ( ) . Logger ( )
fallbacklog . Error ( ) . Msgf ( "Falling back to a default logger due to logger setup failure: %s" , err )
return & failLog
}
2020-11-25 06:55:13 +00:00
func newZerolog ( loggerConfig * Config ) * zerolog . Logger {
var writers [ ] io . Writer
2020-11-15 01:49:44 +00:00
2020-11-25 06:55:13 +00:00
if loggerConfig . ConsoleConfig != nil {
2020-12-02 20:58:17 +00:00
writers = append ( writers , createConsoleLogger ( * loggerConfig . ConsoleConfig ) )
2020-11-15 01:49:44 +00:00
}
2020-12-08 18:16:25 +00:00
if loggerConfig . FileConfig != nil {
fileLogger , err := createFileLogger ( * loggerConfig . FileConfig )
if err != nil {
return fallbackLogger ( err )
}
writers = append ( writers , fileLogger )
}
2020-12-02 20:58:17 +00:00
if loggerConfig . RollingConfig != nil {
rollingLogger , err := createRollingLogger ( * loggerConfig . RollingConfig )
if err != nil {
return fallbackLogger ( err )
}
writers = append ( writers , rollingLogger )
}
2020-11-15 01:49:44 +00:00
2020-11-25 06:55:13 +00:00
multi := zerolog . MultiLevelWriter ( writers ... )
2020-11-15 01:49:44 +00:00
2020-11-25 06:55:13 +00:00
level , err := zerolog . ParseLevel ( loggerConfig . MinLevel )
2020-11-15 01:49:44 +00:00
if err != nil {
2020-12-02 20:58:17 +00:00
return fallbackLogger ( err )
2020-11-15 01:49:44 +00:00
}
2020-11-25 06:55:13 +00:00
log := zerolog . New ( multi ) . With ( ) . Timestamp ( ) . Logger ( ) . Level ( level )
2020-11-15 01:49:44 +00:00
2020-11-25 06:55:13 +00:00
return & log
2020-11-15 01:49:44 +00:00
}
2020-11-25 06:55:13 +00:00
func CreateTransportLoggerFromContext ( c * cli . Context , disableTerminal bool ) * zerolog . Logger {
2020-11-15 01:49:44 +00:00
return createFromContext ( c , LogTransportLevelFlag , LogDirectoryFlag , disableTerminal )
}
2020-11-25 06:55:13 +00:00
func CreateLoggerFromContext ( c * cli . Context , disableTerminal bool ) * zerolog . Logger {
2020-11-15 01:49:44 +00:00
return createFromContext ( c , LogLevelFlag , LogDirectoryFlag , disableTerminal )
}
2020-11-25 06:55:13 +00:00
func CreateSSHLoggerFromContext ( c * cli . Context , disableTerminal bool ) * zerolog . Logger {
2020-11-15 01:49:44 +00:00
return createFromContext ( c , LogSSHLevelFlag , LogSSHDirectoryFlag , disableTerminal )
}
func createFromContext (
c * cli . Context ,
logLevelFlagName ,
logDirectoryFlagName string ,
disableTerminal bool ,
2020-11-25 06:55:13 +00:00
) * zerolog . Logger {
2020-11-15 01:49:44 +00:00
logLevel := c . String ( logLevelFlagName )
logFile := c . String ( LogFileFlag )
logDirectory := c . String ( logDirectoryFlagName )
2020-11-25 06:55:13 +00:00
loggerConfig := CreateConfig (
logLevel ,
disableTerminal ,
logDirectory ,
logFile ,
)
2020-11-15 01:49:44 +00:00
2020-12-08 18:16:25 +00:00
log := newZerolog ( loggerConfig )
if incompatibleFlagsSet := logFile != "" && logDirectory != "" ; incompatibleFlagsSet {
log . Error ( ) . Msgf ( "Your config includes values for both %s and %s, but they are incompatible. %s takes precedence." , LogFileFlag , logDirectoryFlagName , LogFileFlag )
}
return log
2020-11-15 01:49:44 +00:00
}
2020-11-25 06:55:13 +00:00
func Create ( loggerConfig * Config ) * zerolog . Logger {
if loggerConfig == nil {
loggerConfig = & defaultConfig
2020-04-29 20:51:32 +00:00
}
2020-08-14 21:51:00 +00:00
2020-11-25 06:55:13 +00:00
return newZerolog ( loggerConfig )
2020-08-14 21:51:00 +00:00
}
2020-12-02 20:58:17 +00:00
func createConsoleLogger ( config ConsoleConfig ) io . Writer {
return zerolog . ConsoleWriter {
Out : os . Stderr ,
NoColor : config . noColor ,
}
}
2020-12-08 18:16:25 +00:00
func createFileLogger ( config FileConfig ) ( io . Writer , error ) {
var logFile io . Writer
fullpath := config . Fullpath ( )
// Try to open the existing file
logFile , err := os . OpenFile ( fullpath , os . O_APPEND | os . O_WRONLY , filePermMode )
if err != nil {
// If the existing file wasn't found, or couldn't be opened, just ignore
// it and recreate a new one.
logFile , err = createLogFile ( config )
// If creating a new logfile fails, then we have no choice but to error out.
if err != nil {
return nil , err
}
}
fileLogger := zerolog . New ( logFile ) . With ( ) . Logger ( )
return fileLogger , nil
}
func createLogFile ( config FileConfig ) ( io . Writer , error ) {
if config . Dirname != "" {
err := os . MkdirAll ( config . Dirname , dirPermMode )
if err != nil {
return nil , fmt . Errorf ( "unable to create directories for new logfile: %s" , err )
}
}
mode := os . FileMode ( filePermMode )
logFile , err := os . OpenFile ( config . Filename , os . O_CREATE | os . O_WRONLY | os . O_TRUNC , mode )
if err != nil {
return nil , fmt . Errorf ( "unable to create a new logfile: %s" , err )
}
return logFile , nil
}
2020-12-02 20:58:17 +00:00
func createRollingLogger ( config RollingConfig ) ( io . Writer , error ) {
2020-12-08 18:16:25 +00:00
if err := os . MkdirAll ( config . Dirname , dirPermMode ) ; err != nil {
2020-12-02 20:58:17 +00:00
return nil , err
}
return & lumberjack . Logger {
2020-12-08 18:16:25 +00:00
Filename : path . Join ( config . Dirname , config . Filename ) ,
2020-12-02 20:58:17 +00:00
MaxBackups : config . maxBackups ,
MaxSize : config . maxSize ,
MaxAge : config . maxAge ,
} , nil
}