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

     1  // Copyright 2023 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package querylogger
     5  
     6  import (
     7  	"runtime/debug"
     8  
     9  	"github.com/juju/clock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/worker/v3"
    12  	"github.com/juju/worker/v3/dependency"
    13  
    14  	coredatabase "github.com/juju/juju/core/database"
    15  	"github.com/juju/juju/worker/common"
    16  )
    17  
    18  // Logger is the interface that is used to log issues with the slow query
    19  // logger.
    20  type Logger interface {
    21  	Warningf(string, ...interface{})
    22  	Errorf(string, ...interface{})
    23  }
    24  
    25  // ManifoldConfig contains:
    26  // - The names of other manifolds on which the DB accessor depends.
    27  // - Other dependencies from ManifoldsConfig required by the worker.
    28  type ManifoldConfig struct {
    29  	LogDir string
    30  	Clock  clock.Clock
    31  	Logger Logger
    32  }
    33  
    34  func (cfg ManifoldConfig) Validate() error {
    35  	if cfg.LogDir == "" {
    36  		return errors.NotValidf("empty LogDir")
    37  	}
    38  	if cfg.Clock == nil {
    39  		return errors.NotValidf("nil Clock")
    40  	}
    41  	if cfg.Logger == nil {
    42  		return errors.NotValidf("nil Logger")
    43  	}
    44  	return nil
    45  }
    46  
    47  // Manifold returns a dependency manifold that runs the query logger
    48  // worker, using the resource names defined in the supplied config.
    49  func Manifold(config ManifoldConfig) dependency.Manifold {
    50  	return dependency.Manifold{
    51  		Inputs: []string{},
    52  		Output: output,
    53  		Start: func(context dependency.Context) (worker.Worker, error) {
    54  			if err := config.Validate(); err != nil {
    55  				return nil, errors.Trace(err)
    56  			}
    57  
    58  			cfg := &WorkerConfig{
    59  				LogDir: config.LogDir,
    60  				Clock:  config.Clock,
    61  				Logger: config.Logger,
    62  				StackGatherer: func() []byte {
    63  					// TODO (stickupkid): Drop the first frames that don't
    64  					// include the slow query logger.
    65  					return debug.Stack()
    66  				},
    67  			}
    68  
    69  			w, err := newWorker(cfg)
    70  			if err != nil {
    71  				return nil, errors.Trace(err)
    72  			}
    73  			return w, nil
    74  		},
    75  	}
    76  }
    77  
    78  func output(in worker.Worker, out interface{}) error {
    79  	if w, ok := in.(*common.CleanupWorker); ok {
    80  		in = w.Worker
    81  	}
    82  	w, ok := in.(*loggerWorker)
    83  	if !ok {
    84  		return errors.Errorf("expected input of type dbWorker, got %T", in)
    85  	}
    86  
    87  	switch out := out.(type) {
    88  	case *coredatabase.SlowQueryLogger:
    89  		var target coredatabase.SlowQueryLogger = w
    90  		*out = target
    91  	default:
    92  		return errors.Errorf("expected output of *database.SlowQueryLogger, got %T", out)
    93  	}
    94  	return nil
    95  }