gitlab.com/gitlab-org/labkit@v1.21.0/log/initialization.go (about)

     1  package log
     2  
     3  import (
     4  	"io"
     5  	"log"
     6  	"os"
     7  	"os/signal"
     8  	"syscall"
     9  
    10  	"github.com/client9/reopen"
    11  	"github.com/sirupsen/logrus"
    12  )
    13  
    14  type nopCloser struct{}
    15  
    16  func (nopCloser) Close() error { return nil }
    17  
    18  // Initialize will configure the logger based on the options passed. It will
    19  // validate the options and if validation fails drop to the defaults while
    20  // logging a message to STDERR.
    21  func Initialize(opts ...LoggerOption) (io.Closer, error) {
    22  	conf := applyLoggerOptions(opts)
    23  
    24  	// Being unable to open the output file will cause an error
    25  	writer, closer, err := getOutputWriter(conf)
    26  	if err != nil {
    27  		return closer, err
    28  	}
    29  
    30  	conf.logger.SetFormatter(conf.buildFormatter())
    31  	conf.logger.SetLevel(conf.level)
    32  	conf.logger.SetOutput(writer)
    33  
    34  	// Only output the warnings _after_ the logger has been configured
    35  	for _, warning := range conf.warnings {
    36  		conf.logger.Warn(warning)
    37  	}
    38  
    39  	return closer, nil
    40  }
    41  
    42  func getOutputWriter(conf *loggerConfig) (io.Writer, io.Closer, error) {
    43  	if conf.writer != nil {
    44  		return conf.writer, nopCloser{}, nil
    45  	}
    46  
    47  	// When writing to a file, use `reopen` so that we can
    48  	// reopen the file on SIGHUP signals
    49  	f, err := reopen.NewFileWriterMode(conf.outputPath, 0644)
    50  	if err != nil {
    51  		return f, nopCloser{}, err
    52  	}
    53  
    54  	isMainLogger := conf.logger == logger
    55  
    56  	sighup := make(chan os.Signal, 1)
    57  	signal.Notify(sighup, syscall.SIGHUP)
    58  	go listenForSignalHangup(f, isMainLogger, conf.outputPath, sighup)
    59  
    60  	return f, f, nil
    61  }
    62  
    63  // Will listen for SIGHUP signals and reopen the underlying file.
    64  func listenForSignalHangup(l reopen.Reopener, isMainLogger bool, logFilePath string, sighup chan os.Signal) {
    65  	for v := range sighup {
    66  		// Specifically, do _not_ write to the log that is being reopened,
    67  		// but log this to the _main_ log file instead as the actual log
    68  		// might be specialised, eg: an access logger leading to an incorrect entry
    69  		logger.WithFields(logrus.Fields{"signal": v, "path": logFilePath}).Print("Reopening log file on signal")
    70  
    71  		err := l.Reopen()
    72  		if err != nil {
    73  			if isMainLogger {
    74  				// Main logger failed to reopen, last ditch effort to notify the user, but don't
    75  				// do this for auxiliary loggers, since we may get double-logs
    76  				log.Printf("Unable to reopen log file '%s' after %v. Error %v", logFilePath, v, err)
    77  			} else {
    78  				logger.WithError(err).WithFields(logrus.Fields{"signal": v, "path": logFilePath}).Print("Failed to reopen log file")
    79  			}
    80  		}
    81  	}
    82  }