diff options
Diffstat (limited to 'internal/logger')
| -rw-r--r-- | internal/logger/logger.go | 457 |
1 files changed, 0 insertions, 457 deletions
diff --git a/internal/logger/logger.go b/internal/logger/logger.go deleted file mode 100644 index ca85e32..0000000 --- a/internal/logger/logger.go +++ /dev/null @@ -1,457 +0,0 @@ -package logger - -import ( - "bufio" - "fmt" - "os" - "os/signal" - "runtime" - "strings" - "sync" - "syscall" - "time" - - "github.com/mimecast/dtail/internal/color" - "github.com/mimecast/dtail/internal/config" -) - -const ( - clientStr string = "CLIENT" - serverStr string = "SERVER" - infoStr string = "INFO" - warnStr string = "WARN" - errorStr string = "ERROR" - fatalStr string = "FATAL" - debugStr string = "DEBUG" - traceStr string = "TRACE" -) - -// Synchronise access to logging. -var mutex sync.Mutex - -// File descriptor of log file when logToFile enabled. -var fd *os.File - -// File write buffer of log file when logToFile enabled. -var writer *bufio.Writer - -// File write buffer of stdout when logToStdout enabled. -var stdoutWriter *bufio.Writer - -// Current hostname. -var hostname string - -// Used to detect change of day (create one log file per day0 -var lastDateStr string - -// True if log in server mode, false if log in client mode. -var serverEnable bool - -// Used to make logging non-blocking. -var logBufCh chan buf -var stdoutBufCh chan string - -// Stdout channel, required to pause output -var pauseCh chan struct{} -var resumeCh chan struct{} - -// Tell the logger that we are done, program shuts down -var stop chan struct{} -var stdoutFlushed chan struct{} - -// Tell the logger about logrotation -var rotateCh chan os.Signal - -// LogMode allows to specify the verbosity of logging. -type LogMode int - -// Possible log modes. -const ( - NormalMode LogMode = iota - DebugMode LogMode = iota - SilentMode LogMode = iota - TraceMode LogMode = iota - NothingMode LogMode = iota -) - -// Mode is the current log mode in use. -var Mode LogMode - -// LogStrategy allows to specify a log rotation strategy. -type LogStrategy int - -// Possible log strategies. -const ( - NormalStrategy LogStrategy = iota - DailyStrategy LogStrategy = iota - StdoutStrategy LogStrategy = iota -) - -// Strategy is the current log strattegy used. -var Strategy LogStrategy - -// Enables logging to stdout. -var logToStdout bool - -// Enables logging to file. -var logToFile bool - -// Helper type to make logging non-blocking. -type buf struct { - time time.Time - message string -} - -// Start logging. -func Start(myServerEnable, debugEnable, silentEnable, nothingEnable bool) { - serverEnable = myServerEnable - - mode := logMode(debugEnable, silentEnable, nothingEnable) - strategy := logStrategy() - - stdoutWriter = bufio.NewWriter(os.Stdout) - Mode = mode - Strategy = strategy - - if Mode == NothingMode { - return - } - - switch Strategy { - case DailyStrategy: - _, err := os.Stat(config.Common.LogDir) - logToFile = !os.IsNotExist(err) - logToStdout = !serverEnable || Mode == DebugMode || Mode == TraceMode - case StdoutStrategy: - fallthrough - default: - logToFile = false - logToStdout = true - } - - fqdn, err := os.Hostname() - if err != nil { - panic(err) - } - s := strings.Split(fqdn, ".") - hostname = s[0] - - pauseCh = make(chan struct{}) - resumeCh = make(chan struct{}) - stop = make(chan struct{}) - stdoutFlushed = make(chan struct{}) - - // Setup logrotation - rotateCh = make(chan os.Signal, 1) - signal.Notify(rotateCh, syscall.SIGHUP) - - if logToStdout { - stdoutBufCh = make(chan string, runtime.NumCPU()*100) - go writeToStdout() - } - - if logToFile { - logBufCh = make(chan buf, runtime.NumCPU()*100) - go writeToFile() - } -} - -func logMode(debugEnable, silentEnable, nothingEnable bool) LogMode { - switch { - case debugEnable: - return DebugMode - case nothingEnable: - return NothingMode - case config.Common.TraceEnable: - return TraceMode - case config.Common.DebugEnable: - return DebugMode - case silentEnable: - return SilentMode - default: - } - return NormalMode -} - -func logStrategy() LogStrategy { - switch config.Common.LogStrategy { - case "daily": - return DailyStrategy - default: - } - return StdoutStrategy -} - -// Info message logging. -func Info(args ...interface{}) string { - if serverEnable { - return log(serverStr, infoStr, args) - } - - return log(clientStr, infoStr, args) -} - -// Warn message logging. -func Warn(args ...interface{}) string { - if serverEnable { - return log(serverStr, warnStr, args) - } - - return log(clientStr, warnStr, args) -} - -// Error message logging. -func Error(args ...interface{}) string { - if serverEnable { - return log(serverStr, errorStr, args) - } - - return log(clientStr, errorStr, args) -} - -// FatalExit logs an error and exists the process. -func FatalExit(args ...interface{}) { - what := clientStr - if serverEnable { - what = serverStr - } - log(what, fatalStr, args) - - time.Sleep(time.Second) - mutex.Lock() - defer mutex.Unlock() - - closeWriter() - os.Exit(3) -} - -// Debug message logging. -func Debug(args ...interface{}) string { - if Mode == DebugMode || Mode == TraceMode { - if serverEnable { - return log(serverStr, debugStr, args) - } - return log(clientStr, debugStr, args) - } - - return "" -} - -// Trace message logging. -func Trace(args ...interface{}) string { - if Mode == TraceMode { - if serverEnable { - return log(serverStr, traceStr, args) - } - return log(clientStr, traceStr, args) - } - - return "" -} - -// Write log line to buffer and/or log file. -func write(what, severity, message string) { - if logToStdout && (Mode != SilentMode || severity != warnStr) { - line := fmt.Sprintf("%s|%s|%s|%s\n", what, hostname, severity, message) - - if color.Colored { - line = color.Colorfy(line) - } - - stdoutBufCh <- line - } - - if logToFile { - t := time.Now() - timeStr := t.Format("20060102-150405") - logBufCh <- buf{ - time: t, - message: fmt.Sprintf("%s|%s|%s|%s\n", severity, timeStr, what, message), - } - } -} - -// Generig log message. -func log(what string, severity string, args []interface{}) string { - if Mode == NothingMode { - return "" - } - - var messages []string - - for _, arg := range args { - switch v := arg.(type) { - case string: - messages = append(messages, v) - case int: - messages = append(messages, fmt.Sprintf("%d", v)) - case error: - messages = append(messages, v.Error()) - default: - messages = append(messages, fmt.Sprintf("%v", v)) - } - } - - message := strings.Join(messages, "|") - write(what, severity, message) - - return fmt.Sprintf("%s|%s", severity, message) -} - -// Raw message logging. -func Raw(message string) { - if Mode == NothingMode { - return - } - - if logToStdout { - if color.Colored { - message = color.Colorfy(message) - } - stdoutBufCh <- message - } - - if logToFile { - logBufCh <- buf{time.Now(), message} - } -} - -// Close log writer (e.g. on change of day). -func closeWriter() { - if writer != nil { - writer.Flush() - fd.Close() - } -} - -// Return the correct log file writer -func fileWriter(dateStr string) *bufio.Writer { - if dateStr != lastDateStr { - return updateFileWriter(dateStr) - } - - // Check for log rotation signal - select { - case <-rotateCh: - stdoutWriter.WriteString("Received signal for logrotation\n") - return updateFileWriter(dateStr) - default: - } - - return writer -} - -// Update log file writer -func updateFileWriter(dateStr string) *bufio.Writer { - // Detected change of day. Close current writer and create a new one. - mutex.Lock() - defer mutex.Unlock() - closeWriter() - - if _, err := os.Stat(config.Common.LogDir); os.IsNotExist(err) { - if err = os.MkdirAll(config.Common.LogDir, 0755); err != nil { - panic(err) - } - } - - logFile := fmt.Sprintf("%s/%s.log", config.Common.LogDir, dateStr) - newFd, err := os.OpenFile(logFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644) - if err != nil { - panic(err) - } - - fd = newFd - writer = bufio.NewWriterSize(fd, 1) - lastDateStr = dateStr - - return writer -} - -func flushStdout() { - defer close(stdoutFlushed) - - for { - select { - case message := <-stdoutBufCh: - stdoutWriter.WriteString(message) - default: - stdoutWriter.Flush() - return - } - } -} - -func writeToStdout() { - for { - select { - case message := <-stdoutBufCh: - stdoutWriter.WriteString(message) - case <-time.After(time.Millisecond * 100): - stdoutWriter.Flush() - case <-pauseCh: - PAUSE: - for { - select { - case <-stdoutBufCh: - case <-resumeCh: - break PAUSE - case <-stop: - return - } - } - case <-stop: - flushStdout() - return - } - } -} - -func writeToFile() { - for { - select { - case buf := <-logBufCh: - dateStr := buf.time.Format("20060102") - w := fileWriter(dateStr) - w.WriteString(buf.message) - case <-pauseCh: - PAUSE: - for { - select { - case <-stdoutBufCh: - case <-resumeCh: - break PAUSE - case <-stop: - return - } - } - case <-stop: - return - } - } -} - -// Pause logging. -func Pause() { - if logToStdout { - pauseCh <- struct{}{} - } - if logToFile { - pauseCh <- struct{}{} - } -} - -// Resume logging (after pausing). -func Resume() { - if logToStdout { - resumeCh <- struct{}{} - } - if logToFile { - resumeCh <- struct{}{} - } -} - -// Stop logging. -func Stop() { - close(stop) - <-stdoutFlushed -} |
