Adds Advanced Logging to server. Advanced Logging is an optional logging capability that allows customers to send log records to any number of destinations.

Supported destinations:
- file
- syslog (with out without TLS)
- raw TCP socket (with out without TLS)

Allows developers to specify discrete log levels as well as the standard trace, debug, info, ... panic. Existing code and logging API usage is unchanged.

Log records are emitted asynchronously to reduce latency to the caller. Supports hot-reloading of logger config, including adding removing targets.

Advanced Logging is configured within config.json via "LogSettings.AdvancedLoggingConfig" which can contain a filespec to another config file, a database DSN, or JSON.
Этот коммит содержится в:
Doug Lauder
2020-07-15 14:40:36 -04:00
коммит произвёл GitHub
родитель 4ba6c35813
Коммит 90ff87a77f
53 изменённых файлов: 1442 добавлений и 82 удалений

Просмотреть файл

@@ -4,10 +4,12 @@
package mlog
import (
"context"
"io"
"log"
"os"
"github.com/mattermost/logr"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
@@ -52,6 +54,7 @@ type Logger struct {
zap *zap.Logger
consoleLevel zap.AtomicLevel
fileLevel zap.AtomicLevel
logrLogger *logr.Logger
}
func getZapLevel(level string) zapcore.Level {
@@ -107,7 +110,6 @@ func NewLogger(config *LoggerConfiguration) *Logger {
logger.zap = zap.New(combinedCore,
zap.AddCaller(),
)
return logger
}
@@ -123,6 +125,10 @@ func (l *Logger) SetConsoleLevel(level string) {
func (l *Logger) With(fields ...Field) *Logger {
newlogger := *l
newlogger.zap = newlogger.zap.With(fields...)
if newlogger.logrLogger != nil {
ll := newlogger.logrLogger.WithFields(zapToLogr(fields))
newlogger.logrLogger = &ll
}
return &newlogger
}
@@ -161,20 +167,98 @@ func (l *Logger) Sugar() *SugarLogger {
func (l *Logger) Debug(message string, fields ...Field) {
l.zap.Debug(message, fields...)
if l.logrLogger != nil && isLevelEnabled(l.logrLogger, logr.Debug) {
l.logrLogger.WithFields(zapToLogr(fields)).Debug(message)
}
}
func (l *Logger) Info(message string, fields ...Field) {
l.zap.Info(message, fields...)
if l.logrLogger != nil && isLevelEnabled(l.logrLogger, logr.Info) {
l.logrLogger.WithFields(zapToLogr(fields)).Info(message)
}
}
func (l *Logger) Warn(message string, fields ...Field) {
l.zap.Warn(message, fields...)
if l.logrLogger != nil && isLevelEnabled(l.logrLogger, logr.Warn) {
l.logrLogger.WithFields(zapToLogr(fields)).Warn(message)
}
}
func (l *Logger) Error(message string, fields ...Field) {
l.zap.Error(message, fields...)
if l.logrLogger != nil && isLevelEnabled(l.logrLogger, logr.Error) {
l.logrLogger.WithFields(zapToLogr(fields)).Error(message)
}
}
func (l *Logger) Critical(message string, fields ...Field) {
l.zap.Error(message, fields...)
if l.logrLogger != nil && isLevelEnabled(l.logrLogger, logr.Error) {
l.logrLogger.WithFields(zapToLogr(fields)).Error(message)
}
}
func (l *Logger) Log(level LogLevel, message string, fields ...Field) {
if l.logrLogger != nil && isLevelEnabled(l.logrLogger, logr.Level(level)) {
l.logrLogger.WithFields(zapToLogr(fields)).Log(logr.Level(level), message)
}
}
func (l *Logger) LogM(levels []LogLevel, message string, fields ...Field) {
if l.logrLogger != nil {
var logger *logr.Logger
for _, lvl := range levels {
if isLevelEnabled(l.logrLogger, logr.Level(lvl)) {
// don't create logger with fields unless at least one level is active.
if logger == nil {
l := l.logrLogger.WithFields(zapToLogr(fields))
logger = &l
}
logger.Log(logr.Level(lvl), message)
}
}
}
}
func (l *Logger) Flush(cxt context.Context) error {
if l.logrLogger != nil {
return l.logrLogger.Logr().Flush() // TODO: use context when Logr lib supports it.
}
return nil
}
// ShutdownAdvancedLogging stops the logger from accepting new log records and tries to
// flush queues within the context timeout. Once complete all targets are shutdown
// and any resources released.
func (l *Logger) ShutdownAdvancedLogging(cxt context.Context) error {
var err error
if l.logrLogger != nil {
err = l.logrLogger.Logr().Shutdown() // TODO: use context when Logr lib supports it.
l.logrLogger = nil
}
return err
}
// ConfigAdvancedLoggingConfig (re)configures advanced logging based on the
// specified log targets. This is the easiest way to get the advanced logger
// configured via a config source such as file.
func (l *Logger) ConfigAdvancedLogging(targets LogTargetCfg) error {
if l.logrLogger != nil {
if err := l.ShutdownAdvancedLogging(context.Background()); err != nil {
Error("error shutting down previous logger", Err(err))
}
}
logr, err := newLogr(targets)
l.logrLogger = logr
return err
}
// AddTarget adds a logr.Target to the advanced logger. This is the preferred method
// to add custom targets or provide configuration that cannot be expressed via a
//config source.
func (l *Logger) AddTarget(target logr.Target) error {
return l.logrLogger.Logr().AddTarget(target)
}