MM-36764 mlog refactor (#18118)
Refactor mlog - simplify mlog by removing redundant code - remove Zap dependency - update unit test helpers - update logging config - update auditing
Этот коммит содержится в:
176
app/server.go
176
app/server.go
@@ -138,7 +138,6 @@ type Server struct {
|
||||
statusCache cache.Cache
|
||||
configListenerId string
|
||||
licenseListenerId string
|
||||
logListenerId string
|
||||
clusterLeaderListenerId string
|
||||
searchConfigListenerId string
|
||||
searchLicenseListenerId string
|
||||
@@ -146,8 +145,6 @@ type Server struct {
|
||||
configStore *config.Store
|
||||
postActionCookieSecret []byte
|
||||
|
||||
advancedLogListenerCleanup func()
|
||||
|
||||
pluginCommands []*PluginCommand
|
||||
pluginCommandsLock sync.RWMutex
|
||||
|
||||
@@ -787,74 +784,79 @@ func (s *Server) DatabaseTypeAndMattermostVersion() (string, string) {
|
||||
return *s.Config().SqlSettings.DriverName, mattermostVersion.Value
|
||||
}
|
||||
|
||||
// initLogging initializes and configures the logger. This may be called more than once.
|
||||
// initLogging initializes and configures the logger(s). This may be called more than once.
|
||||
func (s *Server) initLogging() error {
|
||||
var err error
|
||||
// create the app logger if needed
|
||||
if s.Log == nil {
|
||||
s.Log = mlog.NewLogger(utils.MloggerConfigFromLoggerConfig(&s.Config().LogSettings, utils.GetLogFileLocation))
|
||||
}
|
||||
|
||||
// Use this app logger as the global logger (eventually remove all instances of global logging).
|
||||
// This is deferred because a copy is made of the logger and it must be fully configured before
|
||||
// the copy is made.
|
||||
defer mlog.InitGlobalLogger(s.Log)
|
||||
|
||||
// Redirect default Go logger to this logger.
|
||||
defer mlog.RedirectStdLog(s.Log)
|
||||
|
||||
if s.NotificationsLog == nil {
|
||||
notificationLogSettings := utils.GetLogSettingsFromNotificationsLogSettings(&s.Config().NotificationLogSettings)
|
||||
s.NotificationsLog = mlog.NewLogger(utils.MloggerConfigFromLoggerConfig(notificationLogSettings, utils.GetNotificationsLogFileLocation)).
|
||||
WithCallerSkip(1).With(mlog.String("logSource", "notifications"))
|
||||
}
|
||||
|
||||
if s.logListenerId != "" {
|
||||
s.RemoveConfigListener(s.logListenerId)
|
||||
}
|
||||
s.logListenerId = s.AddConfigListener(func(_, after *model.Config) {
|
||||
s.Log.ChangeLevels(utils.MloggerConfigFromLoggerConfig(&after.LogSettings, utils.GetLogFileLocation))
|
||||
|
||||
notificationLogSettings := utils.GetLogSettingsFromNotificationsLogSettings(&after.NotificationLogSettings)
|
||||
s.NotificationsLog.ChangeLevels(utils.MloggerConfigFromLoggerConfig(notificationLogSettings, utils.GetNotificationsLogFileLocation))
|
||||
})
|
||||
|
||||
// Configure advanced logging.
|
||||
// Advanced logging is E20 only, however logging must be initialized before the license
|
||||
// file is loaded. If no valid E20 license exists then advanced logging will be
|
||||
// shutdown once license is loaded/checked.
|
||||
if *s.Config().LogSettings.AdvancedLoggingConfig != "" {
|
||||
dsn := *s.Config().LogSettings.AdvancedLoggingConfig
|
||||
|
||||
cfg, err := config.NewLogConfigSrc(dsn, s.configStore)
|
||||
s.Log, err = mlog.NewLogger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid advanced logging config, %w", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.Log.ConfigAdvancedLogging(cfg.Get()); err != nil {
|
||||
return fmt.Errorf("error configuring advanced logging, %w", err)
|
||||
// create notification logger if needed
|
||||
if s.NotificationsLog == nil {
|
||||
l, err := mlog.NewLogger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.NotificationsLog = l.With(mlog.String("logSource", "notifications"))
|
||||
}
|
||||
|
||||
mlog.Info("Loaded advanced logging config", mlog.String("source", dsn))
|
||||
|
||||
listenerId := cfg.AddListener(func(_, newCfg mlog.LogTargetCfg) {
|
||||
if err := s.Log.ConfigAdvancedLogging(newCfg); err != nil {
|
||||
mlog.Error("Error re-configuring advanced logging", mlog.Err(err))
|
||||
} else {
|
||||
mlog.Info("Re-configured advanced logging")
|
||||
}
|
||||
})
|
||||
|
||||
// In case initLogging is called more than once.
|
||||
if s.advancedLogListenerCleanup != nil {
|
||||
s.advancedLogListenerCleanup()
|
||||
if err := s.configureLogger("logging", s.Log, &s.Config().LogSettings, s.configStore, config.GetLogFileLocation); err != nil {
|
||||
// if the config is locked then a unit test has already configured and locked the logger; not an error.
|
||||
if !errors.Is(err, mlog.ErrConfigurationLock) {
|
||||
// revert to default logger if the config is invalid
|
||||
mlog.InitGlobalLogger(nil)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s.advancedLogListenerCleanup = func() {
|
||||
cfg.RemoveListener(listenerId)
|
||||
// Redirect default Go logger to app logger.
|
||||
s.Log.RedirectStdLog(mlog.LvlStdLog)
|
||||
|
||||
// Use the app logger as the global logger (eventually remove all instances of global logging).
|
||||
mlog.InitGlobalLogger(s.Log)
|
||||
|
||||
notificationLogSettings := config.GetLogSettingsFromNotificationsLogSettings(&s.Config().NotificationLogSettings)
|
||||
if err := s.configureLogger("notification logging", s.NotificationsLog, notificationLogSettings, s.configStore, config.GetNotificationsLogFileLocation); err != nil {
|
||||
if !errors.Is(err, mlog.ErrConfigurationLock) {
|
||||
mlog.Error("Error configuring notification logger", mlog.Err(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// configureLogger applies the specified configuration to a logger.
|
||||
func (s *Server) configureLogger(name string, logger *mlog.Logger, logSettings *model.LogSettings, configStore *config.Store, getPath func(string) string) error {
|
||||
// Advanced logging is E20 only, however logging must be initialized before the license
|
||||
// file is loaded. If no valid E20 license exists then advanced logging will be
|
||||
// shutdown once license is loaded/checked.
|
||||
var err error
|
||||
dsn := *logSettings.AdvancedLoggingConfig
|
||||
var logConfigSrc config.LogConfigSrc
|
||||
if dsn != "" {
|
||||
logConfigSrc, err = config.NewLogConfigSrc(dsn, configStore)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid config source for %s, %w", name, err)
|
||||
}
|
||||
mlog.Info("Loaded configuration for "+name, mlog.String("source", dsn))
|
||||
}
|
||||
|
||||
cfg, err := config.MloggerConfigFromLoggerConfig(logSettings, logConfigSrc, getPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid config source for %s, %w", name, err)
|
||||
}
|
||||
|
||||
if err := logger.ConfigureTargets(cfg); err != nil {
|
||||
return fmt.Errorf("invalid config for %s, %w", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// removeUnlicensedLogTargets removes any unlicensed log target types.
|
||||
func (s *Server) removeUnlicensedLogTargets(license *model.License) {
|
||||
if license != nil && *license.Features.AdvancedLogging {
|
||||
// advanced logging enabled via license; no need to remove any targets
|
||||
@@ -864,8 +866,12 @@ func (s *Server) removeUnlicensedLogTargets(license *model.License) {
|
||||
timeoutCtx, cancelCtx := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancelCtx()
|
||||
|
||||
mlog.RemoveTargets(timeoutCtx, func(ti mlog.TargetInfo) bool {
|
||||
return ti.Type != "*target.Writer" && ti.Type != "*target.File"
|
||||
s.Log.RemoveTargets(timeoutCtx, func(ti mlog.TargetInfo) bool {
|
||||
return ti.Type != "*targets.Writer" && ti.Type != "*targets.File"
|
||||
})
|
||||
|
||||
s.NotificationsLog.RemoveTargets(timeoutCtx, func(ti mlog.TargetInfo) bool {
|
||||
return ti.Type != "*targets.Writer" && ti.Type != "*targets.File"
|
||||
})
|
||||
}
|
||||
|
||||
@@ -939,11 +945,15 @@ func (s *Server) enableLoggingMetrics() {
|
||||
return
|
||||
}
|
||||
|
||||
if err := mlog.EnableMetrics(s.Metrics.GetLoggerMetricsCollector()); err != nil {
|
||||
mlog.Error("Failed to enable advanced logging metrics", mlog.Err(err))
|
||||
} else {
|
||||
mlog.Debug("Advanced logging metrics enabled")
|
||||
s.Log.SetMetricsCollector(s.Metrics.GetLoggerMetricsCollector(), mlog.DefaultMetricsUpdateFreqMillis)
|
||||
|
||||
// logging config needs to be reloaded when metrics collector is added or changed.
|
||||
if err := s.initLogging(); err != nil {
|
||||
mlog.Error("Error re-configuring logging for metrics")
|
||||
return
|
||||
}
|
||||
|
||||
mlog.Debug("Logging metrics enabled")
|
||||
}
|
||||
|
||||
const TimeToWaitForConnectionsToCloseOnServerShutdown = time.Second
|
||||
@@ -1014,13 +1024,7 @@ func (s *Server) Shutdown() {
|
||||
|
||||
s.WaitForGoroutines()
|
||||
|
||||
if s.advancedLogListenerCleanup != nil {
|
||||
s.advancedLogListenerCleanup()
|
||||
s.advancedLogListenerCleanup = nil
|
||||
}
|
||||
|
||||
s.RemoveConfigListener(s.configListenerId)
|
||||
s.RemoveConfigListener(s.logListenerId)
|
||||
s.stopSearchEngine()
|
||||
|
||||
s.Audit.Shutdown()
|
||||
@@ -1058,12 +1062,6 @@ func (s *Server) Shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), time.Second*15)
|
||||
defer timeoutCancel()
|
||||
if err := mlog.Flush(timeoutCtx); err != nil {
|
||||
mlog.Warn("Error flushing logs", mlog.Err(err))
|
||||
}
|
||||
|
||||
s.dndTaskMut.Lock()
|
||||
if s.dndTask != nil {
|
||||
s.dndTask.Cancel()
|
||||
@@ -1072,10 +1070,15 @@ func (s *Server) Shutdown() {
|
||||
|
||||
mlog.Info("Server stopped")
|
||||
|
||||
// this should just write the "server stopped" record, the rest are already flushed.
|
||||
timeoutCtx2, timeoutCancel2 := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer timeoutCancel2()
|
||||
_ = mlog.ShutdownAdvancedLogging(timeoutCtx2)
|
||||
// shutdown main and notification loggers which will flush any remaining log records.
|
||||
timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), time.Second*15)
|
||||
defer timeoutCancel()
|
||||
if err = s.NotificationsLog.ShutdownWithTimeout(timeoutCtx); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error shutting down notification logger: %v", err)
|
||||
}
|
||||
if err = s.Log.ShutdownWithTimeout(timeoutCtx); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error shutting down main logger: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Restart() error {
|
||||
@@ -1202,7 +1205,7 @@ func (s *Server) Start() error {
|
||||
|
||||
// If we have debugging of CORS turned on then forward messages to logs
|
||||
if debug {
|
||||
corsWrapper.Log = s.Log.StdLog(mlog.String("source", "cors"))
|
||||
corsWrapper.Log = s.Log.With(mlog.String("source", "cors")).StdLogger(mlog.LvlDebug)
|
||||
}
|
||||
|
||||
handler = corsWrapper.Handler(handler)
|
||||
@@ -1222,10 +1225,7 @@ func (s *Server) Start() error {
|
||||
s.Busy = NewBusy(s.Cluster)
|
||||
|
||||
// Creating a logger for logging errors from http.Server at error level
|
||||
errStdLog, err := s.Log.StdLogAt(mlog.LevelError, mlog.String("source", "httpserver"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errStdLog := s.Log.With(mlog.String("source", "httpserver")).StdLogger(mlog.LvlError)
|
||||
|
||||
s.Server = &http.Server{
|
||||
Handler: handler,
|
||||
@@ -1270,7 +1270,7 @@ func (s *Server) Start() error {
|
||||
server := &http.Server{
|
||||
Addr: httpListenAddress,
|
||||
Handler: m.HTTPHandler(nil),
|
||||
ErrorLog: s.Log.StdLog(mlog.String("source", "le_forwarder_server")),
|
||||
ErrorLog: s.Log.With(mlog.String("source", "le_forwarder_server")).StdLogger(mlog.LvlError),
|
||||
}
|
||||
go server.ListenAndServe()
|
||||
} else {
|
||||
@@ -1284,7 +1284,7 @@ func (s *Server) Start() error {
|
||||
|
||||
server := &http.Server{
|
||||
Handler: http.HandlerFunc(handleHTTPRedirect),
|
||||
ErrorLog: s.Log.StdLog(mlog.String("source", "forwarder_server")),
|
||||
ErrorLog: s.Log.With(mlog.String("source", "forwarder_server")).StdLogger(mlog.LvlError),
|
||||
}
|
||||
server.Serve(redirectListener)
|
||||
}()
|
||||
@@ -2026,7 +2026,7 @@ func (a *App) getNotificationsLog() (*model.FileData, string) {
|
||||
// Getting notifications.log
|
||||
if *a.Srv().Config().NotificationLogSettings.EnableFile {
|
||||
// notifications.log
|
||||
notificationsLog := utils.GetNotificationsLogFileLocation(*a.Srv().Config().LogSettings.FileLocation)
|
||||
notificationsLog := config.GetNotificationsLogFileLocation(*a.Srv().Config().LogSettings.FileLocation)
|
||||
|
||||
notificationsLogFileData, notificationsLogFileDataErr := ioutil.ReadFile(notificationsLog)
|
||||
|
||||
@@ -2053,7 +2053,7 @@ func (a *App) getMattermostLog() (*model.FileData, string) {
|
||||
// Getting mattermost.log
|
||||
if *a.Srv().Config().LogSettings.EnableFile {
|
||||
// mattermost.log
|
||||
mattermostLog := utils.GetLogFileLocation(*a.Srv().Config().LogSettings.FileLocation)
|
||||
mattermostLog := config.GetLogFileLocation(*a.Srv().Config().LogSettings.FileLocation)
|
||||
|
||||
mattermostLogFileData, mattermostLogFileDataErr := ioutil.ReadFile(mattermostLog)
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user