github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/logger/logger.go (about) 1 package logger 2 3 import ( 4 "fmt" 5 "io" 6 "path/filepath" 7 "strings" 8 "time" 9 10 "github.com/hashicorp/go-syslog" 11 "github.com/hashicorp/logutils" 12 "github.com/mitchellh/cli" 13 ) 14 15 // Config is used to set up logging. 16 type Config struct { 17 // LogLevel is the minimum level to be logged. 18 LogLevel string 19 20 // EnableSyslog controls forwarding to syslog. 21 EnableSyslog bool 22 23 // SyslogFacility is the destination for syslog forwarding. 24 SyslogFacility string 25 26 //LogFilePath is the path to write the logs to the user specified file. 27 LogFilePath string 28 29 //LogRotateDuration is the user specified time to rotate logs 30 LogRotateDuration time.Duration 31 32 //LogRotateBytes is the user specified byte limit to rotate logs 33 LogRotateBytes int 34 } 35 36 const ( 37 // defaultRotateDuration is the default time taken by the agent to rotate logs 38 defaultRotateDuration = 24 * time.Hour 39 ) 40 41 var ( 42 logRotateDuration time.Duration 43 logRotateBytes int 44 ) 45 46 // Setup is used to perform setup of several logging objects: 47 // 48 // * A LevelFilter is used to perform filtering by log level. 49 // * A GatedWriter is used to buffer logs until startup UI operations are 50 // complete. After this is flushed then logs flow directly to output 51 // destinations. 52 // * A LogWriter provides a mean to temporarily hook logs, such as for running 53 // a command like "consul monitor". 54 // * An io.Writer is provided as the sink for all logs to flow to. 55 // 56 // The provided ui object will get any log messages related to setting up 57 // logging itself, and will also be hooked up to the gated logger. The final bool 58 // parameter indicates if logging was set up successfully. 59 func Setup(config *Config, ui cli.Ui) (*logutils.LevelFilter, *GatedWriter, *LogWriter, io.Writer, bool) { 60 // The gated writer buffers logs at startup and holds until it's flushed. 61 logGate := &GatedWriter{ 62 Writer: &cli.UiWriter{Ui: ui}, 63 } 64 65 // Set up the level filter. 66 logFilter := LevelFilter() 67 logFilter.MinLevel = logutils.LogLevel(strings.ToUpper(config.LogLevel)) 68 logFilter.Writer = logGate 69 if !ValidateLevelFilter(logFilter.MinLevel, logFilter) { 70 ui.Error(fmt.Sprintf( 71 "Invalid log level: %s. Valid log levels are: %v", 72 logFilter.MinLevel, logFilter.Levels)) 73 return nil, nil, nil, nil, false 74 } 75 76 // Set up syslog if it's enabled. 77 var syslog io.Writer 78 if config.EnableSyslog { 79 retries := 12 80 delay := 5 * time.Second 81 for i := 0; i <= retries; i++ { 82 l, err := gsyslog.NewLogger(gsyslog.LOG_NOTICE, config.SyslogFacility, "consul") 83 if err == nil { 84 syslog = &SyslogWrapper{l, logFilter} 85 break 86 } 87 88 ui.Error(fmt.Sprintf("Syslog setup error: %v", err)) 89 if i == retries { 90 timeout := time.Duration(retries) * delay 91 ui.Error(fmt.Sprintf("Syslog setup did not succeed within timeout (%s).", timeout.String())) 92 return nil, nil, nil, nil, false 93 } 94 95 ui.Error(fmt.Sprintf("Retrying syslog setup in %s...", delay.String())) 96 time.Sleep(delay) 97 } 98 } 99 // Create a log writer, and wrap a logOutput around it 100 logWriter := NewLogWriter(512) 101 writers := []io.Writer{logFilter, logWriter} 102 103 var logOutput io.Writer 104 if syslog != nil { 105 writers = append(writers, syslog) 106 } 107 108 // Create a file logger if the user has specified the path to the log file 109 if config.LogFilePath != "" { 110 dir, fileName := filepath.Split(config.LogFilePath) 111 // If a path is provided but has no fileName a default is provided. 112 if fileName == "" { 113 fileName = "consul.log" 114 } 115 // Try to enter the user specified log rotation duration first 116 if config.LogRotateDuration != 0 { 117 logRotateDuration = config.LogRotateDuration 118 } else { 119 // Default to 24 hrs if no rotation period is specified 120 logRotateDuration = defaultRotateDuration 121 } 122 // User specified byte limit for log rotation if one is provided 123 if config.LogRotateBytes != 0 { 124 logRotateBytes = config.LogRotateBytes 125 } 126 logFile := &LogFile{fileName: fileName, logPath: dir, duration: logRotateDuration, MaxBytes: logRotateBytes} 127 writers = append(writers, logFile) 128 } 129 130 logOutput = io.MultiWriter(writers...) 131 return logFilter, logGate, logWriter, logOutput, true 132 }