github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/logger/logger.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package logger
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/names/v5"
    10  	"github.com/juju/worker/v3"
    11  
    12  	"github.com/juju/juju/core/watcher"
    13  	"github.com/juju/juju/state/mgo"
    14  )
    15  
    16  // LoggerAPI represents the API calls the logger makes.
    17  type LoggerAPI interface {
    18  	LoggingConfig(agentTag names.Tag) (string, error)
    19  	WatchLoggingConfig(agentTag names.Tag) (watcher.NotifyWatcher, error)
    20  }
    21  
    22  // WorkerConfig contains the information required for the Logger worker
    23  // to operate.
    24  type WorkerConfig struct {
    25  	Context  *loggo.Context
    26  	API      LoggerAPI
    27  	Tag      names.Tag
    28  	Logger   Logger
    29  	Override string
    30  
    31  	Callback func(string) error
    32  }
    33  
    34  // Validate ensures all the necessary fields have values.
    35  func (c *WorkerConfig) Validate() error {
    36  	if c.Context == nil {
    37  		return errors.NotValidf("missing logging context")
    38  	}
    39  	if c.API == nil {
    40  		return errors.NotValidf("missing api")
    41  	}
    42  	if c.Logger == nil {
    43  		return errors.NotValidf("missing logger")
    44  	}
    45  	return nil
    46  }
    47  
    48  // loggerWorker is responsible for updating the loggo configuration when the
    49  // environment watcher tells the agent that the value has changed.
    50  type loggerWorker struct {
    51  	config     WorkerConfig
    52  	lastConfig string
    53  }
    54  
    55  // NewLogger returns a worker.Worker that uses the notify watcher returned
    56  // from the setup.
    57  func NewLogger(config WorkerConfig) (worker.Worker, error) {
    58  	if err := config.Validate(); err != nil {
    59  		return nil, errors.Trace(err)
    60  	}
    61  	logger := &loggerWorker{
    62  		config:     config,
    63  		lastConfig: config.Context.Config().String(),
    64  	}
    65  	config.Logger.Debugf("initial log config: %q", logger.lastConfig)
    66  
    67  	w, err := watcher.NewNotifyWorker(watcher.NotifyConfig{
    68  		Handler: logger,
    69  	})
    70  	if err != nil {
    71  		return nil, errors.Trace(err)
    72  	}
    73  	return w, nil
    74  }
    75  
    76  func (l *loggerWorker) setLogging() {
    77  	loggingConfig := ""
    78  	logger := l.config.Logger
    79  
    80  	if override := l.config.Override; override != "" {
    81  		logger.Debugf("overriding logging config with override from agent.conf %q", override)
    82  		loggingConfig = override
    83  	} else {
    84  		modelLoggingConfig, err := l.config.API.LoggingConfig(l.config.Tag)
    85  		if err != nil {
    86  			logger.Errorf("%v", err)
    87  			return
    88  		}
    89  		loggingConfig = modelLoggingConfig
    90  	}
    91  
    92  	if loggingConfig != l.lastConfig {
    93  		logger.Debugf("reconfiguring logging from %q to %q", l.lastConfig, loggingConfig)
    94  		context := l.config.Context
    95  		context.ResetLoggerLevels()
    96  		if err := context.ConfigureLoggers(loggingConfig); err != nil {
    97  			// This shouldn't occur as the loggingConfig should be
    98  			// validated by the original Config before it gets here.
    99  			logger.Warningf("configure loggers failed: %v", err)
   100  			// Try to reset to what we had before
   101  			_ = context.ConfigureLoggers(l.lastConfig)
   102  			return
   103  		}
   104  		mgo.ConfigureMgoLogging()
   105  		l.lastConfig = loggingConfig
   106  		// Save the logging config in the agent.conf file.
   107  		if callback := l.config.Callback; callback != nil {
   108  			err := callback(loggingConfig)
   109  			if err != nil {
   110  				logger.Errorf("%v", err)
   111  			}
   112  		}
   113  	}
   114  }
   115  
   116  // SetUp is called by the NotifyWorker when the worker starts, and it is
   117  // required to return a notify watcher that is used as the event source
   118  // for the Handle method.
   119  func (l *loggerWorker) SetUp() (watcher.NotifyWatcher, error) {
   120  	l.config.Logger.Infof("logger worker started")
   121  	// We need to set this up initially as the NotifyWorker sucks up the first
   122  	// event.
   123  	l.setLogging()
   124  	return l.config.API.WatchLoggingConfig(l.config.Tag)
   125  }
   126  
   127  // Handle is called by the NotifyWorker whenever the notify event is fired.
   128  func (l *loggerWorker) Handle(_ <-chan struct{}) error {
   129  	l.setLogging()
   130  	return nil
   131  }
   132  
   133  // TearDown is called by the NotifyWorker when the worker is being stopped.
   134  func (l *loggerWorker) TearDown() error {
   135  	// Nothing to cleanup, only state is the watcher
   136  	l.config.Logger.Infof("logger worker stopped")
   137  	return nil
   138  }