diff --git a/SPAG.md b/SPAG.md index bc403809..96e4fbd5 100644 --- a/SPAG.md +++ b/SPAG.md @@ -44,18 +44,18 @@ In this example we see three steps, one of which uses `cmd` step plugin and two Step plugin is a Go struct which implements `TestStep` interface. The interface is defined in [pkg/test/step.go](https://github.com/linuxboot/contest/blob/master/pkg/test/step.go) and it looks like this: -``` +```go // TestStep is the interface that all steps need to implement to be executed // by the TestRunner type TestStep interface { // Name returns the name of the step Name() string // Run runs the test step. The test step is expected to be synchronous. - Run(ctx xcontext.Context, ch TestStepChannels, params TestStepParameters, ev testevent.Emitter, + Run(ctx context.Context, ch TestStepChannels, params TestStepParameters, ev testevent.Emitter, resumeState json.RawMessage) (json.RawMessage, error) // ValidateParameters checks that the parameters are correct before passing // them to Run. - ValidateParameters(ctx xcontext.Context, params TestStepParameters) error + ValidateParameters(ctx context.Context, params TestStepParameters) error } ``` @@ -63,7 +63,7 @@ type TestStep interface { `Run` is the heart of the plugin. It’s a method where the main code lives. It’s discussed in the “Implementing Run()” chapter. `ValidateParameters`, yeah, validates parameters and we will discuss it in the “Working with parameters” chapter. There are two additional functions, which also should be implemented: `New` and `Load`. Usually they reside in the same module with the interface implementation. Function `New` returns a reference to a new instance of the plugin (implementation of the TestStep interface) and will be used by Contest to create plugin instances. Function Load is an entry point of the plugin. It’s used during registration process and reports everything Contest needs to know about our plugin. Implementation of the Load function could look like this: -``` +```go // Load returns the name, factory and events which are needed to register the step. func Load() (string, test.TestStepFactory, []event.Name) { return Name, New, Events @@ -91,8 +91,8 @@ Plugin specific parameters can be passed to a plugin instance through `parameter Sometimes Contest may need to pause a job. The most common reason for this is restart of the contest process itself. As a plugin author you may need to assist in orderly shutdown if possible. There are two things that can happen to your test step plugin: -* A **cancellation** may come in (`ctx.Done()`). This means the job is cancelled or failed entirely and nothing can be done to save it. Plugins SHOULD immediately cease all actions and return. Plugins MUST return within roughly 30s. Plugins do not have to deal with targets/DUTs, you don’t need to put them into any channels or similar - the job is dead. Return `xcontext.ErrCancelled` -* A **pause request** may come in. This means the contest server wants to restart. Not all plugins can support this easily, you can choose to ignore the pause request and continue as normal, however we want to minimize or completely get rid of these cases in the future. Plugin can either ignore the signal or react to it by serializing the state and returning it as `json.RawMessage` together with `xcontext.ErrPaused`. If you do this, the framework will call Run again after the server has restarted and give your json back in `resumeState`. Note targets will not be re-injected, you need to remember them. However, new targets can still arrive after the resumption. You don’t need to remember or care about targets that you already returned with pass/fail, the framework knows and will send them to the following step if required. +* A **cancellation** may come in (`ctx.Done()`). This means the job is cancelled or failed entirely and nothing can be done to save it. Plugins SHOULD immediately cease all actions and return. Plugins MUST return within roughly 30s. Plugins do not have to deal with targets/DUTs, you don’t need to put them into any channels or similar - the job is dead. Return `context.Canceled` +* A **pause request** may come in. This means the contest server wants to restart. Not all plugins can support this easily, you can choose to ignore the pause request and continue as normal, however we want to minimize or completely get rid of these cases in the future. Plugin can either ignore the signal or react to it by serializing the state and returning it as `json.RawMessage` together with `signals.Paused`. If you do this, the framework will call Run again after the server has restarted and give your json back in `resumeState`. Note targets will not be re-injected, you need to remember them. However, new targets can still arrive after the resumption. You don’t need to remember or care about targets that you already returned with pass/fail, the framework knows and will send them to the following step if required. Further details on the semantics of Pause. @@ -102,9 +102,9 @@ Further details on the semantics of Pause. * An example of a good case for implementing pause: a plugin that launches an external job and wait for it to complete, polling for its status. In this case, upon receiving pause, it should serialize all the targets in flight at the moment along with job tokens, return them, and continue waiting in the next instance with the same targets and tokens. * When pausing, ConTest will close the plugin’s input channel signaling that no more targets will be coming during lifetime of this Step object. This is done in addition to asserting the pause signal so the simplest plugins do not need to handle it separately. (Note: more targets can come in after resumption) * Paused plugin retains responsibility for the targets in flight at the time of pausing, i.e. ones that were injected but for which no result was received yet. -* Successful pause is communicated by returning `ErrPaused` from the Run method. If the plugin was responsible for any targets at the time, any other return value (including `nil`) will be considered a failure to pause and will abort the job. +* Successful pause is communicated by returning `signals.Paused` from the Run method. If the plugin was responsible for any targets at the time, any other return value (including `nil`) will be considered a failure to pause and will abort the job. * Cancellation will follow pause if timeout is about to expire, so both conditions may be asserted on a context, keep that in mind when testing for them. -* When there are no targets in flight and pause is requested, returning `ErrPaused` is allowed (for simplicity). It may be accompanied by `nil` . In general, return value of a plugin not responsible for any targets does not matter. +* When there are no targets in flight and pause is requested, returning `signals.Paused` is allowed (for simplicity). It may be accompanied by `nil` . In general, return value of a plugin not responsible for any targets does not matter. * When successfully paused, a new instance of the plugin may be resumed with the state returned but it is not a guarantee: another step may have failed to pause correctly in which case entire job would have been aborted and steps that did pause correctly will not be revived. * On resumption, targets the plugin was responsible for will not be reinjected but plugin is still expected to produce results for them. Therefore, state returned by the plugin must include everything necessary for the new instance to produce results for targets that had been injected into the previous instance. * Cancel signal may be asserted together with pause, in which case cancellation takes precedence. If both pause and cancel are asserted, there is no need to perform pause-related activities anymore. diff --git a/cmds/admin_server/job/rdb/rdb.go b/cmds/admin_server/job/rdb/rdb.go index 330ee702..9b99260c 100644 --- a/cmds/admin_server/job/rdb/rdb.go +++ b/cmds/admin_server/job/rdb/rdb.go @@ -1,11 +1,12 @@ package rdb import ( + "context" "fmt" "github.com/google/go-safeweb/safesql" adminServerJob "github.com/linuxboot/contest/cmds/admin_server/job" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/pkg/logging" ) var ( @@ -39,7 +40,7 @@ func New(dbURI, driveName string) (*Storage, error) { } // GetTags returns tags that has a tag matches tagPattern -func (r *Storage) GetTags(ctx xcontext.Context, tagPattern string) ([]adminServerJob.Tag, error) { +func (r *Storage) GetTags(ctx context.Context, tagPattern string) ([]adminServerJob.Tag, error) { var resultErr error res := []adminServerJob.Tag{} doneChan := make(chan struct{}) @@ -57,7 +58,7 @@ func (r *Storage) GetTags(ctx xcontext.Context, tagPattern string) ([]adminServe defer func() { err = rows.Close() if err != nil { - ctx.Errorf("error while closing the rows reader: %w", err) + logging.Errorf(ctx, "error while closing the rows reader: %w", err) } }() @@ -87,7 +88,7 @@ func (r *Storage) GetTags(ctx xcontext.Context, tagPattern string) ([]adminServe } // GetJobs returns jobs with final report if exists that are under a given tagName -func (r *Storage) GetJobs(ctx xcontext.Context, tagName string) ([]adminServerJob.Job, error) { +func (r *Storage) GetJobs(ctx context.Context, tagName string) ([]adminServerJob.Job, error) { var resultErr error res := []adminServerJob.Job{} doneChan := make(chan struct{}) @@ -105,7 +106,7 @@ func (r *Storage) GetJobs(ctx xcontext.Context, tagName string) ([]adminServerJo defer func() { err = rows.Close() if err != nil { - ctx.Errorf("error while closing the rows reader: %w", err) + logging.Errorf(ctx, "error while closing the rows reader: %w", err) } }() diff --git a/cmds/admin_server/job/storage.go b/cmds/admin_server/job/storage.go index ee7ed8f8..cb4c3c32 100644 --- a/cmds/admin_server/job/storage.go +++ b/cmds/admin_server/job/storage.go @@ -1,16 +1,16 @@ package job import ( + "context" "time" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // DB wraps a job database type Storage interface { - GetTags(ctx xcontext.Context, tagPattern string) ([]Tag, error) - GetJobs(ctx xcontext.Context, projectName string) ([]Job, error) + GetTags(ctx context.Context, tagPattern string) ([]Tag, error) + GetJobs(ctx context.Context, projectName string) ([]Job, error) } // Tag contains metadata about jobs under a given tag diff --git a/cmds/admin_server/main.go b/cmds/admin_server/main.go index 1e8f0918..953bf204 100644 --- a/cmds/admin_server/main.go +++ b/cmds/admin_server/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "crypto/tls" "flag" "fmt" @@ -15,9 +16,8 @@ import ( "github.com/linuxboot/contest/cmds/admin_server/server" mongoStorage "github.com/linuxboot/contest/cmds/admin_server/storage/mongo" "github.com/linuxboot/contest/pkg/logging" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/tool/logger" ) var ( @@ -27,7 +27,7 @@ var ( flagContestDBURI *string flagTLSCert *string flagTLSKey *string - flagLogLevel *string + logLevel = logger.LevelDebug ) func initFlags(cmd string) { @@ -37,7 +37,7 @@ func initFlags(cmd string) { flagContestDBURI = flagSet.String("contestdbURI", "contest:contest@tcp(localhost:3306)/contest_integ?parseTime=true", "Contest Database URI") flagTLSCert = flagSet.String("tlsCert", "", "Path to the tls cert file") flagTLSKey = flagSet.String("tlsKey", "", "Path to the tls key file") - flagLogLevel = flagSet.String("logLevel", "debug", "A log level, possible values: debug, info, warning, error, panic, fatal") + flagSet.Var(&logLevel, "logLevel", "A log level, possible values: debug, info, warning, error, panic, fatal") } @@ -58,27 +58,21 @@ func main() { exitWithError(err, 1) } - logLevel, err := logger.ParseLogLevel(*flagLogLevel) - if err != nil { - exitWithError(err, 1) - } + ctx := logging.WithBelt(context.Background(), logLevel) - ctx, cancel := logrusctx.NewContext(logLevel, logging.DefaultOptions()...) - defer cancel() - - storageCtx, cancel := xcontext.WithTimeout(ctx, 10*time.Second) - defer cancel() + storageCtx, storageCtxCancel := context.WithTimeout(ctx, 10*time.Second) + defer storageCtxCancel() storage, err := mongoStorage.NewMongoStorage(storageCtx, *flagDBURI) if err != nil { exitWithError(err, 1) } - closeCtx, cancel := xcontext.WithTimeout(xcontext.Background(), 10*time.Second) + closeCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() defer storage.Close(closeCtx) var jobStorage *rdb.Storage - ctx.Debugf("init contest db connection %v \n", *flagContestDBURI) + logging.Debugf(ctx, "init contest db connection %v \n", *flagContestDBURI) jobStorage, err = rdb.New(*flagContestDBURI, "mysql") if err != nil { exitWithError(err, 1) diff --git a/cmds/admin_server/server/server.go b/cmds/admin_server/server/server.go index 648a7426..7ddeba3f 100644 --- a/cmds/admin_server/server/server.go +++ b/cmds/admin_server/server/server.go @@ -1,6 +1,7 @@ package server import ( + "context" "crypto/tls" "errors" "fmt" @@ -12,9 +13,10 @@ import ( adminServerJob "github.com/linuxboot/contest/cmds/admin_server/job" "github.com/linuxboot/contest/cmds/admin_server/storage" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/tool/logger" ) var ( @@ -174,9 +176,9 @@ func (r *RouteHandler) addLogs(c *gin.Context) { storageLogs = append(storageLogs, log.ToStorageLog()) } - ctx, cancel := xcontext.WithTimeout(xcontext.Background(), DefaultDBAccessTimeout) + ctx, cancel := context.WithTimeout(context.Background(), DefaultDBAccessTimeout) defer cancel() - ctx = ctx.WithLogger(r.log) + ctx = logger.CtxWithLogger(ctx, r.log) err := r.storage.StoreLogs(ctx, storageLogs) if err != nil { r.log.Errorf("Err while storing logs: %v", err) @@ -203,9 +205,9 @@ func (r *RouteHandler) getLogs(c *gin.Context) { return } - ctx, cancel := xcontext.WithTimeout(xcontext.Background(), DefaultDBAccessTimeout) + ctx, cancel := context.WithTimeout(context.Background(), DefaultDBAccessTimeout) defer cancel() - ctx = ctx.WithLogger(r.log) + ctx = logger.CtxWithLogger(ctx, r.log) result, err := r.storage.GetLogs(ctx, query.ToStorageQuery()) if err != nil { c.JSON(http.StatusInternalServerError, makeRestErr("error while getting the logs")) @@ -227,9 +229,9 @@ func (r *RouteHandler) getTags(c *gin.Context) { return } - ctx, cancel := xcontext.WithTimeout(xcontext.Background(), DefaultDBAccessTimeout) + ctx, cancel := context.WithTimeout(context.Background(), DefaultDBAccessTimeout) defer cancel() - ctx = ctx.WithLogger(r.log) + ctx = logger.CtxWithLogger(ctx, r.log) res, err := r.jobStorage.GetTags(ctx, query.Text) if err != nil { c.JSON(http.StatusInternalServerError, makeRestErr("error while getting the projects")) @@ -247,9 +249,9 @@ func (r *RouteHandler) getJobs(c *gin.Context) { return } - ctx, cancel := xcontext.WithTimeout(xcontext.Background(), DefaultDBAccessTimeout) + ctx, cancel := context.WithTimeout(context.Background(), DefaultDBAccessTimeout) defer cancel() - ctx = ctx.WithLogger(r.log) + ctx = logger.CtxWithLogger(ctx, r.log) res, err := r.jobStorage.GetJobs(ctx, projectName) if err != nil { c.JSON(http.StatusInternalServerError, makeRestErr("error while getting the jobs")) @@ -263,7 +265,7 @@ func makeRestErr(format string, args ...any) gin.H { return gin.H{"status": "err", "msg": fmt.Sprintf(format, args...)} } -func initRouter(ctx xcontext.Context, rh RouteHandler, middlewares []gin.HandlerFunc) *gin.Engine { +func initRouter(ctx context.Context, rh RouteHandler, middlewares []gin.HandlerFunc) *gin.Engine { r := gin.New() r.Use(gin.Logger()) @@ -292,11 +294,11 @@ func initRouter(ctx xcontext.Context, rh RouteHandler, middlewares []gin.Handler return r } -func Serve(ctx xcontext.Context, port int, storage storage.Storage, jobStorage adminServerJob.Storage, middlewares []gin.HandlerFunc, tlsConfig *tls.Config) error { +func Serve(ctx context.Context, port int, storage storage.Storage, jobStorage adminServerJob.Storage, middlewares []gin.HandlerFunc, tlsConfig *tls.Config) error { routeHandler := RouteHandler{ storage: storage, jobStorage: jobStorage, - log: ctx.Logger(), + log: logger.FromCtx(ctx), } router := initRouter(ctx, routeHandler, middlewares) server := &http.Server{ @@ -308,9 +310,9 @@ func Serve(ctx xcontext.Context, port int, storage storage.Storage, jobStorage a go func() { <-ctx.Done() // on cancel close the server - ctx.Debugf("Closing the server") + logging.Debugf(ctx, "Closing the server") if err := server.Close(); err != nil { - ctx.Errorf("Error closing the server: %v", err) + logging.Errorf(ctx, "Error closing the server: %v", err) } }() diff --git a/cmds/admin_server/storage/mongo/mongo.go b/cmds/admin_server/storage/mongo/mongo.go index 4a72692d..02c6624e 100644 --- a/cmds/admin_server/storage/mongo/mongo.go +++ b/cmds/admin_server/storage/mongo/mongo.go @@ -7,7 +7,8 @@ import ( "time" "github.com/linuxboot/contest/cmds/admin_server/storage" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/pkg/logging" + "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -27,7 +28,7 @@ type MongoStorage struct { collection *mongo.Collection } -func NewMongoStorage(ctx xcontext.Context, uri string) (*MongoStorage, error) { +func NewMongoStorage(ctx context.Context, uri string) (*MongoStorage, error) { client, err := mongo.NewClient(options.Client().ApplyURI(uri)) if err != nil { return nil, err @@ -106,25 +107,25 @@ func toMongoQuery(query storage.Query) bson.D { return q } -func (s *MongoStorage) StoreLogs(ctx xcontext.Context, logs []storage.Log) error { +func (s *MongoStorage) StoreLogs(ctx context.Context, logs []storage.Log) error { var mongoLogs []interface{} for _, log := range logs { mongoLogs = append(mongoLogs, toMongoLog(&log)) } _, err := s.collection.InsertMany(ctx, mongoLogs) if err != nil { - ctx.Errorf("Error while inserting a batch of logs: %v", err) + logging.Errorf(ctx, "Error while inserting a batch of logs: %v", err) return storage.ErrInsert } return nil } -func (s *MongoStorage) GetLogs(ctx xcontext.Context, query storage.Query) (*storage.Result, error) { +func (s *MongoStorage) GetLogs(ctx context.Context, query storage.Query) (*storage.Result, error) { q := toMongoQuery(query) //get the count of the logs count, err := s.collection.CountDocuments(ctx, q) if err != nil { - ctx.Errorf("Error while performing count query: %v", err) + logging.Errorf(ctx, "Error while performing count query: %v", err) return nil, storage.ErrQuery } @@ -134,14 +135,14 @@ func (s *MongoStorage) GetLogs(ctx xcontext.Context, query storage.Query) (*stor cur, err := s.collection.Find(ctx, q, opts) if err != nil { - ctx.Errorf("Error while querying logs from db: %v", err) + logging.Errorf(ctx, "Error while querying logs from db: %v", err) return nil, storage.ErrQuery } var logs []Log err = cur.All(ctx, &logs) if err != nil { - ctx.Errorf("Error while reading query result from db: %v", err) + logging.Errorf(ctx, "Error while reading query result from db: %v", err) return nil, storage.ErrQuery } // convert to storage logs @@ -158,7 +159,7 @@ func (s *MongoStorage) GetLogs(ctx xcontext.Context, query storage.Query) (*stor }, nil } -func (s *MongoStorage) Close(ctx xcontext.Context) error { +func (s *MongoStorage) Close(ctx context.Context) error { return s.dbClient.Disconnect(ctx) } diff --git a/cmds/admin_server/storage/storage.go b/cmds/admin_server/storage/storage.go index 43a0daa2..2bc3f2dc 100644 --- a/cmds/admin_server/storage/storage.go +++ b/cmds/admin_server/storage/storage.go @@ -1,10 +1,9 @@ package storage import ( + "context" "errors" "time" - - "github.com/linuxboot/contest/pkg/xcontext" ) var ( @@ -19,8 +18,8 @@ var ( ) type Storage interface { - StoreLogs(ctx xcontext.Context, logs []Log) error - GetLogs(ctx xcontext.Context, query Query) (*Result, error) + StoreLogs(ctx context.Context, logs []Log) error + GetLogs(ctx context.Context, query Query) (*Result, error) } // Log defines the basic log info pushed by the server @@ -42,7 +41,7 @@ type Query struct { Page uint } -//Result defines the expected result returned from the db +// Result defines the expected result returned from the db type Result struct { Logs []Log Count uint64 diff --git a/cmds/contest/server/server.go b/cmds/contest/server/server.go index 72848001..3196c57f 100644 --- a/cmds/contest/server/server.go +++ b/cmds/contest/server/server.go @@ -6,6 +6,7 @@ package server import ( + "context" "flag" "fmt" "os" @@ -22,15 +23,16 @@ import ( "github.com/linuxboot/contest/pkg/loggerhook" "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/pluginregistry" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/userfunctions/donothing" "github.com/linuxboot/contest/pkg/userfunctions/ocp" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/tool/experimental/errmon" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/plugins/storage/memory" "github.com/linuxboot/contest/plugins/storage/rdbms" "github.com/linuxboot/contest/plugins/targetlocker/dblocker" @@ -48,7 +50,6 @@ var ( flagProcessTimeout *time.Duration flagTargetLocker *string flagInstanceTag *string - flagLogLevel *string flagPauseTimeout *time.Duration flagResumeJobs *bool flagTargetLockDuration *time.Duration @@ -59,6 +60,7 @@ var ( flagHttpLoggerMaxBatchCount *int flagHttpLoggerBatchSendFreq *time.Duration flagHttpLoggerTimeout *time.Duration + logLevel = logger.LevelDebug ) func initFlags(cmd string) { @@ -75,7 +77,7 @@ func initFlags(cmd string) { flagProcessTimeout = flagSet.Duration("processTimeout", api.DefaultEventTimeout, "API request processing timeout") flagTargetLocker = flagSet.String("targetLocker", "auto", "Target locker implementation to use, \"auto\" follows DBURI setting") flagInstanceTag = flagSet.String("instanceTag", "", "A tag for this instance. Server will only operate on jobs with this tag and will add this tag to the jobs it creates.") - flagLogLevel = flagSet.String("logLevel", "debug", "A log level, possible values: debug, info, warning, error, panic, fatal") + flagSet.Var(&logLevel, "logLevel", "A log level, possible values: debug, info, warning, error, panic, fatal") flagPauseTimeout = flagSet.Duration("pauseTimeout", 0, "SIGINT/SIGTERM shutdown timeout (seconds), after which pause will be escalated to cancellaton; -1 - no escalation, 0 - do not pause, cancel immediately") flagResumeJobs = flagSet.Bool("resumeJobs", false, "Attempt to resume paused jobs") flagTargetLockDuration = flagSet.Duration("targetLockDuration", config.DefaultTargetLockDuration, @@ -156,32 +158,28 @@ func Main(pluginConfig *PluginConfig, cmd string, args []string, sigs <-chan os. return err } - logLevel, err := logger.ParseLogLevel(*flagLogLevel) - if err != nil { - return err - } - clk := clock.New() - logrusOpts := logging.DefaultOptions() + ctx, cancel := context.WithCancel(context.Background()) + ctx = logging.WithBelt(ctx, logLevel) if *flagAdminServerAddr != "" { - logrusOpts = append( - logrusOpts, - bundles.OptionHttpLoggerConfig(loggerhook.Config{ - Addr: *flagAdminServerAddr, - BufferSize: *flagHttpLoggerBufferSize, - MaxBatchSize: *flagHttpLoggerMaxBatchSize, - MaxBatchCount: *flagHttpLoggerMaxBatchCount, - BatchSendFreq: *flagHttpLoggerBatchSendFreq, - LogTimeout: *flagHttpLoggerTimeout, - }), - ) + httpHook, err := loggerhook.NewHttpHook(loggerhook.Config{ + Addr: *flagAdminServerAddr, + BufferSize: *flagHttpLoggerBufferSize, + MaxBatchSize: *flagHttpLoggerMaxBatchSize, + MaxBatchCount: *flagHttpLoggerMaxBatchCount, + BatchSendFreq: *flagHttpLoggerBatchSendFreq, + LogTimeout: *flagHttpLoggerTimeout, + }) + errmon.ObserveErrorCtx(ctx, err) + if httpHook != nil { + ctx = logger.CtxWithLogger(ctx, logger.FromCtx(ctx).WithHooks(httpHook)) + } } - ctx, cancel := logrusctx.NewContext(logLevel, logrusOpts...) - ctx, pause := xcontext.WithNotify(ctx, xcontext.ErrPaused) - log := ctx.Logger() + ctx, pause := signaling.WithSignal(ctx, signals.Paused) + log := logger.FromCtx(ctx) defer cancel() // Let's store storage engine in context diff --git a/cmds/exec_agent/verbs.go b/cmds/exec_agent/verbs.go index 3c5d8758..7e0cc8dd 100644 --- a/cmds/exec_agent/verbs.go +++ b/cmds/exec_agent/verbs.go @@ -6,6 +6,7 @@ package main import ( + "context" "errors" "fmt" "log" @@ -17,7 +18,6 @@ import ( "syscall" "github.com/linuxboot/contest/pkg/remote" - "github.com/linuxboot/contest/pkg/xcontext" ) func run() error { @@ -69,11 +69,11 @@ func run() error { } func start(bin string, args []string) error { - ctx := xcontext.Background() + ctx := context.Background() if flagTimeQuota != nil && *flagTimeQuota != 0 { - var cancel xcontext.CancelFunc - ctx, cancel = xcontext.WithTimeout(ctx, *flagTimeQuota) + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, *flagTimeQuota) defer cancel() } diff --git a/db/rdbms/migration/0002_migrate_descriptor_to_extended_descriptor.go b/db/rdbms/migration/0002_migrate_descriptor_to_extended_descriptor.go index ed014a68..652bf5c9 100644 --- a/db/rdbms/migration/0002_migrate_descriptor_to_extended_descriptor.go +++ b/db/rdbms/migration/0002_migrate_descriptor_to_extended_descriptor.go @@ -6,6 +6,7 @@ package migration import ( + "context" "database/sql" "encoding/json" "fmt" @@ -13,13 +14,15 @@ import ( "sync" "time" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" "github.com/linuxboot/contest/pkg/userfunctions/donothing" "github.com/linuxboot/contest/pkg/userfunctions/ocp" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/reporters/noop" "github.com/linuxboot/contest/plugins/reporters/targetsuccess" "github.com/linuxboot/contest/plugins/targetmanagers/csvtargetmanager" @@ -85,17 +88,18 @@ type Request struct { // actually submitted at test time. // Schema v0002 introduces the concept of extended_descriptor, which is defined as follows: -// type ExtendedDescriptor struct { -// JobDescriptor -// TestStepsDescriptors []test.TestStepsDescriptors -// } +// +// type ExtendedDescriptor struct { +// JobDescriptor +// TestStepsDescriptors []test.TestStepsDescriptors +// } // // We remove TestDescriptors from Request objects, and we store that information side-by-side with // JobDescriptor into an ExtendedDescriptor. We then store this ExtendedDescriptor in the jobs table // so that all the test information can be re-fetched by reading extended_descriptor field in // jobs table, without any dependency after submission time on the test fetcher. type DescriptorMigration struct { - Context xcontext.Context + Context context.Context } type dbConn interface { @@ -114,7 +118,7 @@ func ms(d time.Duration) float64 { // fetchJobs fetches job requests based on limit and offset func (m *DescriptorMigration) fetchJobs(db dbConn, limit, offset uint64) ([]Request, error) { - log := m.Context.Logger() + log := logger.FromCtx(m.Context) log.Debugf("fetching shard limit: %d, offset: %d", limit, offset) selectStatement := "select job_id, name, requestor, server_id, request_time, descriptor, teststeps from jobs limit ? offset ?" @@ -174,7 +178,7 @@ func (m *DescriptorMigration) fetchJobs(db dbConn, limit, offset uint64) ([]Requ } func (m *DescriptorMigration) migrateJobs(db dbConn, requests []Request, registry *pluginregistry.PluginRegistry) error { - log := m.Context.Logger() + log := logger.FromCtx(m.Context) log.Debugf("migrating %d jobs", len(requests)) start := time.Now() @@ -360,7 +364,7 @@ func (m *DescriptorMigration) up(db dbConn) error { count := uint64(0) ctx := m.Context - ctx.Debugf("counting the number of jobs to migrate") + logging.Debugf(ctx, "counting the number of jobs to migrate") start := time.Now() rows, err := db.Query("select count(*) from jobs") if err != nil { @@ -377,17 +381,17 @@ func (m *DescriptorMigration) up(db dbConn) error { return fmt.Errorf("could not fetch number of records to migrate: %w", err) } if err := rows.Close(); err != nil { - ctx.Warnf("could not close rows after count(*) query") + logging.Warnf(ctx, "could not close rows after count(*) query") } // Create a new plugin registry. This is necessary because some information that need to be // associated with the extended_descriptor is not available in the db and can only be looked // up via the TestFetcher. registry := pluginregistry.NewPluginRegistry(ctx) - initPlugins(registry, ctx.Logger()) + initPlugins(registry, logger.FromCtx(ctx)) elapsed := time.Since(start) - ctx.Debugf("total number of jobs to migrate: %d, fetched in %.3f ms", count, ms(elapsed)) + logging.Debugf(ctx, "total number of jobs to migrate: %d, fetched in %.3f ms", count, ms(elapsed)) for offset := uint64(0); offset < count; offset += shardSize { jobs, err := m.fetchJobs(db, shardSize, offset) if err != nil { @@ -397,13 +401,13 @@ func (m *DescriptorMigration) up(db dbConn) error { if err != nil { return fmt.Errorf("could not migrate events in range offset %d limit %d: %w", offset, shardSize, err) } - ctx.Infof("migrated %d/%d", offset, count) + logging.Infof(ctx, "migrated %d/%d", offset, count) } return nil } // NewDescriptorMigration is the factory for DescriptorMigration -func NewDescriptorMigration(ctx xcontext.Context) migrate.Migrate { +func NewDescriptorMigration(ctx context.Context) migrate.Migrate { return &DescriptorMigration{ Context: ctx, } @@ -446,7 +450,7 @@ var userFunctions = []map[string]interface{}{ var testInitOnce sync.Once // Init initializes the plugin registry -func initPlugins(pluginRegistry *pluginregistry.PluginRegistry, log xcontext.Logger) { +func initPlugins(pluginRegistry *pluginregistry.PluginRegistry, log logger.Logger) { // Register TargetManager plugins for _, tmloader := range TargetManagers { diff --git a/go.mod b/go.mod index 2ceb208d..e6daa044 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,7 @@ go 1.18 require ( github.com/aws/aws-sdk-go v1.41.14 github.com/benbjohnson/clock v1.1.0 - github.com/chappjc/logrus-prefix v0.0.0-20180227015900-3a1d64819adb - github.com/gin-gonic/gin v1.8.1 + github.com/gin-gonic/gin v1.9.0 github.com/go-sql-driver/mysql v1.6.0 github.com/google/go-safeweb v0.0.0-20211026121254-697f59a9d57f github.com/google/goexpect v0.0.0-20200703111054-623d5ca06f56 @@ -16,40 +15,43 @@ require ( github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/pkg/sftp v1.13.4 github.com/pressly/goose v2.7.0+incompatible - github.com/prometheus/client_golang v1.12.2 - github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.35.0 - github.com/sirupsen/logrus v1.8.1 + github.com/sirupsen/logrus v1.9.2 github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.3 github.com/u-root/cpu v0.0.0-20210922222005-0a371c3a086d github.com/u-root/u-root v7.0.0+incompatible - github.com/xaionaro-go/metrics v0.0.0-20210425194006-68050b337673 - github.com/xaionaro-go/statuspage v0.0.0-20220629202611-97b44b308599 - github.com/xaionaro-go/unsafetools v0.0.0-20210722164218-75ba48cf7b3c go.mongodb.org/mongo-driver v1.9.1 - go.uber.org/atomic v1.9.0 - go.uber.org/zap v1.19.1 - golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d - golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc + golang.org/x/crypto v0.5.0 + golang.org/x/exp v0.0.0-20230519143937-03e91628a987 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/OneOfOne/xxhash v1.2.8 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/DataDog/gostackparse v0.6.0 // indirect + github.com/bytedance/sonic v1.8.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/go-ng/slices v0.0.0-20220616195238-b8d239c57d65 // indirect + github.com/go-ng/sort v0.0.0-20220617173827-2cc7cd04f7c7 // indirect + github.com/go-ng/xsort v0.0.0-20220617174223-1d146907bccc // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.7.0 // indirect +) + +require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/demdxx/gocast v1.2.0 // indirect - github.com/fatih/structs v1.1.0 // indirect + github.com/facebookincubator/go-belt v0.0.0-20230519225445-7590c998d440 github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.11.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.11.2 // indirect github.com/go-stack/stack v1.8.0 // indirect - github.com/goccy/go-json v0.9.8 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/goccy/go-json v0.10.0 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f // indirect github.com/hugelgupf/p9 v0.1.0 // indirect @@ -59,35 +61,19 @@ require ( github.com/klauspost/compress v1.13.6 // indirect github.com/kr/fs v0.1.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect - github.com/mattn/go-colorable v0.1.11 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/onsi/ginkgo v1.12.0 // indirect - github.com/onsi/gomega v1.9.0 // indirect - github.com/pelletier/go-toml/v2 v2.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/term v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - github.com/stretchr/objx v0.4.0 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect - github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect - github.com/xaionaro-go/atomicmap v0.0.0-20210620215405-96a7f1f95a70 // indirect - github.com/xaionaro-go/spinlock v0.0.0-20200518175509-30e6d1ce68a1 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/ugorji/go/codec v1.2.9 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.0.2 // indirect github.com/xdg-go/stringprep v1.0.2 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - go.uber.org/multierr v1.7.0 // indirect - golang.org/x/net v0.1.0 // indirect - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.1.0 // indirect - golang.org/x/term v0.1.0 // indirect - golang.org/x/text v0.4.0 // indirect - golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect google.golang.org/grpc v1.31.0 // indirect - google.golang.org/protobuf v1.28.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/go.sum b/go.sum index 123c85d8..1c951392 100644 --- a/go.sum +++ b/go.sum @@ -1,158 +1,72 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.7/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= -github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/DataDog/gostackparse v0.6.0 h1:egCGQviIabPwsyoWpGvIBGrEnNWez35aEO7OJ1vBI4o= +github.com/DataDog/gostackparse v0.6.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/aws/aws-sdk-go v1.41.14 h1:zJnJ8Y964DjyRE55UVoMKgOG4w5i88LpN6xSpBX7z84= github.com/aws/aws-sdk-go v1.41.14/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chappjc/logrus-prefix v0.0.0-20180227015900-3a1d64819adb h1:aZTKxMminKeQWHtzJBbV8TttfTxzdJ+7iEJFE6FmUzg= -github.com/chappjc/logrus-prefix v0.0.0-20180227015900-3a1d64819adb/go.mod h1:xzXc1S/L+64uglB3pw54o8kqyM6KFYpTeC9Q6+qZIu8= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cornelk/hashmap v1.0.1/go.mod h1:8wbysTUDnwJGrPZ1Iwsou3m+An6sldFrJItjRhfegCw= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dchest/siphash v1.1.0/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= -github.com/demdxx/gocast v1.2.0 h1:Z9zVpAjyTWJIJwFFynnOoP30yxot4Y2QafNPSD+VEEo= -github.com/demdxx/gocast v1.2.0/go.mod h1:RTyqNS6BdIq/19jJX96PlVhfqG31tldKMnpVJnPa3pw= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/facebookincubator/go-belt v0.0.0-20230519225445-7590c998d440 h1:wLBr+/pwyzzmzwcfV2ZTTVRHoJ71cucOB2xVbfq6YjQ= +github.com/facebookincubator/go-belt v0.0.0-20230519225445-7590c998d440/go.mod h1:JBAZF82h/QDBLiwj2dhQrlhHh0ErRsW0xsIZXrNS5vg= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= -github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/gliderlabs/ssh v0.3.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw= -github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-ng/slices v0.0.0-20220616195238-b8d239c57d65 h1:Z0bSxwn4xHsF3+MmGqMvKYtMAFqsSMmW04/zpc4k1sk= +github.com/go-ng/slices v0.0.0-20220616195238-b8d239c57d65/go.mod h1:oRD4LxXsmqAI0X6Lj1vKWymfNKcCLZH5b18qyPZOTv4= +github.com/go-ng/sort v0.0.0-20220617173827-2cc7cd04f7c7 h1:Ng6QMSlQSB+goG6430/Fp7O4YO2BJZXZJaldtg+7kEc= +github.com/go-ng/sort v0.0.0-20220617173827-2cc7cd04f7c7/go.mod h1:QUXmOopthsqLYJ+rAybuCf16J7qQm60TLVdQR0w1Nus= +github.com/go-ng/xsort v0.0.0-20220617174223-1d146907bccc h1:VNz633GRJx2/hL0SpBNoNlLid4xtyi7LSJP1kHpD2Fo= +github.com/go-ng/xsort v0.0.0-20220617174223-1d146907bccc/go.mod h1:Pz/V4pxeXP0hjBlXIrm2ehR0GJ0l4Bon3fsOl6TmoJs= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.9.8 h1:DxXB6MLd6yyel7CLph8EwNIonUtVZd3Ue5iRcL4DQCE= -github.com/goccy/go-json v0.9.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-safeweb v0.0.0-20211026121254-697f59a9d57f h1:yA8MLwNYjLVI8VZn7MEfiKFBx1vuuZVPuc9fcwytiz8= @@ -162,30 +76,13 @@ github.com/google/goexpect v0.0.0-20200703111054-623d5ca06f56/go.mod h1:qtE5aAEk github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f h1:5CjVwnuUcp5adK4gmY6i72gpVFVnZDP2h5TmPScB6u4= github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/p9 v0.1.0 h1:oVoauPju1AEI22fmNEcIFKI4hsT9XlxG4OpQiEhqG+4= github.com/hugelgupf/p9 v0.1.0/go.mod h1:1rAW9NtDC5qvKmViRdQlPcDNtLcpo+yzOmQZqfVlS+U= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/termhook v0.0.0-20210329134026-a267c978e590 h1:Awh527xGLDUFsWXw1CWYQAll6I8NmhVrsFUjz6lry1Q= github.com/insomniacslk/termhook v0.0.0-20210329134026-a267c978e590/go.mod h1:8eGC3NZFqSFxpbWduqdoolXfuhN3K8KH9wMmldc3sYs= github.com/insomniacslk/xjson v0.0.0-20210106140854-1589ccfd1a1a h1:SnoF1lbXJyorSE5e8thJwM4OSsmhx2aEOSb+tsH3aho= @@ -194,68 +91,36 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o= github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= -github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= -github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.4 h1:Lb0RYJCmgUcBgZosfoi9Y9sbl6+LJgOIgk/2Y4YjMFg= @@ -266,82 +131,38 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pressly/goose v2.7.0+incompatible h1:PWejVEv07LCerQEzMMeAtjuyCKbyprZ/LBa6K5P0OCQ= github.com/pressly/goose v2.7.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.35.0 h1:Eyr+Pw2VymWejHqCugNaQXkAi6KayVNxaHeu6khmFBE= -github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace h1:9PNP1jnUjRhfmGMlkXHjYPishpcw4jpSt/V/xYY3FMA= github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/trafficstars/metrics v0.0.0-20200814135838-ec71779fd01d/go.mod h1:HHFbOLT4Kf5raCtxlL8s5cDvsJC9knlxD1EL2B8pjGw= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/u-root/cpu v0.0.0-20210922222005-0a371c3a086d h1:DitnLbNGHuPucOQkWi73clOG+wdPgNMgUpr3hBzBJJ0= github.com/u-root/cpu v0.0.0-20210922222005-0a371c3a086d/go.mod h1:1JzU+/YbK0tQ7WbufDMLA0iVbpIQNywhiCX/paytE4k= github.com/u-root/u-root v6.0.1-0.20200118052101-6bcd1cda5996+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= github.com/u-root/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066/go.mod h1:FSQhuTO7eHT34mPzX+B04SUAjiqLxtXs1et0S6l9k4k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= -github.com/xaionaro-go/atomicmap v0.0.0-20200307233044-c040bc137895/go.mod h1:WgfDl7x9++CVnKSu63ThFhBF3nvgj60Ft1nCgrOSgWM= -github.com/xaionaro-go/atomicmap v0.0.0-20210620215405-96a7f1f95a70 h1:z/+V+ai0R41aym9Hz6flJ90LuuuaHv2EfI7pNaYSPuw= -github.com/xaionaro-go/atomicmap v0.0.0-20210620215405-96a7f1f95a70/go.mod h1:WgfDl7x9++CVnKSu63ThFhBF3nvgj60Ft1nCgrOSgWM= -github.com/xaionaro-go/metrics v0.0.0-20210425194006-68050b337673 h1:JbI/0kqtrQ4etaxSxjuRmz02+tyKzb0TglwUCIyF1DI= -github.com/xaionaro-go/metrics v0.0.0-20210425194006-68050b337673/go.mod h1:mg+WWOABLgtBKT9UFqWxP+p+4C5Nj9ho1GicoVrhWsc= -github.com/xaionaro-go/spinlock v0.0.0-20190309154744-55278e21e817/go.mod h1:Nb/15eS0BMty6TMuWgRQM8WCDIUlyPZagcpchHT6c9Y= -github.com/xaionaro-go/spinlock v0.0.0-20200518175509-30e6d1ce68a1 h1:1Kqw9dv2LnznIhJoMt3dNzc/ctSj6VHjyGh4YZHjpE4= -github.com/xaionaro-go/spinlock v0.0.0-20200518175509-30e6d1ce68a1/go.mod h1:UwmTXX+EpoEYHuy0rSys1Rp5PW+eVTgZSjgMVLJENKg= -github.com/xaionaro-go/statuspage v0.0.0-20220629202611-97b44b308599 h1:KyVDoQ7L1THO5rEClxAb7m5oM/9IJo90ajufNx39rHQ= -github.com/xaionaro-go/statuspage v0.0.0-20220629202611-97b44b308599/go.mod h1:GJMJm6wjbnnzY6HGHivU/lIALdNynbzD9mIR75v0z08= -github.com/xaionaro-go/unsafetools v0.0.0-20210722164218-75ba48cf7b3c h1:WeiZrQbFImtlpYCHdxWpjm033Zm0n1ihx3bD/9b6rYI= -github.com/xaionaro-go/unsafetools v0.0.0-20210722164218-75ba48cf7b3c/go.mod h1:fnHPnf0CsRZNVxlSs0ZdUiYW49mLF5QFycfmoT+LuO4= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= @@ -350,367 +171,121 @@ github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyh github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.mongodb.org/mongo-driver v1.9.1 h1:m078y9v7sBItkt1aaoe2YlvWEXcD263e1a4E1fBrJ1c= go.mongodb.org/mongo-driver v1.9.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20230519143937-03e91628a987 h1:3xJIFvzUFbu4ls0BTBYcgbCGhA63eAOEMxIHugyXJqA= +golang.org/x/exp v0.0.0-20230519143937-03e91628a987/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190903213830-1f305c863dab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201026173827-119d4633e4d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200119215504-eb0d8dd85bcc/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200915201639-f4cefd1cb5ba/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/pkg/api/api.go b/pkg/api/api.go index cebccf2b..f336cdbf 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -6,15 +6,16 @@ package api import ( + "context" "errors" "fmt" "os" "time" + "github.com/facebookincubator/go-belt/beltctx" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/storage/limits" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // CurrentAPIVersion is the current version of the API that the clients must be @@ -162,12 +163,20 @@ func (a *API) SendReceiveEvent(ev *Event, timeout *time.Duration) (*EventRespons // operations via the API, e.g. getting the job status or stopping it. // This method should return an error if the job description is malformed or // invalid, and if the API version is incompatible. -func (a *API) Start(ctx xcontext.Context, requestor EventRequestor, jobDescriptor string) (Response, error) { +func (a *API) Start(ctx context.Context, requestor EventRequestor, jobDescriptor string) (Response, error) { resp := a.newResponse(ResponseTypeStart) + + // To allow jobs to finish we do not allow passing cancel and pause + // signals to the job's context. Therefore we use a fresh context + // (without any cancels and signalings) and just passthrough its + // observability belt. + // + // It also loose context values, but there are no any values + // we care about here. + ctx = beltctx.WithField(beltctx.WithBelt(context.Background(), beltctx.Belt(ctx)), "api_method", "start") + ev := &Event{ - // To allow jobs to finish we do not allow passing cancel and pause - // signals to the job's context (therefore: xcontext.WithResetSignalers). - Context: xcontext.WithResetSignalers(ctx).WithField("api_method", "start"), + Context: ctx, Type: EventTypeStart, ServerID: resp.ServerID, Msg: EventStartMsg{ @@ -188,10 +197,10 @@ func (a *API) Start(ctx xcontext.Context, requestor EventRequestor, jobDescripto } // Stop requests a job cancellation by the given job ID. -func (a *API) Stop(ctx xcontext.Context, requestor EventRequestor, jobID types.JobID) (Response, error) { +func (a *API) Stop(ctx context.Context, requestor EventRequestor, jobID types.JobID) (Response, error) { resp := a.newResponse(ResponseTypeStop) ev := &Event{ - Context: ctx.WithField("api_method", "stop"), + Context: beltctx.WithField(ctx, "api_method", "stop"), Type: EventTypeStop, ServerID: resp.ServerID, Msg: EventStopMsg{ @@ -210,11 +219,11 @@ func (a *API) Stop(ctx xcontext.Context, requestor EventRequestor, jobID types.J } // Status polls the status of a job by its ID, and returns a contest.Status -//object -func (a *API) Status(ctx xcontext.Context, requestor EventRequestor, jobID types.JobID) (Response, error) { +// object +func (a *API) Status(ctx context.Context, requestor EventRequestor, jobID types.JobID) (Response, error) { resp := a.newResponse(ResponseTypeStatus) ev := &Event{ - Context: ctx.WithField("api_method", "status"), + Context: beltctx.WithField(ctx, "api_method", "status"), Type: EventTypeStatus, ServerID: resp.ServerID, Msg: EventStatusMsg{ @@ -236,10 +245,10 @@ func (a *API) Status(ctx xcontext.Context, requestor EventRequestor, jobID types // Retry will retry a job identified by its ID, using the same job // description. If the job is still running, an error is returned. -func (a *API) Retry(ctx xcontext.Context, requestor EventRequestor, jobID types.JobID) (Response, error) { +func (a *API) Retry(ctx context.Context, requestor EventRequestor, jobID types.JobID) (Response, error) { resp := a.newResponse(ResponseTypeRetry) ev := &Event{ - Context: ctx.WithField("api_method", "retry"), + Context: beltctx.WithField(ctx, "api_method", "retry"), Type: EventTypeRetry, ServerID: resp.ServerID, Msg: EventRetryMsg{ @@ -263,10 +272,10 @@ func (a *API) Retry(ctx xcontext.Context, requestor EventRequestor, jobID types. } // List will list jobs matching the specified criteria. -func (a *API) List(ctx xcontext.Context, requestor EventRequestor, query *storage.JobQuery) (Response, error) { +func (a *API) List(ctx context.Context, requestor EventRequestor, query *storage.JobQuery) (Response, error) { resp := a.newResponse(ResponseTypeList) ev := &Event{ - Context: ctx.WithField("api_method", "list"), + Context: beltctx.WithField(ctx, "api_method", "list"), Type: EventTypeList, ServerID: resp.ServerID, Msg: EventListMsg{ diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index 1fc8f1f1..81b33d88 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -6,19 +6,19 @@ package api import ( + "context" "runtime" "testing" "time" "github.com/linuxboot/contest/pkg/job" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/tool/logger" "github.com/stretchr/testify/require" ) -var ctx, _ = logrusctx.NewContext(logger.LevelDebug) +var ctx = logger.CtxWithLogger(context.Background(), logger.Default()) func TestOptions(t *testing.T) { eventTimeout := 3141592654 * time.Second @@ -74,7 +74,7 @@ func TestEventTimeout(t *testing.T) { }, } - ctx, cancelFunc := xcontext.WithCancel(ctx) + ctx, cancelFunc := context.WithCancel(ctx) defer cancelFunc() go func() { for { diff --git a/pkg/api/event.go b/pkg/api/event.go index e08ba0f6..01564388 100644 --- a/pkg/api/event.go +++ b/pkg/api/event.go @@ -6,10 +6,11 @@ package api import ( + "context" + "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // EventType identifies an API event type. @@ -50,7 +51,7 @@ const ( // Event represents an event that the API can generate. This is used by the API // listener to enable event handling. type Event struct { - Context xcontext.Context + Context context.Context Type EventType ServerID string Err error diff --git a/pkg/api/listener.go b/pkg/api/listener.go index c89c79f1..309927ca 100644 --- a/pkg/api/listener.go +++ b/pkg/api/listener.go @@ -5,9 +5,7 @@ package api -import ( - "github.com/linuxboot/contest/pkg/xcontext" -) +import "context" // Listener defines the interface for an API listener. This is used to // implement different API transports, like thrift, or gRPC. @@ -17,5 +15,5 @@ type Listener interface { // The channel is used for cancellation, which can be called by the // JobManager and should be handled by the listener to do a graceful // shutdown. - Serve(xcontext.Context, *API) error + Serve(context.Context, *API) error } diff --git a/pkg/cerrors/cerrors.go b/pkg/cerrors/cerrors.go index 333a8527..b88622a7 100644 --- a/pkg/cerrors/cerrors.go +++ b/pkg/cerrors/cerrors.go @@ -19,7 +19,8 @@ func (e *ErrAlreadyDone) Error() string { } // ErrTestStepsNeverReturned indicates that one or multiple TestSteps -// did not complete when the test terminated or when the pipeline +// did not complete when the test terminated or when the pipeline +// // received a cancellation or pause signal type ErrTestStepsNeverReturned struct { StepNames []string diff --git a/pkg/event/frameworkevent/framework.go b/pkg/event/frameworkevent/framework.go index 55a2b795..e1fff2b8 100644 --- a/pkg/event/frameworkevent/framework.go +++ b/pkg/event/frameworkevent/framework.go @@ -6,6 +6,7 @@ package frameworkevent import ( + "context" "encoding/json" "fmt" "time" @@ -13,7 +14,6 @@ import ( "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/internal/querytools" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Event represents an event emitted by the framework @@ -98,12 +98,12 @@ func (value queryFieldEmittedEndTime) queryFieldPointer(query *Query) interface{ // Emitter defines the interface that emitter objects for framework vents must implement type Emitter interface { - Emit(ctx xcontext.Context, event Event) error + Emit(ctx context.Context, event Event) error } // Fetcher defines the interface that fetcher objects for framework events must implement type Fetcher interface { - Fetch(ctx xcontext.Context, fields ...QueryField) ([]Event, error) + Fetch(ctx context.Context, fields ...QueryField) ([]Event, error) } // EmitterFetcher defines the interface that objects supporting emitting and retrieving framework events must implement diff --git a/pkg/event/testevent/test.go b/pkg/event/testevent/test.go index dc642c03..6c960b8c 100644 --- a/pkg/event/testevent/test.go +++ b/pkg/event/testevent/test.go @@ -6,6 +6,7 @@ package testevent import ( + "context" "encoding/json" "fmt" "time" @@ -14,7 +15,6 @@ import ( "github.com/linuxboot/contest/pkg/event/internal/querytools" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Header models the header of a test event, which consists in metadata that defines the @@ -143,12 +143,12 @@ func (value queryFieldRunID) queryFieldPointer(query *Query) interface{} { retur // Emitter defines the interface that emitter objects must implement type Emitter interface { - Emit(ctx xcontext.Context, event Data) error + Emit(ctx context.Context, event Data) error } // Fetcher defines the interface that fetcher objects must implement type Fetcher interface { - Fetch(ctx xcontext.Context, fields ...QueryField) ([]Event, error) + Fetch(ctx context.Context, fields ...QueryField) ([]Event, error) } // EmitterFetcher defines the interface that objects supporting emitting and fetching events must implement diff --git a/pkg/job/reporting.go b/pkg/job/reporting.go index 33053739..62efe64d 100644 --- a/pkg/job/reporting.go +++ b/pkg/job/reporting.go @@ -7,12 +7,12 @@ package job import ( "bytes" + "context" "encoding/json" "time" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Reporting is the configuration section that determines how to report the @@ -49,8 +49,8 @@ type Reporter interface { Name() string - RunReport(ctx xcontext.Context, parameters interface{}, runStatus *RunStatus, ev testevent.Fetcher) (bool, interface{}, error) - FinalReport(ctx xcontext.Context, parameters interface{}, runStatuses []RunStatus, ev testevent.Fetcher) (bool, interface{}, error) + RunReport(ctx context.Context, parameters interface{}, runStatus *RunStatus, ev testevent.Fetcher) (bool, interface{}, error) + FinalReport(ctx context.Context, parameters interface{}, runStatuses []RunStatus, ev testevent.Fetcher) (bool, interface{}, error) } // ReporterBundle bundles the selected Reporter together with its parameters diff --git a/pkg/jobmanager/bundles.go b/pkg/jobmanager/bundles.go index 3f076088..d3965508 100644 --- a/pkg/jobmanager/bundles.go +++ b/pkg/jobmanager/bundles.go @@ -6,6 +6,7 @@ package jobmanager import ( + "context" "errors" "fmt" "strings" @@ -14,7 +15,6 @@ import ( "github.com/linuxboot/contest/pkg/pluginregistry" "github.com/linuxboot/contest/pkg/storage/limits" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // newReportingBundles returns the bundles for the run report and the final report @@ -57,7 +57,7 @@ func newReportingBundles(registry *pluginregistry.PluginRegistry, jobDescriptor } // newBundlesFromSteps creates bundles for the test -func newBundlesFromSteps(ctx xcontext.Context, descriptors []*test.TestStepDescriptor, registry *pluginregistry.PluginRegistry) ([]test.TestStepBundle, error) { +func newBundlesFromSteps(ctx context.Context, descriptors []*test.TestStepDescriptor, registry *pluginregistry.PluginRegistry) ([]test.TestStepBundle, error) { // look up test step plugins in the plugin registry var stepBundles []test.TestStepBundle diff --git a/pkg/jobmanager/job.go b/pkg/jobmanager/job.go index 61198d21..1f9007cb 100644 --- a/pkg/jobmanager/job.go +++ b/pkg/jobmanager/job.go @@ -6,6 +6,7 @@ package jobmanager import ( + "context" "encoding/json" "errors" "fmt" @@ -16,10 +17,9 @@ import ( "github.com/linuxboot/contest/pkg/pluginregistry" "github.com/linuxboot/contest/pkg/storage/limits" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) -func newJob(ctx xcontext.Context, registry *pluginregistry.PluginRegistry, jobDescriptor *job.Descriptor, resolver stepsResolver) (*job.Job, error) { +func newJob(ctx context.Context, registry *pluginregistry.PluginRegistry, jobDescriptor *job.Descriptor, resolver stepsResolver) (*job.Job, error) { if resolver == nil { return nil, fmt.Errorf("cannot create job without resolver") @@ -91,7 +91,7 @@ func newJob(ctx xcontext.Context, registry *pluginregistry.PluginRegistry, jobDe } func buildTestsFromDescriptors( - ctx xcontext.Context, + ctx context.Context, registry *pluginregistry.PluginRegistry, testDescriptors []*test.TestDescriptor, stepsDescriptors []test.TestStepsDescriptors) ([]*test.Test, error) { @@ -150,19 +150,19 @@ func buildTestsFromDescriptors( } // NewJobFromDescriptor creates a job object from a job descriptor -func NewJobFromDescriptor(ctx xcontext.Context, registry *pluginregistry.PluginRegistry, jobDescriptor *job.Descriptor) (*job.Job, error) { +func NewJobFromDescriptor(ctx context.Context, registry *pluginregistry.PluginRegistry, jobDescriptor *job.Descriptor) (*job.Job, error) { resolver := fetcherStepsResolver{jobDescriptor: jobDescriptor, registry: registry} return newJob(ctx, registry, jobDescriptor, resolver) } // NewJobFromExtendedDescriptor creates a job object from an extended job descriptor -func NewJobFromExtendedDescriptor(ctx xcontext.Context, registry *pluginregistry.PluginRegistry, jobDescriptor *job.ExtendedDescriptor) (*job.Job, error) { +func NewJobFromExtendedDescriptor(ctx context.Context, registry *pluginregistry.PluginRegistry, jobDescriptor *job.ExtendedDescriptor) (*job.Job, error) { resolver := literalStepsResolver{stepsDescriptors: jobDescriptor.TestStepsDescriptors} return newJob(ctx, registry, &jobDescriptor.Descriptor, resolver) } // NewJobFromJSONDescriptor builds a descriptor object from a JSON serialization -func NewJobFromJSONDescriptor(ctx xcontext.Context, registry *pluginregistry.PluginRegistry, jobDescriptorJSON string) (*job.Job, error) { +func NewJobFromJSONDescriptor(ctx context.Context, registry *pluginregistry.PluginRegistry, jobDescriptorJSON string) (*job.Job, error) { var jd *job.Descriptor if err := json.Unmarshal([]byte(jobDescriptorJSON), &jd); err != nil { return nil, err diff --git a/pkg/jobmanager/job_test.go b/pkg/jobmanager/job_test.go index 3b8490ff..f32b9d5d 100644 --- a/pkg/jobmanager/job_test.go +++ b/pkg/jobmanager/job_test.go @@ -1,12 +1,13 @@ package jobmanager import ( + "context" "testing" "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/pluginregistry" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/reporters/noop" "github.com/linuxboot/contest/plugins/targetmanagers/targetlist" "github.com/linuxboot/contest/plugins/testfetchers/literal" @@ -15,7 +16,7 @@ import ( ) func TestDisabledTestDescriptor(t *testing.T) { - pr := pluginregistry.NewPluginRegistry(xcontext.Background()) + pr := pluginregistry.NewPluginRegistry(context.Background()) require.NoError(t, pr.RegisterTestStep(echo.Load())) require.NoError(t, pr.RegisterTargetManager(targetlist.Load())) require.NoError(t, pr.RegisterTestFetcher(literal.Load())) @@ -82,7 +83,7 @@ func TestDisabledTestDescriptor(t *testing.T) { }, } - result, err := NewJobFromDescriptor(xcontext.Background(), pr, &jd) + result, err := NewJobFromDescriptor(context.Background(), pr, &jd) require.NoError(t, err) require.NotNil(t, result) @@ -91,7 +92,7 @@ func TestDisabledTestDescriptor(t *testing.T) { } func TestNewJobNoTests(t *testing.T) { - pr := pluginregistry.NewPluginRegistry(xcontext.Background()) + pr := pluginregistry.NewPluginRegistry(context.Background()) // require.NoError(t, pr.RegisterTestStep(echo.Load())) require.NoError(t, pr.RegisterTargetManager(targetlist.Load())) require.NoError(t, pr.RegisterTestFetcher(literal.Load())) @@ -108,12 +109,12 @@ func TestNewJobNoTests(t *testing.T) { }, } - _, err := NewJobFromDescriptor(xcontext.Background(), pr, &jd) + _, err := NewJobFromDescriptor(context.Background(), pr, &jd) require.Error(t, err) } func TestNewJobNoTestSteps(t *testing.T) { - pr := pluginregistry.NewPluginRegistry(xcontext.Background()) + pr := pluginregistry.NewPluginRegistry(context.Background()) // require.NoError(t, pr.RegisterTestStep(echo.Load())) require.NoError(t, pr.RegisterTargetManager(targetlist.Load())) require.NoError(t, pr.RegisterTestFetcher(literal.Load())) @@ -153,6 +154,6 @@ func TestNewJobNoTestSteps(t *testing.T) { }, } - _, err := NewJobFromDescriptor(xcontext.Background(), pr, &jd) + _, err := NewJobFromDescriptor(context.Background(), pr, &jd) require.Error(t, err) } diff --git a/pkg/jobmanager/jobmanager.go b/pkg/jobmanager/jobmanager.go index 5be3b5af..6cd22310 100644 --- a/pkg/jobmanager/jobmanager.go +++ b/pkg/jobmanager/jobmanager.go @@ -6,12 +6,14 @@ package jobmanager import ( + "context" "encoding/json" "errors" "fmt" "sync" "time" + "github.com/facebookincubator/go-belt/beltctx" "github.com/insomniacslk/xjson" "github.com/linuxboot/contest/pkg/api" @@ -19,11 +21,13 @@ import ( "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/pluginregistry" "github.com/linuxboot/contest/pkg/runner" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // ErrorEventPayload represents the payload carried by a failure event (e.g. JobStateFailed, JobStateCancelled, etc.) @@ -56,7 +60,7 @@ type JobManager struct { apiListener api.Listener pluginRegistry *pluginregistry.PluginRegistry - apiCancel xcontext.CancelFunc + apiCancel context.CancelFunc msgCounter int } @@ -120,7 +124,7 @@ func (jm *JobManager) handleEvent(ev *api.Event) { } } - ev.Context.Debugf("Sending response %+v", resp) + logging.Debugf(ev.Context, "Sending response %+v", resp) // time to wait before printing an error if the response is not received. sendEventTimeout := 3 * time.Second @@ -130,12 +134,12 @@ func (jm *JobManager) handleEvent(ev *api.Event) { // TODO send failure event once we have the event infra // TODO determine whether the server should shut down if there // are too many errors - ev.Context.Logger().Panicf("timed out after %v trying to send a response event", sendEventTimeout) + logging.Panicf(ev.Context, "timed out after %v trying to send a response event", sendEventTimeout) } } // Run is responsible for starting the API listener and responding to incoming events. -func (jm *JobManager) Run(ctx xcontext.Context, resumeJobs bool) error { +func (jm *JobManager) Run(ctx context.Context, resumeJobs bool) error { jm.jobRunner.StartLockRefresh() defer jm.jobRunner.StopLockRefresh() @@ -146,7 +150,7 @@ func (jm *JobManager) Run(ctx xcontext.Context, resumeJobs bool) error { // Deal with zombieed jobs (fail them). if err := jm.failZombieJobs(ctx, a.ServerID()); err != nil { - ctx.Errorf("failed to fail jobs: %v", err) + logging.Errorf(ctx, "failed to fail jobs: %v", err) } // First, resume paused jobs. @@ -156,13 +160,16 @@ func (jm *JobManager) Run(ctx xcontext.Context, resumeJobs bool) error { } } - apiCtx, apiCancel := xcontext.WithCancel(ctx) - jm.apiCancel = apiCancel + apiCtx, apiCancel := context.WithCancel(ctx) + jm.apiCancel = func() { + logging.Debugf(ctx, "cancelling API context") + apiCancel() + } errCh := make(chan error, 1) go func() { lErr := jm.apiListener.Serve(apiCtx, a) - ctx.Infof("Listener shut down successfully.") + logging.Infof(ctx, "Listener shut down successfully.") errCh <- lErr close(errCh) }() @@ -173,7 +180,7 @@ loop: select { // handle events from the API case ev := <-a.Events: - ev.Context.Debugf("Handling event %+v", ev) + logging.Debugf(ev.Context, "Handling event %+v", ev) handlerWg.Add(1) go func() { defer handlerWg.Done() @@ -182,11 +189,11 @@ loop: // check for errors or premature termination from the listener. case err := <-errCh: if err != nil { - ctx.Infof("JobManager: API listener failed (%v)", err) + logging.Infof(ctx, "JobManager: API listener failed (%v)", err) } break loop - case <-ctx.Until(xcontext.ErrPaused): - ctx.Infof("Paused") + case <-signaling.Until(ctx, signals.Paused): + logging.Infof(ctx, "Paused") jm.PauseAll(ctx) break loop case <-ctx.Done(): @@ -200,15 +207,15 @@ loop: handlerWg.Wait() // Wait for jobs to complete or for cancellation signal. doneCh := ctx.Done() - pausedCh := ctx.Until(xcontext.ErrPaused) + pausedCh := signaling.Until(ctx, signals.Paused) for !jm.checkIdle(ctx) { select { case <-pausedCh: - ctx.Infof("Paused") + logging.Infof(ctx, "Paused") jm.PauseAll(ctx) pausedCh = nil case <-doneCh: - ctx.Infof("Canceled") + logging.Infof(ctx, "Canceled") jm.CancelAll(ctx) // Note that we do not break out of the loop here, we expect runner to wind down and exit. doneCh = nil @@ -220,24 +227,24 @@ loop: return nil } -func (jm *JobManager) failZombieJobs(ctx xcontext.Context, serverID string) error { +func (jm *JobManager) failZombieJobs(ctx context.Context, serverID string) error { zombieJobs, err := jm.listMyJobs(ctx, serverID, job.JobStateStarted) if err != nil { return fmt.Errorf("failed to list zombie jobs: %w", err) } - ctx.Infof("Found %d zombie jobs for %s/%s", len(zombieJobs), jm.config.instanceTag, serverID) + logging.Infof(ctx, "Found %d zombie jobs for %s/%s", len(zombieJobs), jm.config.instanceTag, serverID) for _, jobID := range zombieJobs { // Log a line with job id so there's something in the job log to tell what happened. - jobCtx := ctx.WithField("job_id", jobID) - jobCtx.Errorf("This became a zombie, most likely the previous server instance was killed ungracefully") + jobCtx := beltctx.WithField(ctx, "job_id", jobID) + logging.Errorf(jobCtx, "This became a zombie, most likely the previous server instance was killed ungracefully") if err = jm.emitErrEvent(ctx, jobID, job.EventJobFailed, fmt.Errorf("Job %d was zombieed", jobID)); err != nil { - ctx.Errorf("Failed to emit event: %v", err) + logging.Errorf(ctx, "Failed to emit event: %v", err) } } return nil } -func (jm *JobManager) listMyJobs(ctx xcontext.Context, serverID string, jobState job.State) ([]types.JobID, error) { +func (jm *JobManager) listMyJobs(ctx context.Context, serverID string, jobState job.State) ([]types.JobID, error) { queryFields := []storage.JobQueryField{ storage.QueryJobServerID(serverID), storage.QueryJobStates(jobState), @@ -256,14 +263,14 @@ func (jm *JobManager) listMyJobs(ctx xcontext.Context, serverID string, jobState return jobs, nil } -func (jm *JobManager) checkIdle(ctx xcontext.Context) bool { +func (jm *JobManager) checkIdle(ctx context.Context) bool { jm.jobsMu.Lock() defer jm.jobsMu.Unlock() if len(jm.jobs) == 0 { return true } if jm.msgCounter%20 == 0 { - ctx.Infof("Waiting for %d jobs", len(jm.jobs)) + logging.Infof(ctx, "Waiting for %d jobs", len(jm.jobs)) } jm.msgCounter++ return false @@ -289,26 +296,26 @@ func (jm *JobManager) StopAPI() { } // CancelAll cancels all running jobs. -func (jm *JobManager) CancelAll(ctx xcontext.Context) { +func (jm *JobManager) CancelAll(ctx context.Context) { jm.jobsMu.Lock() defer jm.jobsMu.Unlock() for jobID, ji := range jm.jobs { - ctx.Debugf("JobManager: cancelling job %d", jobID) + logging.Debugf(ctx, "JobManager: cancelling job %d", jobID) ji.cancel() } } // CancelAll pauses all running jobs. -func (jm *JobManager) PauseAll(ctx xcontext.Context) { +func (jm *JobManager) PauseAll(ctx context.Context) { jm.jobsMu.Lock() defer jm.jobsMu.Unlock() for jobID, ji := range jm.jobs { - ctx.Debugf("JobManager: pausing job %d", jobID) + logging.Debugf(ctx, "JobManager: pausing job %d", jobID) ji.pause() } } -func (jm *JobManager) emitEventPayload(ctx xcontext.Context, jobID types.JobID, eventName event.Name, payload interface{}) error { +func (jm *JobManager) emitEventPayload(ctx context.Context, jobID types.JobID, eventName event.Name, payload interface{}) error { var payloadJSON json.RawMessage if payload != nil { if p, err := json.Marshal(payload); err == nil { @@ -324,20 +331,20 @@ func (jm *JobManager) emitEventPayload(ctx xcontext.Context, jobID types.JobID, EmitTime: time.Now(), } if err := jm.frameworkEvManager.Emit(ctx, ev); err != nil { - ctx.Warnf("Could not emit event %s for job %d: %v", eventName, jobID, err) + logging.Warnf(ctx, "Could not emit event %s for job %d: %v", eventName, jobID, err) return err } return nil } -func (jm *JobManager) emitErrEvent(ctx xcontext.Context, jobID types.JobID, eventName event.Name, err error) error { +func (jm *JobManager) emitErrEvent(ctx context.Context, jobID types.JobID, eventName event.Name, err error) error { if err != nil { - ctx.Errorf(err.Error()) + logging.Errorf(ctx, err.Error()) return jm.emitEventPayload(ctx, jobID, eventName, &ErrorEventPayload{Err: *xjson.NewError(err)}) } return jm.emitEventPayload(ctx, jobID, eventName, nil) } -func (jm *JobManager) emitEvent(ctx xcontext.Context, jobID types.JobID, eventName event.Name) error { +func (jm *JobManager) emitEvent(ctx context.Context, jobID types.JobID, eventName event.Name) error { return jm.emitErrEvent(ctx, jobID, eventName, nil) } diff --git a/pkg/jobmanager/resume.go b/pkg/jobmanager/resume.go index 33329df7..5ceebc99 100644 --- a/pkg/jobmanager/resume.go +++ b/pkg/jobmanager/resume.go @@ -6,34 +6,35 @@ package jobmanager import ( + "context" "encoding/json" "fmt" "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) -func (jm *JobManager) resumeJobs(ctx xcontext.Context, serverID string) error { +func (jm *JobManager) resumeJobs(ctx context.Context, serverID string) error { pausedJobs, err := jm.listMyJobs(ctx, serverID, job.JobStatePaused) if err != nil { return fmt.Errorf("failed to list paused jobs: %w", err) } - ctx.Infof("Found %d paused jobs for %s/%s", len(pausedJobs), jm.config.instanceTag, serverID) + logging.Infof(ctx, "Found %d paused jobs for %s/%s", len(pausedJobs), jm.config.instanceTag, serverID) for _, jobID := range pausedJobs { if err := jm.resumeJob(ctx, jobID); err != nil { - ctx.Errorf("failed to resume job %d: %v, failing it", jobID, err) + logging.Errorf(ctx, "failed to resume job %d: %v, failing it", jobID, err) if err = jm.emitErrEvent(ctx, jobID, job.EventJobFailed, fmt.Errorf("failed to resume job %d: %w", jobID, err)); err != nil { - ctx.Warnf("Failed to emit event for %d: %v", jobID, err) + logging.Warnf(ctx, "Failed to emit event for %d: %v", jobID, err) } } } return nil } -func (jm *JobManager) resumeJob(ctx xcontext.Context, jobID types.JobID) error { - ctx.Debugf("attempting to resume job %d", jobID) +func (jm *JobManager) resumeJob(ctx context.Context, jobID types.JobID) error { + logging.Debugf(ctx, "attempting to resume job %d", jobID) results, err := jm.frameworkEvManager.Fetch( ctx, frameworkevent.QueryJobID(jobID), @@ -73,7 +74,7 @@ func (jm *JobManager) resumeJob(ctx xcontext.Context, jobID types.JobID) error { return fmt.Errorf("failed to create job %d: %w", jobID, err) } j.ID = jobID - ctx.Debugf("running resumed job %d", j.ID) + logging.Debugf(ctx, "running resumed job %d", j.ID) jm.startJob(ctx, j, &resumeState) return nil } diff --git a/pkg/jobmanager/start.go b/pkg/jobmanager/start.go index d630bfb2..238580ff 100644 --- a/pkg/jobmanager/start.go +++ b/pkg/jobmanager/start.go @@ -6,14 +6,20 @@ package jobmanager import ( + "context" "encoding/json" "fmt" "time" + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/experimental/errmon" + "github.com/facebookincubator/go-belt/tool/experimental/metrics" "github.com/linuxboot/contest/pkg/api" "github.com/linuxboot/contest/pkg/job" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/metrics/perf" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/metrics/perf" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" ) func (jm *JobManager) start(ev *api.Event) *api.EventResponse { @@ -76,72 +82,86 @@ func (jm *JobManager) start(ev *api.Event) *api.EventResponse { } } -func (jm *JobManager) startJob(ctx xcontext.Context, j *job.Job, resumeState *job.PauseEventPayload) { +func (jm *JobManager) startJob(ctx context.Context, j *job.Job, resumeState *job.PauseEventPayload) { jm.jobsMu.Lock() defer jm.jobsMu.Unlock() - jobCtx, jobCancel := xcontext.WithCancel(ctx) - jobCtx, jobPause := xcontext.WithNotify(jobCtx, xcontext.ErrPaused) - jm.jobs[j.ID] = &jobInfo{job: j, pause: jobPause, cancel: jobCancel} + jobCtx := ctx + jobCtx, jobCancel := context.WithCancel(jobCtx) + jobCtx, jobPause := signaling.WithSignal(jobCtx, signals.Paused) + jm.jobs[j.ID] = &jobInfo{ + job: j, + pause: func() { + logging.Debugf(ctx, "pausing job") + jobPause() + }, + cancel: func() { + logging.Debugf(ctx, "cancelling job context") + jobCancel() + }} go jm.runJob(jobCtx, j, resumeState) } -func (jm *JobManager) runJob(ctx xcontext.Context, j *job.Job, resumeState *job.PauseEventPayload) { +func (jm *JobManager) runJob(ctx context.Context, j *job.Job, resumeState *job.PauseEventPayload) { defer func() { jm.jobsMu.Lock() delete(jm.jobs, j.ID) jm.jobsMu.Unlock() }() - if metrics := ctx.Metrics(); metrics != nil { + if metrics := metrics.FromCtx(ctx); metrics != nil { // reflect the number of running jobs metrics.IntGauge(perf.RUNNING_JOBS).Add(1) //, when the job is done decrement the counter defer metrics.IntGauge(perf.RUNNING_JOBS).Add(-1) } - ctx = ctx.WithField("job_id", j.ID) + ctx = beltctx.WithField(ctx, "job_id", j.ID) if err := jm.emitEvent(ctx, j.ID, job.EventJobStarted); err != nil { - ctx.Errorf("failed to emit event: %v", err) + logging.Errorf(ctx, "failed to emit event: %v", err) return } start := time.Now() resumeState, err := jm.jobRunner.Run(ctx, j, resumeState) duration := time.Since(start) - ctx.Debugf("Job %d: runner finished, err %v", j.ID, err) + logging.Debugf(ctx, "Job %d: runner finished, err %v", j.ID, err) switch err { - case xcontext.ErrCanceled: - _ = jm.emitEvent(ctx, j.ID, job.EventJobCancelled) + case context.Canceled: + _err := jm.emitEvent(ctx, j.ID, job.EventJobCancelled) + errmon.ObserveErrorCtx(ctx, _err) return - case xcontext.ErrPaused: + case signals.Paused: if err := jm.emitEventPayload(ctx, j.ID, job.EventJobPaused, resumeState); err != nil { - _ = jm.emitErrEvent(ctx, j.ID, job.EventJobPauseFailed, fmt.Errorf("Job %+v failed pausing: %v", j, err)) + _err := jm.emitErrEvent(ctx, j.ID, job.EventJobPauseFailed, fmt.Errorf("job %+v failed pausing: %w", j, err)) + errmon.ObserveErrorCtx(ctx, _err) } else { - ctx.Infof("Successfully paused job %d (run %d, %d targets)", j.ID, resumeState.RunID, len(resumeState.Targets)) - ctx.Debugf("Job %d pause state: %+v", j.ID, resumeState) + logging.Infof(ctx, "Successfully paused job %d (run %d, %d targets)", j.ID, resumeState.RunID, len(resumeState.Targets)) + logging.Debugf(ctx, "Job %d pause state: %+v", j.ID, resumeState) } return } select { - case <-ctx.Until(xcontext.ErrPaused): + case <-signaling.Until(ctx, signals.Paused): // We were asked to pause but failed to do so. - pauseErr := fmt.Errorf("Job %+v failed pausing: %v", j, err) - ctx.Errorf("%v", pauseErr) - _ = jm.emitErrEvent(ctx, j.ID, job.EventJobPauseFailed, pauseErr) + pauseErr := fmt.Errorf("job %+v failed pausing: %w", j, err) + logging.Errorf(ctx, "%v", pauseErr) + _err := jm.emitErrEvent(ctx, j.ID, job.EventJobPauseFailed, pauseErr) + errmon.ObserveErrorCtx(ctx, _err) return default: } - ctx.Infof("Job %d finished", j.ID) + logging.Infof(ctx, "Job %d finished", j.ID) // at this point it is safe to emit the job status event. Note: this is // checking `err` from the `jm.jobRunner.Run()` call above. if err != nil { - _ = jm.emitErrEvent(ctx, j.ID, job.EventJobFailed, fmt.Errorf("Job %d failed after %s: %w", j.ID, duration, err)) + _err := jm.emitErrEvent(ctx, j.ID, job.EventJobFailed, fmt.Errorf("job %d failed after %s: %w", j.ID, duration, err)) + errmon.ObserveErrorCtx(ctx, _err) } else { - ctx.Infof("Job %+v completed after %s", j, duration) + logging.Infof(ctx, "Job %+v completed after %s", j, duration) err = jm.emitEvent(ctx, j.ID, job.EventJobCompleted) if err != nil { - ctx.Warnf("event emission failed: %v", err) + logging.Warnf(ctx, "event emission failed: %v", err) } } } diff --git a/pkg/jobmanager/steps.go b/pkg/jobmanager/steps.go index fec13aa5..fa79f0ce 100644 --- a/pkg/jobmanager/steps.go +++ b/pkg/jobmanager/steps.go @@ -6,23 +6,24 @@ package jobmanager import ( + "context" + "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/pluginregistry" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // stepsResolver is an interface which determines how to fetch TestStepsDescriptors, which could // have either already been pre-calculated, or built by the TestFetcher. type stepsResolver interface { - GetStepsDescriptors(xcontext.Context) ([]test.TestStepsDescriptors, error) + GetStepsDescriptors(context.Context) ([]test.TestStepsDescriptors, error) } type literalStepsResolver struct { stepsDescriptors []test.TestStepsDescriptors } -func (l literalStepsResolver) GetStepsDescriptors(xcontext.Context) ([]test.TestStepsDescriptors, error) { +func (l literalStepsResolver) GetStepsDescriptors(context.Context) ([]test.TestStepsDescriptors, error) { return l.stepsDescriptors, nil } @@ -31,7 +32,7 @@ type fetcherStepsResolver struct { registry *pluginregistry.PluginRegistry } -func (f fetcherStepsResolver) GetStepsDescriptors(ctx xcontext.Context) ([]test.TestStepsDescriptors, error) { +func (f fetcherStepsResolver) GetStepsDescriptors(ctx context.Context) ([]test.TestStepsDescriptors, error) { var descriptors []test.TestStepsDescriptors for _, testDescriptor := range f.jobDescriptor.TestDescriptors { bundleTestFetcher, err := f.registry.NewTestFetcherBundle(ctx, testDescriptor) diff --git a/pkg/jobmanager/stop.go b/pkg/jobmanager/stop.go index e5c56286..92dbf1cd 100644 --- a/pkg/jobmanager/stop.go +++ b/pkg/jobmanager/stop.go @@ -11,6 +11,7 @@ import ( "github.com/linuxboot/contest/pkg/api" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" ) func (jm *JobManager) stop(ev *api.Event) *api.EventResponse { @@ -24,7 +25,7 @@ func (jm *JobManager) stop(ev *api.Event) *api.EventResponse { // TargetManagerReleaseTimeout for Release to return. err := jm.CancelJob(jobID) if err != nil { - ctx.Errorf("Cannot stop job: %v", err) + logging.Errorf(ctx, "Cannot stop job: %v", err) return &api.EventResponse{Err: fmt.Errorf("could not stop job: %v", err)} } _ = jm.emitEvent(ctx, jobID, job.EventJobCancelling) diff --git a/pkg/loggerhook/httphook.go b/pkg/loggerhook/httphook.go index 701a38c3..c313313b 100644 --- a/pkg/loggerhook/httphook.go +++ b/pkg/loggerhook/httphook.go @@ -11,9 +11,10 @@ import ( "strings" "time" + "github.com/facebookincubator/go-belt/pkg/field" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/cmds/admin_server/server" "github.com/linuxboot/contest/pkg/types" - "github.com/sirupsen/logrus" ) const ( @@ -82,9 +83,12 @@ type HttpHook struct { batchTicker *time.Ticker logChan chan server.Log + flushChan chan struct{} closeChan chan struct{} } +var _ logger.Hook = (*HttpHook)(nil) + func NewHttpHook(cfg Config) (*HttpHook, error) { url, err := url.ParseRequestURI(cfg.Addr) if err != nil { @@ -98,6 +102,7 @@ func NewHttpHook(cfg Config) (*HttpHook, error) { batch: NewBatch(url.String()), batchTicker: time.NewTicker(cfg.BatchSendFreq), logChan: make(chan server.Log, cfg.BufferSize), + flushChan: make(chan struct{}), closeChan: make(chan struct{}), } @@ -107,30 +112,28 @@ func NewHttpHook(cfg Config) (*HttpHook, error) { } -// this implements logrus Hook interface -func (hh *HttpHook) Levels() []logrus.Level { - return logrus.AllLevels -} - -// this implements logrus Hook interface -func (hh *HttpHook) Fire(entry *logrus.Entry) error { +// this implements go-belt's Logger Hook interface +func (hh *HttpHook) ProcessLogEntry(entry *logger.Entry) bool { msg := strings.TrimRight(entry.Message, "\n") if msg == "" { - return nil + return true } - jobId, ok := entry.Data["job_id"] - jobIdInt, notJobID := jobId.(types.JobID) - if !ok || !notJobID { - // to indicate an invalid job id - jobIdInt = 0 - } + var jobID types.JobID + entry.Fields.ForEachField(func(f *field.Field) bool { + switch f.Key { + case "job_id": + jobID, _ = f.Value.(types.JobID) + return false + } + return true + }) log := server.Log{ LogData: msg, - JobID: uint64(jobIdInt), + JobID: uint64(jobID), LogLevel: entry.Level.String(), - Date: entry.Time, + Date: entry.Timestamp, } // timeout is used to not block the service on the logging @@ -139,10 +142,10 @@ func (hh *HttpHook) Fire(entry *logrus.Entry) error { case hh.logChan <- log: // do nothing case <-timeout: - fmt.Fprintf(os.Stderr, "Logging Fire timeout: %v", log) + fmt.Fprintf(os.Stderr, "Logging ProcessLogEntry timeout: %v", log) // TODO: remove os.Stderr hardcodes } - return nil + return true } // logHandler consumes logChan and pushes the logs to the admin server @@ -152,36 +155,44 @@ func (hh *HttpHook) logHandler() { case log := <-hh.logChan: hh.batch.Add(log) if hh.batch.Count() > hh.cfg.MaxBatchCount || hh.batch.Size() > uint64(hh.cfg.MaxBatchSize) { - err := hh.batch.PostAndReset() - if err != nil { - fmt.Fprintf(os.Stderr, "Send Batch failed: %v", err) + if !hh.doFlush() { break } // if the batch is sent // to avoid ticking on an empty batch hh.batchTicker.Reset(hh.cfg.BatchSendFreq) } + case <-hh.flushChan: + if hh.batch.Size() > 0 { + hh.doFlush() + } case <-hh.batchTicker.C: if hh.batch.Size() > 0 { - err := hh.batch.PostAndReset() - if err != nil { - fmt.Fprintf(os.Stderr, "Send Batch failed: %v", err) - } + hh.doFlush() } case <-hh.closeChan: // if there are logs in the buffered batch, send them if hh.batch.Count() > 0 { - err := hh.batch.PostAndReset() - if err != nil { - fmt.Fprintf(os.Stderr, "Send Batch failed: %v", err) - } + hh.doFlush() } - fmt.Fprintf(os.Stderr, "Closing http logger") + fmt.Fprintf(os.Stderr, "Closing http logger") // TODO: remove os.Stderr hardcodes return } } } +func (hh *HttpHook) doFlush() bool { + err := hh.batch.PostAndReset() + if err != nil { + fmt.Fprintf(os.Stderr, "Send Batch failed: %v", err) // TODO: remove os.Stderr hardcodes + } + return err == nil +} + +func (hh *HttpHook) Flush() { + hh.flushChan <- struct{}{} +} + // Close ends the logHandler goroutine func (hh *HttpHook) Close() { hh.closeChan <- struct{}{} diff --git a/pkg/logging/default_options.go b/pkg/logging/default_options.go index c955f809..7604d474 100644 --- a/pkg/logging/default_options.go +++ b/pkg/logging/default_options.go @@ -6,13 +6,22 @@ package logging import ( - "github.com/linuxboot/contest/pkg/xcontext/bundles" + "context" + + "github.com/facebookincubator/go-belt/tool/logger" + "github.com/facebookincubator/go-belt/tool/logger/implementation/logrus" + "github.com/facebookincubator/go-belt/tool/logger/implementation/logrus/formatter" ) // DefaultOptions is a set options recommended to use by default. -func DefaultOptions() []bundles.Option { - return []bundles.Option{ - bundles.OptionLogFormat(bundles.LogFormatPlainTextCompact), - bundles.OptionTimestampFormat("2006-01-02T15:04:05.000Z07:00"), +func WithBelt( + ctx context.Context, + logLevel logger.Level, +) context.Context { + l := logrus.DefaultLogrusLogger() + l.Formatter = &formatter.CompactText{ + TimestampFormat: "2006-01-02T15:04:05.000Z07:00", } + ctx = logger.CtxWithLogger(ctx, logrus.New(l).WithLevel(logLevel)) + return ctx } diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go index a4fb8139..f7f0a2e3 100644 --- a/pkg/logging/logger.go +++ b/pkg/logging/logger.go @@ -6,82 +6,113 @@ package logging import ( - "io" + "context" - log_prefixed "github.com/chappjc/logrus-prefix" - "github.com/sirupsen/logrus" + "github.com/facebookincubator/go-belt/pkg/field" + "github.com/facebookincubator/go-belt/tool/logger" ) -var ( - log *logrus.Logger -) +// Trace is an shorthand for logger.FromCtx(ctx).Trace +func Trace(ctx context.Context, args ...any) { + logger.FromCtx(ctx).Trace(args...) +} + +// Tracef is an shorthand for logger.FromCtx(ctx).Tracef +func Tracef(ctx context.Context, format string, args ...any) { + logger.FromCtx(ctx).Tracef(format, args...) +} + +// TraceFields is an shorthand for logger.FromCtx(ctx).TraceFields +func TraceFields(ctx context.Context, message string, fields field.AbstractFields) { + logger.FromCtx(ctx).TraceFields(message, fields) +} + +// Debug is an shorthand for logger.FromCtx(ctx).Debug +func Debug(ctx context.Context, args ...any) { + logger.FromCtx(ctx).Debug(args...) +} + +// Debugf is an shorthand for logger.FromCtx(ctx).Debugf +func Debugf(ctx context.Context, format string, args ...any) { + logger.FromCtx(ctx).Debugf(format, args...) +} + +// DebugFields is an shorthand for logger.FromCtx(ctx).DebugFields +func DebugFields(ctx context.Context, message string, fields field.AbstractFields) { + logger.FromCtx(ctx).DebugFields(message, fields) +} + +// Info is an shorthand for logger.FromCtx(ctx).Info +func Info(ctx context.Context, args ...any) { + logger.FromCtx(ctx).Info(args...) +} + +// Infof is an shorthand for logger.FromCtx(ctx).Infof +func Infof(ctx context.Context, format string, args ...any) { + logger.FromCtx(ctx).Infof(format, args...) +} + +// InfoFields is an shorthand for logger.FromCtx(ctx).InfoFields +func InfoFields(ctx context.Context, message string, fields field.AbstractFields) { + logger.FromCtx(ctx).InfoFields(message, fields) +} -// GetLogger returns a configured logger instance -func GetLogger(prefix string) *logrus.Entry { - return log.WithField("prefix", prefix) +// Warn is an shorthand for logger.FromCtx(ctx).Warn +func Warn(ctx context.Context, args ...any) { + logger.FromCtx(ctx).Warn(args...) } -// AddField add a field to an existing logrus.Entry -func AddField(e *logrus.Entry, name string, value interface{}) *logrus.Entry { - l := log.WithField(name, value) - for k, v := range e.Data { - l = l.WithField(k, v) - } - return l +// Warnf is an shorthand for logger.FromCtx(ctx).Warnf +func Warnf(ctx context.Context, format string, args ...any) { + logger.FromCtx(ctx).Warnf(format, args...) } -// AddFields adds multiple fields to an existing logrus.Entry -func AddFields(e *logrus.Entry, fields map[string]interface{}) *logrus.Entry { - l := e - for k, v := range fields { - l = AddField(l, k, v) - } - return l +// WarnFields is an shorthand for logger.FromCtx(ctx).WarnFields +func WarnFields(ctx context.Context, message string, fields field.AbstractFields) { + logger.FromCtx(ctx).WarnFields(message, fields) } -// Disable sends all logging output to the bit bucket. -func Disable() { - log.SetOutput(io.Discard) +// Error is an shorthand for logger.FromCtx(ctx).Error +func Error(ctx context.Context, args ...any) { + logger.FromCtx(ctx).Error(args...) } -// Trace - Set Log Level to Trace -func Trace() { - log.SetLevel(logrus.TraceLevel) +// Errorf is an shorthand for logger.FromCtx(ctx).Errorf +func Errorf(ctx context.Context, format string, args ...any) { + logger.FromCtx(ctx).Errorf(format, args...) } -// Debug - Set Log Level to Debug -func Debug() { - log.SetLevel(logrus.DebugLevel) +// ErrorFields is an shorthand for logger.FromCtx(ctx).ErrorFields +func ErrorFields(ctx context.Context, message string, fields field.AbstractFields) { + logger.FromCtx(ctx).ErrorFields(message, fields) } -// Info - Set Log Level to Info -func Info() { - log.SetLevel(logrus.InfoLevel) +// Panic is an shorthand for logger.FromCtx(ctx).Panic +func Panic(ctx context.Context, args ...any) { + logger.FromCtx(ctx).Panic(args...) } -// Warn - Set Log Level to Warn -func Warn() { - log.SetLevel(logrus.WarnLevel) +// Panicf is an shorthand for logger.FromCtx(ctx).Panicf +func Panicf(ctx context.Context, format string, args ...any) { + logger.FromCtx(ctx).Panicf(format, args...) } -// Error - Set Log Level to Error -func Error() { - log.SetLevel(logrus.ErrorLevel) +// PanicFields is an shorthand for logger.FromCtx(ctx).PanicFields +func PanicFields(ctx context.Context, message string, fields field.AbstractFields) { + logger.FromCtx(ctx).PanicFields(message, fields) } -// Fatal - Set Log Level to Fatal -func Fatal() { - log.SetLevel(logrus.FatalLevel) +// Fatal is an shorthand for logger.FromCtx(ctx).Fatal +func Fatal(ctx context.Context, args ...any) { + logger.FromCtx(ctx).Fatal(args...) } -// Panic - Set Log Level to Panic -func Panic() { - log.SetLevel(logrus.PanicLevel) +// Fatalf is an shorthand for logger.FromCtx(ctx).Fatalf +func Fatalf(ctx context.Context, format string, args ...any) { + logger.FromCtx(ctx).Fatalf(format, args...) } -func init() { - log = logrus.New() - log.SetFormatter(&log_prefixed.TextFormatter{ - FullTimestamp: true, - }) +// FatalFields is an shorthand for logger.FromCtx(ctx).FatalFields +func FatalFields(ctx context.Context, message string, fields field.AbstractFields) { + logger.FromCtx(ctx).FatalFields(message, fields) } diff --git a/pkg/xcontext/metrics/perf/perf.go b/pkg/metrics/perf/perf.go similarity index 100% rename from pkg/xcontext/metrics/perf/perf.go rename to pkg/metrics/perf/perf.go diff --git a/pkg/pluginregistry/bundles.go b/pkg/pluginregistry/bundles.go index 81096f9e..8aca15e7 100644 --- a/pkg/pluginregistry/bundles.go +++ b/pkg/pluginregistry/bundles.go @@ -6,16 +6,16 @@ package pluginregistry import ( + "context" "fmt" "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // NewTestStepBundle creates a TestStepBundle from a TestStepDescriptor -func (r *PluginRegistry) NewTestStepBundle(ctx xcontext.Context, testStepDescriptor test.TestStepDescriptor) (*test.TestStepBundle, error) { +func (r *PluginRegistry) NewTestStepBundle(ctx context.Context, testStepDescriptor test.TestStepDescriptor) (*test.TestStepBundle, error) { testStep, err := r.NewTestStep(testStepDescriptor.Name) if err != nil { return nil, fmt.Errorf("could not get the desired TestStep (%s): %v", testStepDescriptor.Name, err) @@ -46,7 +46,7 @@ func (r *PluginRegistry) NewTestStepBundle(ctx xcontext.Context, testStepDescrip // NewTestFetcherBundle creates a TestFetcher and associated parameters based on // the content of the job descriptor -func (r *PluginRegistry) NewTestFetcherBundle(ctx xcontext.Context, testDescriptor *test.TestDescriptor) (*test.TestFetcherBundle, error) { +func (r *PluginRegistry) NewTestFetcherBundle(ctx context.Context, testDescriptor *test.TestDescriptor) (*test.TestFetcherBundle, error) { // Initialization and validation of the TestFetcher and its parameters if testDescriptor == nil { return nil, fmt.Errorf("test description is null") diff --git a/pkg/pluginregistry/pluginregistry.go b/pkg/pluginregistry/pluginregistry.go index 213c9a67..07006865 100644 --- a/pkg/pluginregistry/pluginregistry.go +++ b/pkg/pluginregistry/pluginregistry.go @@ -6,15 +6,16 @@ package pluginregistry import ( + "context" "fmt" "strings" "sync" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // PluginRegistry manages all the plugins available in the system. It associates Plugin @@ -23,7 +24,7 @@ import ( type PluginRegistry struct { lock sync.RWMutex - Context xcontext.Context + Context context.Context // TargetManagers collects a mapping of Plugin Name <-> TargetManager constructor TargetManagers map[string]target.TargetManagerFactory @@ -43,7 +44,7 @@ type PluginRegistry struct { } // NewPluginRegistry constructs a new empty plugin registry -func NewPluginRegistry(ctx xcontext.Context) *PluginRegistry { +func NewPluginRegistry(ctx context.Context) *PluginRegistry { pr := PluginRegistry{ Context: ctx, } @@ -60,7 +61,7 @@ func (r *PluginRegistry) RegisterTargetManager(pluginName string, tmf target.Tar pluginName = strings.ToLower(pluginName) r.lock.Lock() defer r.lock.Unlock() - r.Context.Infof("Registering target manager %s", pluginName) + logging.Infof(r.Context, "Registering target manager %s", pluginName) if _, found := r.TargetManagers[pluginName]; found { return fmt.Errorf("TargetManager %s already registered", pluginName) } @@ -73,7 +74,7 @@ func (r *PluginRegistry) RegisterTestFetcher(pluginName string, tff test.TestFet pluginName = strings.ToLower(pluginName) r.lock.Lock() defer r.lock.Unlock() - r.Context.Infof("Registering test fetcher %s", pluginName) + logging.Infof(r.Context, "Registering test fetcher %s", pluginName) if _, found := r.TestFetchers[pluginName]; found { return fmt.Errorf("TestFetcher %s already registered", pluginName) } @@ -86,7 +87,7 @@ func (r *PluginRegistry) RegisterTestStep(pluginName string, tsf test.TestStepFa pluginName = strings.ToLower(pluginName) r.lock.Lock() defer r.lock.Unlock() - r.Context.Infof("Registering test step %s", pluginName) + logging.Infof(r.Context, "Registering test step %s", pluginName) if _, found := r.TestSteps[pluginName]; found { return fmt.Errorf("TestSteps %s already registered", pluginName) } @@ -110,7 +111,7 @@ func (r *PluginRegistry) RegisterReporter(pluginName string, rf job.ReporterFact pluginName = strings.ToLower(pluginName) r.lock.Lock() defer r.lock.Unlock() - r.Context.Infof("Registering reporter %s", pluginName) + logging.Infof(r.Context, "Registering reporter %s", pluginName) if _, found := r.Reporters[pluginName]; found { return fmt.Errorf("Reporter %s already registered", pluginName) } diff --git a/pkg/pluginregistry/pluginregistry_test.go b/pkg/pluginregistry/pluginregistry_test.go index 109b39df..20ac34ae 100644 --- a/pkg/pluginregistry/pluginregistry_test.go +++ b/pkg/pluginregistry/pluginregistry_test.go @@ -6,15 +6,17 @@ package pluginregistry import ( + "context" "encoding/json" "testing" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/logger" + "github.com/facebookincubator/go-belt/tool/logger/implementation/logrus" "github.com/stretchr/testify/require" ) @@ -30,7 +32,7 @@ func NewAStep() test.TestStep { } // ValidateParameters validates the parameters for the AStep -func (e AStep) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error { +func (e AStep) ValidateParameters(ctx context.Context, params test.TestStepParameters) error { return nil } @@ -41,7 +43,7 @@ func (e AStep) Name() string { // Run executes the AStep func (e AStep) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -52,7 +54,8 @@ func (e AStep) Run( } func TestRegisterTestStep(t *testing.T) { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logger.CtxWithLogger(context.Background(), logrus.Default())) + defer beltctx.Flush(ctx) defer cancel() pr := NewPluginRegistry(ctx) err := pr.RegisterTestStep("AStep", NewAStep, []event.Name{"AStepEventName"}) @@ -60,7 +63,8 @@ func TestRegisterTestStep(t *testing.T) { } func TestRegisterTestStepDoesNotValidate(t *testing.T) { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logger.CtxWithLogger(context.Background(), logrus.Default())) + defer beltctx.Flush(ctx) defer cancel() pr := NewPluginRegistry(ctx) err := pr.RegisterTestStep("AStep", NewAStep, []event.Name{"Event which does not validate"}) diff --git a/pkg/runner/base_test_suite_test.go b/pkg/runner/base_test_suite_test.go index b88fb567..a0148ab6 100644 --- a/pkg/runner/base_test_suite_test.go +++ b/pkg/runner/base_test_suite_test.go @@ -1,6 +1,7 @@ package runner import ( + "context" "encoding/json" "github.com/benbjohnson/clock" @@ -9,7 +10,7 @@ import ( "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/storage/memory" "github.com/linuxboot/contest/plugins/targetlocker/inmemory" "github.com/linuxboot/contest/tests/common" @@ -39,15 +40,15 @@ func NewMemoryStorageEngine() (*MemoryStorageEngine, error) { }, nil } -func (mse *MemoryStorageEngine) GetStepEvents(ctx xcontext.Context, testNames []string, stepLabel string) string { +func (mse *MemoryStorageEngine) GetStepEvents(ctx context.Context, testNames []string, stepLabel string) string { return common.GetTestEventsAsString(ctx, mse.Storage, testNames, nil, &stepLabel) } -func (mse *MemoryStorageEngine) GetTargetEvents(ctx xcontext.Context, testNames []string, targetID string) string { +func (mse *MemoryStorageEngine) GetTargetEvents(ctx context.Context, testNames []string, targetID string) string { return common.GetTestEventsAsString(ctx, mse.Storage, testNames, &targetID, nil) } -func (mse *MemoryStorageEngine) GetTestEvents(ctx xcontext.Context, testNames []string) string { +func (mse *MemoryStorageEngine) GetTestEvents(ctx context.Context, testNames []string) string { return common.GetTestEventsAsString(ctx, mse.Storage, testNames, nil, nil) } @@ -65,7 +66,7 @@ func (s *BaseTestSuite) SetupTest() { target.SetLocker(inmemory.New(clock.New())) - s.PluginRegistry = pluginregistry.NewPluginRegistry(xcontext.Background()) + s.PluginRegistry = pluginregistry.NewPluginRegistry(context.Background()) } func (s *BaseTestSuite) TearDownTest() { @@ -73,10 +74,10 @@ func (s *BaseTestSuite) TearDownTest() { } func (s *BaseTestSuite) RegisterStateFullStep( - runFunction func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + runFunction func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error), - validateFunction func(ctx xcontext.Context, params test.TestStepParameters) error) error { + validateFunction func(ctx context.Context, params test.TestStepParameters) error) error { return s.PluginRegistry.RegisterTestStep(stateFullStepName, func() test.TestStep { return &stateFullStep{ @@ -87,7 +88,7 @@ func (s *BaseTestSuite) RegisterStateFullStep( } func (s *BaseTestSuite) NewStep( - ctx xcontext.Context, + ctx context.Context, label, name string, params test.TestStepParameters, ) test.TestStepBundle { diff --git a/pkg/runner/job_runner.go b/pkg/runner/job_runner.go index 97ea214b..6ca48482 100644 --- a/pkg/runner/job_runner.go +++ b/pkg/runner/job_runner.go @@ -6,29 +6,35 @@ package runner import ( + "context" "encoding/json" "fmt" "sync" "time" "github.com/benbjohnson/clock" + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/pkg/field" + "github.com/facebookincubator/go-belt/tool/experimental/metrics" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/metrics/perf" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/metrics/perf" ) // jobInfo describes jobs currently being run. type jobInfo struct { jobID types.JobID targets []*target.Target - jobCtx xcontext.Context + jobCtx context.Context jobCancel func() } @@ -69,7 +75,7 @@ type JobRunner struct { // last // - []job.Report: all the final reports // - error: an error, if any -func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.PauseEventPayload) (*job.PauseEventPayload, error) { +func (jr *JobRunner) Run(ctx context.Context, j *job.Job, resumeState *job.PauseEventPayload) (*job.PauseEventPayload, error) { if resumeState != nil && resumeState.JobID != j.ID { return nil, fmt.Errorf("wrong resume state, job id %d (want %d)", resumeState.JobID, j.ID) } @@ -84,9 +90,9 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus ) // Values are for plugins to read... - ctx = xcontext.WithValue(ctx, types.KeyJobID, j.ID) + ctx = context.WithValue(ctx, types.KeyJobID, j.ID) // .. Fields are for structured logging - ctx, jobCancel := xcontext.WithCancel(ctx.WithField("job_id", j.ID)) + ctx, jobCancel := context.WithCancel(beltctx.WithField(ctx, "job_id", j.ID)) jr.jobsMapLock.Lock() jr.jobsMap[j.ID] = &jobInfo{jobID: j.ID, jobCtx: ctx, jobCancel: jobCancel} @@ -113,9 +119,9 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus } if j.Runs == 0 { - ctx.Infof("Running job '%s' (id %v) indefinitely, current run #%d test #%d", j.Name, j.ID, runID, testID) + logging.Infof(ctx, "Running job '%s' (id %v) indefinitely, current run #%d test #%d", j.Name, j.ID, runID, testID) } else { - ctx.Infof("Running job '%s' %d times, starting at #%d test #%d", j.Name, j.Runs, runID, testID) + logging.Infof(ctx, "Running job '%s' %d times, starting at #%d test #%d", j.Name, j.Runs, runID, testID) } pauseTest := func( @@ -126,7 +132,7 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus testRunnerState json.RawMessage, cleanupRunnerState json.RawMessage, ) (*job.PauseEventPayload, error) { - ctx.Infof("pause requested for job ID %v", j.ID) + logging.Infof(ctx, "pause requested for job ID %v", j.ID) // Return without releasing targets and keep the job entry so locks continue to be refreshed // all the way to server exit. keepJobEntry = true @@ -140,29 +146,29 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus Targets: targets, TestRunnerState: testRunnerState, CleanupRunnerState: cleanupRunnerState, - }, xcontext.ErrPaused + }, signals.Paused } ev := storage.NewTestEventFetcher(jr.storageEngineVault) for ; runID <= types.RunID(j.Runs) || j.Runs == 0; runID++ { - runCtx := xcontext.WithValue(ctx, types.KeyRunID, runID) - runCtx = runCtx.WithField("run_id", runID) + runCtx := context.WithValue(ctx, types.KeyRunID, runID) + runCtx = beltctx.WithField(runCtx, "run_id", runID) if runDelay > 0 { nextRun := jr.clock.Now().Add(runDelay) - runCtx.Infof("Sleeping %s before the next run...", runDelay) + logging.Infof(runCtx, "Sleeping %s before the next run...", runDelay) select { case <-jr.clock.After(runDelay): - case <-ctx.Until(xcontext.ErrPaused): + case <-signaling.Until(ctx, signals.Paused): resumeState = &job.PauseEventPayload{ Version: job.CurrentPauseEventPayloadVersion, JobID: j.ID, RunID: runID, StartAt: &nextRun, } - runCtx.Infof("Job paused with %s left until next run", nextRun.Sub(jr.clock.Now())) - return resumeState, xcontext.ErrPaused + logging.Infof(runCtx, "Job paused with %s left until next run", nextRun.Sub(jr.clock.Now())) + return resumeState, signals.Paused case <-ctx.Done(): - return nil, xcontext.ErrCanceled + return nil, context.Canceled } } @@ -171,7 +177,7 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus payload := RunStartedPayload{RunID: runID} err := jr.emitEvent(runCtx, j.ID, EventRunStarted, payload) if err != nil { - runCtx.Warnf("Could not emit event run (run %d) start for job %d: %v", runID, j.ID, err) + logging.Warnf(runCtx, "Could not emit event run (run %d) start for job %d: %v", runID, j.ID, err) } for ; testID <= len(j.Tests); testID++ { @@ -180,18 +186,18 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus usedResumeState := resumeState resumeState = nil - runCtx.Infof("Current attempt: %d, allowed retries: %d", + logging.Infof(runCtx, "Current attempt: %d, allowed retries: %d", testAttempt, retryParameters.NumRetries, ) if nextTestAttempt != nil { sleepTime := time.Until(*nextTestAttempt) if sleepTime > 0 { - runCtx.Infof("Sleep until next test attempt at '%v'", *nextTestAttempt) + logging.Infof(runCtx, "Sleep until next test attempt at '%v'", *nextTestAttempt) select { case <-runCtx.Done(): return nil, runCtx.Err() - case <-runCtx.Until(xcontext.ErrPaused): + case <-signaling.Until(ctx, signals.Paused): return pauseTest( runID, testID, @@ -201,13 +207,13 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus usedResumeState.CleanupRunnerState, ) case <-time.After(sleepTime): - runCtx.Infof("Finish sleep") + logging.Infof(runCtx, "Finish sleep") } } } targets, testRunnerState, cleanupRunnerState, succeeded, runErr := jr.runTest(runCtx, j, runID, testID, testAttempt, usedResumeState) - if runErr == xcontext.ErrPaused { + if runErr == signals.Paused { return pauseTest(runID, testID, testAttempt, targets, testRunnerState, cleanupRunnerState) } if runErr != nil { @@ -232,17 +238,17 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus for _, bundle := range j.RunReporterBundles { runStatus, err := jr.BuildRunStatus(ctx, runCoordinates, j) if err != nil { - ctx.Warnf("could not build run status for job %d: %v. Run report will not execute", j.ID, err) + logging.Warnf(ctx, "could not build run status for job %d: %v. Run report will not execute", j.ID, err) continue } success, data, err := bundle.Reporter.RunReport(runCtx, bundle.Parameters, runStatus, ev) if err != nil { - ctx.Warnf("Run reporter failed while calculating run results, proceeding anyway: %v", err) + logging.Warnf(ctx, "Run reporter failed while calculating run results, proceeding anyway: %v", err) } else { if success { - ctx.Infof("Run #%d of job %d considered successful according to %s", runID, j.ID, bundle.Reporter.Name()) + logging.Infof(ctx, "Run #%d of job %d considered successful according to %s", runID, j.ID, bundle.Reporter.Name()) } else { - ctx.Errorf("Run #%d of job %d considered failed according to %s", runID, j.ID, bundle.Reporter.Name()) + logging.Errorf(ctx, "Run #%d of job %d considered failed according to %s", runID, j.ID, bundle.Reporter.Name()) } } report := &job.Report{ @@ -254,7 +260,7 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus Data: data, } if err := jr.jobStorage.StoreReport(ctx, report); err != nil { - ctx.Warnf("Could not store job run report: %v", err) + logging.Warnf(ctx, "Could not store job run report: %v", err) } } @@ -269,18 +275,18 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus // execution early and we did not perform all runs runStatuses, err := jr.BuildRunStatuses(ctx, j) if err != nil { - ctx.Warnf("could not calculate run statuses: %v. Run report will not execute", err) + logging.Warnf(ctx, "could not calculate run statuses: %v. Run report will not execute", err) continue } success, data, err := bundle.Reporter.FinalReport(ctx, bundle.Parameters, runStatuses, ev) if err != nil { - ctx.Warnf("Final reporter failed while calculating test results, proceeding anyway: %v", err) + logging.Warnf(ctx, "Final reporter failed while calculating test results, proceeding anyway: %v", err) } else { if success { - ctx.Infof("Job %d (%d runs out of %d desired) considered successful", j.ID, runID-1, j.Runs) + logging.Infof(ctx, "Job %d (%d runs out of %d desired) considered successful", j.ID, runID-1, j.Runs) } else { - ctx.Errorf("Job %d (%d runs out of %d desired) considered failed", j.ID, runID-1, j.Runs) + logging.Errorf(ctx, "Job %d (%d runs out of %d desired) considered failed", j.ID, runID-1, j.Runs) } } report := &job.Report{ @@ -292,7 +298,7 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus Data: data, } if err := jr.jobStorage.StoreReport(ctx, report); err != nil { - ctx.Warnf("Could not store job run report: %v", err) + logging.Warnf(ctx, "Could not store job run report: %v", err) } } @@ -300,7 +306,7 @@ func (jr *JobRunner) Run(ctx xcontext.Context, j *job.Job, resumeState *job.Paus } func (jr *JobRunner) acquireTargets( - ctx xcontext.Context, + ctx context.Context, j *job.Job, testID int, targetLocker target.Locker, @@ -336,21 +342,21 @@ func (jr *JobRunner) acquireTargets( return nil, false, fmt.Errorf("target locking failed: %w", err) } - ctx.Infof("%d Targets acquired", len(targets)) + logging.Infof(ctx, "%d Targets acquired", len(targets)) // when the targets are acquired, update the counter - if metrics := ctx.Metrics(); metrics != nil { + if metrics := metrics.FromCtx(ctx); metrics != nil { metrics.IntGauge(perf.ACQUIRED_TARGETS).Add(int64(len(targets))) } return targets, true, nil } -func (jr *JobRunner) runTest(ctx xcontext.Context, +func (jr *JobRunner) runTest(ctx context.Context, j *job.Job, runID types.RunID, testID int, testAttempt uint32, resumeState *job.PauseEventPayload, ) ([]*target.Target, json.RawMessage, json.RawMessage, bool, error) { t := j.Tests[testID-1] - ctx.Infof("Run #%d: fetching targets for test '%s'", runID, t.Name) + logging.Infof(ctx, "Run #%d: fetching targets for test '%s'", runID, t.Name) bundle := t.TargetManagerBundle var ( targets []*target.Target @@ -369,7 +375,7 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, tl := target.GetLocker() - acquireCtx, acquireCancel := xcontext.WithTimeout(ctx, j.TargetManagerAcquireTimeout) + acquireCtx, acquireCancel := context.WithTimeout(ctx, j.TargetManagerAcquireTimeout) defer acquireCancel() // the Acquire semantic is synchronous, so that the implementation @@ -387,11 +393,11 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, select { case acquireErr := <-errCh: if acquireErr != nil { - ctx.Errorf("run #%d: cannot fetch targets for test '%s': %w", runID, t.Name, acquireErr) + logging.Errorf(ctx, "run #%d: cannot fetch targets for test '%s': %w", runID, t.Name, acquireErr) // Assume that all errors could be retried except cancellation as both // target manager and target locking problems can disappear if retried - if acquireErr == xcontext.ErrCanceled { + if acquireErr == context.Canceled { return nil, nil, nil, false, acquireErr } @@ -423,14 +429,14 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, // Check for pause during target acquisition. select { - case <-ctx.Until(xcontext.ErrPaused): - ctx.Infof("pause requested for job ID %v", j.ID) - return targets, nil, nil, false, xcontext.ErrPaused + case <-signaling.Until(ctx, signals.Paused): + logging.Infof(ctx, "pause requested for job ID %v", j.ID) + return targets, nil, nil, false, signals.Paused default: } if runErr == nil { - ctx.Infof("Run #%d: running test #%d for job '%s' (job ID: %d) on %d targets", + logging.Infof(ctx, "Run #%d: running test #%d for job '%s' (job ID: %d) on %d targets", runID, testID, j.Name, j.ID, len(targets)) var ( @@ -445,20 +451,20 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, cleanupRunnerState = resumeState.CleanupRunnerState } - runCtx := ctx.WithFields(xcontext.Fields{ + runCtx := beltctx.WithFields(ctx, field.Map[any]{ "job_id": j.ID, "run_id": runID, "attempt": testAttempt, }) - runCtx = xcontext.WithValue(runCtx, types.KeyJobID, j.ID) - runCtx = xcontext.WithValue(runCtx, types.KeyRunID, runID) + runCtx = context.WithValue(runCtx, types.KeyJobID, j.ID) + runCtx = context.WithValue(runCtx, types.KeyRunID, runID) // If a previous run was interrupted in cleanup, do not re-run tests if cleanupRunnerState != nil { - runCtx.Debugf("== test runner skipping test steps as it was interrupted during cleanup") + logging.Debugf(runCtx, "== test runner skipping test steps as it was interrupted during cleanup") } else { testRunner := NewTestRunner() - runCtx.Debugf("== test runner starting test steps") + logging.Debugf(runCtx, "== test runner starting test steps") testRunnerState, targetsResults, stepOutputs, err = testRunner.Run( runCtx, t, @@ -468,24 +474,24 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, nil, t.TestStepsBundles, ) - runCtx.Debugf("== test runner test finished, err: %v", err) + logging.Debugf(runCtx, "== test runner test finished, err: %v", err) succeed = len(targetsResults) == len(targets) for targetID, targetErr := range targetsResults { if targetErr != nil { - ctx.Infof("target '%s' failed with err: '%v'", targetID, err) + logging.Infof(ctx, "target '%s' failed with err: '%v'", targetID, err) succeed = false } } - if err == xcontext.ErrPaused { + if err == signals.Paused { return targets, testRunnerState, nil, succeed, err } runErr = err } if t.CleanupStepsBundles != nil { - runCtx.Debugf("== test runner starting cleanup steps") + logging.Debugf(runCtx, "== test runner starting cleanup steps") cleanupRunner := NewTestRunner() cleanupRunnerState, _, _, err := cleanupRunner.Run( runCtx, @@ -496,9 +502,9 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, stepOutputs, t.CleanupStepsBundles, ) - runCtx.Debugf("== test runner cleanup finished, err: %v", err) + logging.Debugf(runCtx, "== test runner cleanup finished, err: %v", err) - if err == xcontext.ErrPaused { + if err == signals.Paused { return targets, testRunnerState, cleanupRunnerState, succeed, err } // Ignore errors happening in cleanup steps @@ -520,9 +526,9 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, jr.jobsMap[j.ID].targets = nil jr.jobsMapLock.Unlock() if err := tl.Unlock(ctx, j.ID, targets); err == nil { - ctx.Infof("Unlocked %d target(s) for job ID %d", len(targets), j.ID) + logging.Infof(ctx, "Unlocked %d target(s) for job ID %d", len(targets), j.ID) } else { - ctx.Warnf("Failed to unlock %d target(s) (%v): %v", len(targets), targets, err) + logging.Warnf(ctx, "Failed to unlock %d target(s) (%v): %v", len(targets), targets, err) } errCh <- err }() @@ -530,7 +536,7 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, case err := <-errCh: if err != nil { errRelease := fmt.Sprintf("Failed to release targets: %v", err) - ctx.Errorf(errRelease) + logging.Errorf(ctx, errRelease) return nil, nil, nil, succeed, fmt.Errorf(errRelease) } case <-jr.clock.After(j.TargetManagerReleaseTimeout): @@ -538,9 +544,9 @@ func (jr *JobRunner) runTest(ctx xcontext.Context, // Ignore cancellation here, we want release and unlock to happen in that case. } - ctx.Infof("%d Targets released", len(targets)) + logging.Infof(ctx, "%d Targets released", len(targets)) // If the targets are released, update the counter - if metrics := ctx.Metrics(); metrics != nil { + if metrics := metrics.FromCtx(ctx); metrics != nil { metrics.IntGauge(perf.ACQUIRED_TARGETS).Add(-int64(len(targets))) } @@ -598,9 +604,9 @@ func (jr *JobRunner) RefreshLocks() { // Job has been canceled, nothing to do break default: - ji.jobCtx.Debugf("Refreshing target locks...") + logging.Debugf(ji.jobCtx, "Refreshing target locks...") if err := tl.RefreshLocks(ji.jobCtx, ji.jobID, jr.targetLockDuration, ji.targets); err != nil { - ji.jobCtx.Errorf("Failed to refresh %d locks for job ID %d (%v), aborting job", len(ji.targets), ji.jobID, err) + logging.Errorf(ji.jobCtx, "Failed to refresh %d locks for job ID %d (%v), aborting job", len(ji.targets), ji.jobID, err) // We lost our grip on targets, fold the tent and leave ASAP. ji.jobCancel() } @@ -612,29 +618,29 @@ func (jr *JobRunner) RefreshLocks() { } // emitTargetEvents emits test events to keep track of Target acquisition and release -func (jr *JobRunner) emitTargetEvents(ctx xcontext.Context, emitter testevent.Emitter, targets []*target.Target, eventName event.Name) error { +func (jr *JobRunner) emitTargetEvents(ctx context.Context, emitter testevent.Emitter, targets []*target.Target, eventName event.Name) error { // The events hold a serialization of the Target in the payload for _, t := range targets { data := testevent.Data{EventName: eventName, Target: t} if err := emitter.Emit(ctx, data); err != nil { - ctx.Warnf("could not emit event %s: %v", eventName, err) + logging.Warnf(ctx, "could not emit event %s: %v", eventName, err) return err } } return nil } -func (jr *JobRunner) emitEvent(ctx xcontext.Context, jobID types.JobID, eventName event.Name, payload interface{}) error { +func (jr *JobRunner) emitEvent(ctx context.Context, jobID types.JobID, eventName event.Name, payload interface{}) error { payloadJSON, err := json.Marshal(payload) if err != nil { - ctx.Warnf("could not encode payload for event %s: %v", eventName, err) + logging.Warnf(ctx, "could not encode payload for event %s: %v", eventName, err) return err } rawPayload := json.RawMessage(payloadJSON) ev := frameworkevent.Event{JobID: jobID, EventName: eventName, Payload: &rawPayload, EmitTime: jr.clock.Now()} if err := jr.frameworkEventManager.Emit(ctx, ev); err != nil { - ctx.Warnf("could not emit event %s: %v", eventName, err) + logging.Warnf(ctx, "could not emit event %s: %v", eventName, err) return err } return nil diff --git a/pkg/runner/job_runner_test.go b/pkg/runner/job_runner_test.go index 8b651843..2d116de3 100644 --- a/pkg/runner/job_runner_test.go +++ b/pkg/runner/job_runner_test.go @@ -1,6 +1,7 @@ package runner import ( + "context" "encoding/json" "fmt" "sync" @@ -18,13 +19,14 @@ import ( "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/plugins/targetmanagers/targetlist" "github.com/linuxboot/contest/plugins/teststeps" "github.com/linuxboot/contest/plugins/teststeps/echo" @@ -53,16 +55,17 @@ func (s *JobRunnerSuite) SetupTest() { } func (s *JobRunnerSuite) TestSimpleJobStartFinish() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() var mu sync.Mutex var resultTargets []*target.Target require.NoError(s.T(), s.RegisterStateFullStep( - func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) { - return teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx xcontext.Context, target *target.Target) error { + return teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx context.Context, target *target.Target) error { assert.NotNil(s.T(), target) mu.Lock() defer mu.Unlock() @@ -119,16 +122,17 @@ func (s *JobRunnerSuite) TestSimpleJobStartFinish() { } func (s *JobRunnerSuite) TestJobWithCleanupStepsStartToFinish() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() var mu sync.Mutex var resultTargets []*target.Target require.NoError(s.T(), s.RegisterStateFullStep( - func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) { - return teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx xcontext.Context, target *target.Target) error { + return teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx context.Context, target *target.Target) error { assert.NotNil(s.T(), target) mu.Lock() defer mu.Unlock() @@ -192,7 +196,8 @@ func (s *JobRunnerSuite) TestJobWithCleanupStepsStartToFinish() { } func (s *JobRunnerSuite) TestJobWithTestRetry() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() var mu sync.Mutex @@ -200,9 +205,9 @@ func (s *JobRunnerSuite) TestJobWithTestRetry() { var callsCount int require.NoError(s.T(), s.RegisterStateFullStep( - func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) { - return teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx xcontext.Context, target *target.Target) error { + return teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx context.Context, target *target.Target) error { assert.NotNil(s.T(), target) mu.Lock() defer mu.Unlock() @@ -312,7 +317,8 @@ func (s *JobRunnerSuite) TestJobWithTestRetry() { } func (s *JobRunnerSuite) TestJobRetryOnFailedAcquire() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() var mu sync.Mutex @@ -320,7 +326,7 @@ func (s *JobRunnerSuite) TestJobRetryOnFailedAcquire() { tm := stateFullTargetManager{ validateAcquireParametersFunc: func([]byte) (interface{}, error) { return nil, nil }, validateReleaseParametersFunc: func(bytes []byte) (interface{}, error) { return nil, nil }, - acquireFunc: func(ctx xcontext.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, + acquireFunc: func(ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker, ) ([]*target.Target, error) { mu.Lock() @@ -337,7 +343,7 @@ func (s *JobRunnerSuite) TestJobRetryOnFailedAcquire() { }, }, nil }, - releaseFunc: func(ctx xcontext.Context, jobID types.JobID, targets []*target.Target, parameters interface{}) error { + releaseFunc: func(ctx context.Context, jobID types.JobID, targets []*target.Target, parameters interface{}) error { return nil }, } @@ -417,18 +423,19 @@ func (s *JobRunnerSuite) TestJobRetryOnFailedAcquire() { } func (s *JobRunnerSuite) TestAcquireFailed() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() tm := stateFullTargetManager{ validateAcquireParametersFunc: func([]byte) (interface{}, error) { return nil, nil }, validateReleaseParametersFunc: func(bytes []byte) (interface{}, error) { return nil, nil }, - acquireFunc: func(ctx xcontext.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, + acquireFunc: func(ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker, ) ([]*target.Target, error) { return nil, fmt.Errorf("some error") }, - releaseFunc: func(ctx xcontext.Context, jobID types.JobID, targets []*target.Target, parameters interface{}) error { + releaseFunc: func(ctx context.Context, jobID types.JobID, targets []*target.Target, parameters interface{}) error { return nil }, } @@ -497,7 +504,8 @@ func (s *JobRunnerSuite) TestAcquireFailed() { } func (s *JobRunnerSuite) TestResumeStateBadJobId() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() acquireParameters := targetlist.AcquireParameters{ @@ -557,9 +565,9 @@ func (s *JobRunnerSuite) TestResumeStateBadJobId() { const stateFullStepName = "statefull" type stateFullStep struct { - runFunction func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + runFunction func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) - validateFunction func(ctx xcontext.Context, params test.TestStepParameters) error + validateFunction func(ctx context.Context, params test.TestStepParameters) error } func (sfs *stateFullStep) Name() string { @@ -567,7 +575,7 @@ func (sfs *stateFullStep) Name() string { } func (sfs *stateFullStep) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -580,7 +588,7 @@ func (sfs *stateFullStep) Run( return sfs.runFunction(ctx, ch, ev, stepsVars, params, resumeState) } -func (sfs *stateFullStep) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error { +func (sfs *stateFullStep) ValidateParameters(ctx context.Context, params test.TestStepParameters) error { if sfs.validateFunction == nil { return nil } @@ -590,9 +598,9 @@ func (sfs *stateFullStep) ValidateParameters(ctx xcontext.Context, params test.T type stateFullTargetManager struct { validateAcquireParametersFunc func([]byte) (interface{}, error) validateReleaseParametersFunc func([]byte) (interface{}, error) - acquireFunc func(ctx xcontext.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, + acquireFunc func(ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) - releaseFunc func(ctx xcontext.Context, jobID types.JobID, targets []*target.Target, parameters interface{}) error + releaseFunc func(ctx context.Context, jobID types.JobID, targets []*target.Target, parameters interface{}) error } func (sfm stateFullTargetManager) ValidateAcquireParameters(params []byte) (interface{}, error) { @@ -604,7 +612,7 @@ func (sfm stateFullTargetManager) ValidateReleaseParameters(params []byte) (inte } func (sfm stateFullTargetManager) Acquire( - ctx xcontext.Context, + ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, @@ -613,7 +621,7 @@ func (sfm stateFullTargetManager) Acquire( return sfm.acquireFunc(ctx, jobID, jobTargetManagerAcquireTimeout, parameters, tl) } -func (sfm stateFullTargetManager) Release(ctx xcontext.Context, jobID types.JobID, targets []*target.Target, parameters interface{}) error { +func (sfm stateFullTargetManager) Release(ctx context.Context, jobID types.JobID, targets []*target.Target, parameters interface{}) error { return sfm.releaseFunc(ctx, jobID, targets, parameters) } @@ -635,11 +643,11 @@ func (r *collectingReporter) ValidateFinalParameters([]byte) (interface{}, error return nil, nil } -func (r *collectingReporter) RunReport(ctx xcontext.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { +func (r *collectingReporter) RunReport(ctx context.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { r.runStatuses = append(r.runStatuses, *runStatus) return true, nil, nil } -func (r *collectingReporter) FinalReport(ctx xcontext.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { +func (r *collectingReporter) FinalReport(ctx context.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { return true, nil, nil } diff --git a/pkg/runner/job_status.go b/pkg/runner/job_status.go index 2391c9a6..150f54f6 100644 --- a/pkg/runner/job_status.go +++ b/pkg/runner/job_status.go @@ -6,6 +6,7 @@ package runner import ( + "context" "encoding/json" "fmt" @@ -13,10 +14,10 @@ import ( "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // targetRoutingEvents gather all event names which track the flow of targets @@ -73,7 +74,7 @@ func (jr *JobRunner) buildTargetStatuses(coordinates job.TestStepCoordinates, ta } // buildTestStepStatus builds the status object of a test step belonging to a test -func (jr *JobRunner) buildTestStepStatus(ctx xcontext.Context, coordinates job.TestStepCoordinates) (*job.TestStepStatus, error) { +func (jr *JobRunner) buildTestStepStatus(ctx context.Context, coordinates job.TestStepCoordinates) (*job.TestStepStatus, error) { testStepStatus := job.TestStepStatus{TestStepCoordinates: coordinates} @@ -106,7 +107,7 @@ func (jr *JobRunner) buildTestStepStatus(ctx xcontext.Context, coordinates job.T // we don't want target routing events in step events, but we want // them in target events below if _, skip := targetRoutingEvents[ev.Data.EventName]; skip { - ctx.Warnf("Found routing event '%s' with no target associated, this could indicate a bug", ev.Data.EventName) + logging.Warnf(ctx, "Found routing event '%s' with no target associated, this could indicate a bug", ev.Data.EventName) continue } // this goes into TestStepStatus.Events @@ -127,7 +128,7 @@ func (jr *JobRunner) buildTestStepStatus(ctx xcontext.Context, coordinates job.T } // buildTestStatus builds the status of a test belonging to a specific to a test -func (jr *JobRunner) buildTestStatus(ctx xcontext.Context, coordinates job.TestCoordinates, currentJob *job.Job) (*job.TestStatus, error) { +func (jr *JobRunner) buildTestStatus(ctx context.Context, coordinates job.TestCoordinates, currentJob *job.Job) (*job.TestStatus, error) { var currentTest *test.Test // Identify the test within the Job for which we are asking to calculate the status @@ -234,7 +235,7 @@ func (jr *JobRunner) buildTestStatus(ctx xcontext.Context, coordinates job.TestC } // BuildRunStatus builds the status of a run with a job -func (jr *JobRunner) BuildRunStatus(ctx xcontext.Context, coordinates job.RunCoordinates, currentJob *job.Job) (*job.RunStatus, error) { +func (jr *JobRunner) BuildRunStatus(ctx context.Context, coordinates job.RunCoordinates, currentJob *job.Job) (*job.RunStatus, error) { runStatus := job.RunStatus{RunCoordinates: coordinates, TestStatuses: make([]job.TestStatus, len(currentJob.Tests))} @@ -250,7 +251,7 @@ func (jr *JobRunner) BuildRunStatus(ctx xcontext.Context, coordinates job.RunCoo } // BuildRunStatuses builds the status of all runs belonging to the job -func (jr *JobRunner) BuildRunStatuses(ctx xcontext.Context, currentJob *job.Job) ([]job.RunStatus, error) { +func (jr *JobRunner) BuildRunStatuses(ctx context.Context, currentJob *job.Job) ([]job.RunStatus, error) { // Calculate the status only for the runs which effectively were executed runStartEvents, err := jr.frameworkEventManager.Fetch(ctx, frameworkevent.QueryEventName(EventRunStarted), frameworkevent.QueryJobID(currentJob.ID)) diff --git a/pkg/runner/step_runner.go b/pkg/runner/step_runner.go index 16de886d..fd1e5473 100644 --- a/pkg/runner/step_runner.go +++ b/pkg/runner/step_runner.go @@ -11,16 +11,18 @@ import ( "github.com/linuxboot/contest/pkg/cerrors" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) type ChanNotifier interface { NotifyCh() <-chan error } -type AddTargetToStep func(ctx xcontext.Context, tgt *target.Target) (ChanNotifier, error) +type AddTargetToStep func(ctx context.Context, tgt *target.Target) (ChanNotifier, error) type StepResult struct { Err error @@ -88,7 +90,7 @@ func NewStepRunner() *StepRunner { } func (sr *StepRunner) Run( - ctx xcontext.Context, + ctx context.Context, bundle test.TestStepBundle, stepsVariables test.StepsVariables, ev testevent.Emitter, @@ -126,7 +128,7 @@ func (sr *StepRunner) Run( } sr.mu.Unlock() - ctx.Debugf("StepRunner finished") + logging.Debugf(ctx, "StepRunner finished") sr.Stop() } @@ -134,23 +136,23 @@ func (sr *StepRunner) Run( go func() { defer finish() sr.runningLoop(ctx, sr.input, stepOut, bundle, stepsVariables, ev, resumeState) - ctx.Debugf("Running loop finished") + logging.Debugf(ctx, "Running loop finished") }() go func() { defer finish() sr.outputLoop(ctx, stepOut, ev, bundle.TestStepLabel) - ctx.Debugf("Reading loop finished") + logging.Debugf(ctx, "Reading loop finished") }() sr.started = true - return func(ctx xcontext.Context, tgt *target.Target) (ChanNotifier, error) { + return func(ctx context.Context, tgt *target.Target) (ChanNotifier, error) { return sr.addTarget(ctx, bundle, ev, tgt) }, resumedTargetsResults, sr.notifyStopped, nil } func (sr *StepRunner) addTarget( - ctx xcontext.Context, + ctx context.Context, bundle test.TestStepBundle, ev testevent.Emitter, tgt *target.Target, @@ -204,8 +206,8 @@ func (sr *StepRunner) addTarget( return targetInfo, nil case <-stopped: return nil, fmt.Errorf("step runner was stopped") - case <-ctx.Until(xcontext.ErrPaused): - return nil, xcontext.ErrPaused + case <-signaling.Until(ctx, signals.Paused): + return nil, signals.Paused case <-ctx.Done(): return nil, ctx.Err() } @@ -277,7 +279,7 @@ func (sr *StepRunner) Stop() { } func (sr *StepRunner) outputLoop( - ctx xcontext.Context, + ctx context.Context, stepOut chan test.TestStepResult, ev testevent.Emitter, testStepLabel string, @@ -286,7 +288,7 @@ func (sr *StepRunner) outputLoop( select { case res, ok := <-stepOut: if !ok { - ctx.Debugf("Output channel closed") + logging.Debugf(ctx, "Output channel closed") func() { sr.mu.Lock() defer sr.mu.Unlock() @@ -312,7 +314,7 @@ func (sr *StepRunner) outputLoop( sr.setErr(ctx, &cerrors.ErrTestStepReturnedNoTarget{StepName: testStepLabel}) return } - ctx.Infof("Obtained '%v' for target '%s'", res, res.Target.ID) + logging.Infof(ctx, "Obtained '%v' for target '%s'", res, res.Target.ID) shouldEmitTargetIn, targetResult, err := func() (bool, *resultNotifier, error) { sr.mu.Lock() @@ -351,20 +353,20 @@ func (sr *StepRunner) outputLoop( err = emitEvent(ctx, ev, target.EventTargetErr, res.Target, target.ErrPayload{Error: res.Err.Error()}) } if err != nil { - ctx.Errorf("failed to emit event: %s", err) + logging.Errorf(ctx, "failed to emit event: %s", err) sr.setErr(ctx, err) return } targetResult.postResult(res.Err) case <-ctx.Done(): - ctx.Debugf("IO loop detected context canceled") + logging.Debugf(ctx, "IO loop detected context canceled") return } } } func (sr *StepRunner) runningLoop( - ctx xcontext.Context, + ctx context.Context, stepIn <-chan *target.Target, stepOut chan test.TestStepResult, bundle test.TestStepBundle, @@ -380,7 +382,7 @@ func (sr *StepRunner) runningLoop( if recoverOccurred := safeCloseOutCh(stepOut); recoverOccurred { sr.setErr(ctx, &cerrors.ErrTestStepClosedChannels{StepName: bundle.TestStepLabel}) } - ctx.Debugf("output channel closed") + logging.Debugf(ctx, "output channel closed") }() sr.mu.Lock() @@ -400,7 +402,7 @@ func (sr *StepRunner) runningLoop( inChannels := test.TestStepChannels{In: stepIn, Out: stepOut} return bundle.TestStep.Run(ctx, inChannels, ev, stepsVariables, bundle.Parameters, resumeState) }() - ctx.Debugf("TestStep finished '%v', rs: '%s'", err, string(resultResumeState)) + logging.Debugf(ctx, "TestStep finished '%v', rs: '%s'", err, string(resultResumeState)) sr.mu.Lock() sr.setErrLocked(ctx, err) @@ -409,17 +411,17 @@ func (sr *StepRunner) runningLoop( } // setErr sets step runner error unless already set. -func (sr *StepRunner) setErr(ctx xcontext.Context, err error) { +func (sr *StepRunner) setErr(ctx context.Context, err error) { sr.mu.Lock() defer sr.mu.Unlock() sr.setErrLocked(ctx, err) } -func (sr *StepRunner) setErrLocked(ctx xcontext.Context, err error) { +func (sr *StepRunner) setErrLocked(ctx context.Context, err error) { if err == nil || sr.resultErr != nil { return } - ctx.Errorf("err: %v", err) + logging.Errorf(ctx, "err: %v", err) sr.resultErr = err sr.notifyStopped.postResult(err) @@ -443,7 +445,7 @@ func safeCloseOutCh(ch chan test.TestStepResult) (recoverOccurred bool) { } // emitEvent emits the specified event with the specified JSON payload (if any). -func emitEvent(ctx xcontext.Context, ev testevent.Emitter, name event.Name, tgt *target.Target, payload interface{}) error { +func emitEvent(ctx context.Context, ev testevent.Emitter, name event.Name, tgt *target.Target, payload interface{}) error { var payloadJSON *json.RawMessage if payload != nil { payloadBytes, jmErr := json.Marshal(payload) diff --git a/pkg/runner/step_runner_test.go b/pkg/runner/step_runner_test.go index 788e0846..ea755937 100644 --- a/pkg/runner/step_runner_test.go +++ b/pkg/runner/step_runner_test.go @@ -1,6 +1,7 @@ package runner import ( + "context" "encoding/json" "fmt" "sync" @@ -9,11 +10,12 @@ import ( "github.com/linuxboot/contest/pkg/cerrors" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/plugins/teststeps" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -44,7 +46,8 @@ func checkErrorResult(t *testing.T, result ChanNotifier) { } func (s *StepRunnerSuite) TestRunningStep() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() targetsReaction := map[string]error{ @@ -57,10 +60,10 @@ func (s *StepRunnerSuite) TestRunningStep() { var obtainedResumeState json.RawMessage err := s.RegisterStateFullStep( - func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) { obtainedResumeState = resumeState - _, err := teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx xcontext.Context, target *target.Target) error { + _, err := teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx context.Context, target *target.Target) error { require.NotNil(s.T(), target) mu.Lock() @@ -109,7 +112,7 @@ func (s *StepRunnerSuite) TestRunningStep() { stepRunner.Stop() checkSuccessfulResult(s.T(), runResult) - closedCtx, closedCtxCancel := xcontext.WithCancel(ctx) + closedCtx, closedCtxCancel := context.WithCancel(ctx) closedCtxCancel() // if step runner has results, it should return them even if input context is closed @@ -123,15 +126,16 @@ func (s *StepRunnerSuite) TestRunningStep() { } func (s *StepRunnerSuite) TestAddSameTargetSequentiallyTimes() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() const inputTargetID = "input_target_id" err := s.RegisterStateFullStep( - func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) { - _, err := teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx xcontext.Context, target *target.Target) error { + _, err := teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx context.Context, target *target.Target) error { require.NotNil(s.T(), target) require.Equal(s.T(), inputTargetID, target.ID) return nil @@ -170,7 +174,8 @@ func (s *StepRunnerSuite) TestAddSameTargetSequentiallyTimes() { } func (s *StepRunnerSuite) TestAddTargetReturnsErrorIfFailsToInput() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() const inputTargetID = "input_target_id" @@ -184,7 +189,7 @@ func (s *StepRunnerSuite) TestAddTargetReturnsErrorIfFailsToInput() { } }() err := s.RegisterStateFullStep( - func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) { <-hangCh for range ch.In { @@ -216,7 +221,7 @@ func (s *StepRunnerSuite) TestAddTargetReturnsErrorIfFailsToInput() { require.NotNil(s.T(), runResult) s.Run("input_context_cancelled", func() { - cancelCtx, cncl := xcontext.WithCancel(ctx) + cancelCtx, cncl := context.WithCancel(ctx) cncl() tgtResult, err := addTarget(cancelCtx, tgt(inputTargetID)) @@ -240,11 +245,12 @@ func (s *StepRunnerSuite) TestAddTargetReturnsErrorIfFailsToInput() { } func (s *StepRunnerSuite) TestStepPanics() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() err := s.RegisterStateFullStep( - func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) { panic("panic") }, @@ -292,13 +298,14 @@ func (s *StepRunnerSuite) TestStepPanics() { } func (s *StepRunnerSuite) TestCornerCases() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) + ctx, cancel := context.WithCancel(logging.WithBelt(context.Background(), logger.LevelDebug)) + defer beltctx.Flush(ctx) defer cancel() err := s.RegisterStateFullStep( - func(ctx xcontext.Context, ch test.TestStepChannels, ev testevent.Emitter, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) { - _, err := teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx xcontext.Context, target *target.Target) error { + _, err := teststeps.ForEachTarget(stateFullStepName, ctx, ch, func(ctx context.Context, target *target.Target) error { return fmt.Errorf("should not be called") }) return nil, err diff --git a/pkg/runner/step_state.go b/pkg/runner/step_state.go index 269c2b76..2cd412a3 100644 --- a/pkg/runner/step_state.go +++ b/pkg/runner/step_state.go @@ -7,16 +7,18 @@ import ( "strconv" "sync" + "github.com/facebookincubator/go-belt/beltctx" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // stepState contains state associated with one state of the pipeline in TestRunner. type stepState struct { mu sync.Mutex - cancel xcontext.CancelFunc + cancel context.CancelFunc stepIndex int // Index of this step in the pipeline. sb test.TestStepBundle // The test bundle. @@ -111,7 +113,7 @@ func (ss *stepState) GetTestStepLabel() string { return ss.sb.TestStepLabel } -func (ss *stepState) Run(ctx xcontext.Context) error { +func (ss *stepState) Run(ctx context.Context) error { ss.mu.Lock() defer ss.mu.Unlock() @@ -125,15 +127,20 @@ func (ss *stepState) Run(ctx xcontext.Context) error { return nil } - stepCtx, cancel := xcontext.WithCancel(ctx) - stepCtx = stepCtx.WithField("step_index", strconv.Itoa(ss.stepIndex)) - stepCtx = stepCtx.WithField("step_label", ss.sb.TestStepLabel) + stepCtx, stepCtxCancel := context.WithCancel(ctx) + cancel := func() { + logging.Debugf(stepCtx, "cancelling step context") + stepCtxCancel() + } + stepCtx = beltctx.WithField(stepCtx, "step_index", strconv.Itoa(ss.stepIndex)) + stepCtx = beltctx.WithField(stepCtx, "step_label", ss.sb.TestStepLabel) addTarget, resumeTargetsNotifiers, stepRunResult, err := ss.stepRunner.Run( stepCtx, ss.sb, newStepVariablesAccessor(ss.sb.TestStepLabel, ss.tsv), ss.ev, ss.resumeState, ss.resumeStateTargets, ) if err != nil { + cancel() return fmt.Errorf("failed to launch step runner: %v", err) } ss.cancel = cancel @@ -151,20 +158,20 @@ func (ss *stepState) Run(ctx xcontext.Context) error { ss.SetError(ctx, runErr) } close(ss.stopped) - stepCtx.Debugf("StepRunner fully stopped") + logging.Debugf(stepCtx, "StepRunner fully stopped") }() select { case stepErr := <-stepRunResult.NotifyCh(): ss.SetError(ctx, stepErr) case <-stepCtx.Done(): - stepCtx.Debugf("Cancelled step context during waiting for step run result") + logging.Debugf(stepCtx, "Cancelled step context during waiting for step run result") } }() return nil } -func (ss *stepState) InjectTarget(ctx xcontext.Context, tgt *target.Target) (ChanNotifier, error) { +func (ss *stepState) InjectTarget(ctx context.Context, tgt *target.Target) (ChanNotifier, error) { ss.mu.Lock() defer ss.mu.Unlock() @@ -192,19 +199,19 @@ func (ss *stepState) String() string { return fmt.Sprintf("[#%d %s]", ss.stepIndex, ss.sb.TestStepLabel) } -func (ss *stepState) SetError(ctx xcontext.Context, runErr error) { +func (ss *stepState) SetError(ctx context.Context, runErr error) { ss.mu.Lock() defer ss.mu.Unlock() if runErr == nil || ss.runErr != nil { return } - ctx.Errorf("Step '%s' failed with error: %v", ss.sb.TestStepLabel, runErr) + logging.Errorf(ctx, "Step '%s' failed with error: %v", ss.sb.TestStepLabel, runErr) ss.runErr = runErr - if ss.runErr != xcontext.ErrPaused && ss.runErr != xcontext.ErrCanceled { + if ss.runErr != signals.Paused && ss.runErr != context.Canceled { if err := emitEvent(ctx, ss.ev, EventTestError, nil, runErr.Error()); err != nil { - ctx.Errorf("failed to emit event: %s", err) + logging.Errorf(ctx, "failed to emit event: %s", err) } } diff --git a/pkg/runner/test_runner.go b/pkg/runner/test_runner.go index b20ca70a..2456b4d5 100644 --- a/pkg/runner/test_runner.go +++ b/pkg/runner/test_runner.go @@ -13,14 +13,17 @@ import ( "sync/atomic" "time" + "github.com/facebookincubator/go-belt/beltctx" "github.com/insomniacslk/xjson" "github.com/linuxboot/contest/pkg/cerrors" "github.com/linuxboot/contest/pkg/config" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // TestRunner is the state associated with a test run. @@ -92,7 +95,7 @@ type TestStepEventsEmitterFactory interface { // Run is the main entry point of the runner. func (tr *TestRunner) Run( - ctx xcontext.Context, + ctx context.Context, t *test.Test, targets []*target.Target, emitterFactory TestStepEventsEmitterFactory, resumeState json.RawMessage, @@ -101,15 +104,18 @@ func (tr *TestRunner) Run( ) (json.RawMessage, map[string]error, *testStepsVariables, error) { // Peel off contexts used for steps and target handlers. - runCtx, runCancel := xcontext.WithCancel(ctx) - defer runCancel() + runCtx, runCancel := context.WithCancel(ctx) + defer func() { + logging.Debugf(ctx, "run finished, cancelling the context") + runCancel() + }() var targetStates map[string]*targetState // If we have state to resume, parse it. var rs resumeStateStruct if len(resumeState) > 0 { - ctx.Debugf("Attempting to resume from state: %s", string(resumeState)) + logging.Debugf(ctx, "Attempting to resume from state: %s", string(resumeState)) if err := json.Unmarshal(resumeState, &rs); err != nil { return nil, nil, nil, fmt.Errorf("invalid resume state: %w", err) } @@ -146,12 +152,12 @@ func (tr *TestRunner) Run( onStepOutputAdded := func(tgtID string, stepLabel string, name string, value json.RawMessage) { emitter := emitterForStep[stepLabel] if emitter == nil { - runCtx.Errorf("not found events emitter for step: '%s'", stepLabel) + logging.Errorf(runCtx, "not found events emitter for step: '%s'", stepLabel) return } tgs := targetStates[tgtID] if tgs == nil { - runCtx.Errorf("unknown target id: '%s'", tgtID) + logging.Errorf(runCtx, "unknown target id: '%s'", tgtID) return } @@ -160,7 +166,7 @@ func (tr *TestRunner) Run( Value: string(value), } if err := emitEvent(runCtx, emitter, EventVariableEmitted, tgs.tgt, payload); err != nil { - runCtx.Errorf("failed to emit event: '%v'", err) + logging.Errorf(runCtx, "failed to emit event: '%v'", err) } } @@ -168,13 +174,13 @@ func (tr *TestRunner) Run( if stepOutputs == nil { stepOutputs, err = newTestStepsVariables(append(t.TestStepsBundles, t.CleanupStepsBundles...), onStepOutputAdded) if err != nil { - ctx.Errorf("Failed to initialise test steps variables: %v", err) + logging.Errorf(ctx, "Failed to initialise test steps variables: %v", err) return nil, nil, nil, err } for targetID, targetState := range targetStates { if err := stepOutputs.initTargetStepsVariables(targetID, targetState.StepsVariables); err != nil { - ctx.Errorf("Failed to initialise test steps variables for target: %s: %v", targetID, err) + logging.Errorf(ctx, "Failed to initialise test steps variables for target: %s: %v", targetID, err) return nil, nil, nil, err } } @@ -211,10 +217,10 @@ func (tr *TestRunner) Run( targetErrors := make(chan error, len(targetStates)) targetErrorsCount := int32(len(targetStates)) for _, tgs := range targetStates { - go func(ctx xcontext.Context, state *targetState, targetErrors chan<- error) { + go func(ctx context.Context, state *targetState, targetErrors chan<- error) { targetErr := tr.handleTarget(ctx, state) if targetErr != nil { - runCtx.Errorf("Target %s reported an error: %v", state.tgt.ID, targetErr) + logging.Errorf(runCtx, "Target %s reported an error: %v", state.tgt.ID, targetErr) } targetErrors <- targetErr if atomic.AddInt32(&targetErrorsCount, -1) == 0 { @@ -235,12 +241,14 @@ func (tr *TestRunner) Run( if !ok { return resultErr } + logging.Tracef(ctx, "got event from targetErrors: %v", runErr) case runErr = <-stepsErrorsCh: + logging.Tracef(ctx, "got event from stepsErrorsCh: %v", runErr) } - if runErr != nil && runErr != xcontext.ErrPaused && resultErr == nil { + if runErr != nil && runErr != signals.Paused && resultErr == nil { resultErr = runErr - ctx.Errorf("Got error: %v, canceling", runErr) + logging.Errorf(ctx, "Got error: %v, canceling", runErr) for _, ss := range tr.steps { ss.ForceStop() } @@ -255,18 +263,18 @@ func (tr *TestRunner) Run( } // There will be no more results cancel everything - ctx.Debugf("cancel target handlers") + logging.Debugf(ctx, "cancel target handlers") runCancel() // Has the run been canceled? If so, ignore whatever happened, it doesn't matter. select { case <-ctx.Done(): - runErr = xcontext.ErrCanceled + runErr = context.Canceled default: } // Examine the resulting state. - ctx.Debugf("leaving, err %v, target states:", runErr) + logging.Debugf(ctx, "leaving, err %v, target states:", runErr) tr.mu.Lock() defer tr.mu.Unlock() resumeOk := runErr == nil @@ -275,25 +283,25 @@ func (tr *TestRunner) Run( tgs := targetStates[tgt.ID] tgs.StepsVariables, err = stepOutputs.getTargetStepsVariables(tgt.ID) if err != nil { - ctx.Errorf("Failed to get steps variables: %v", err) + logging.Errorf(ctx, "Failed to get steps variables: %v", err) return nil, nil, nil, err } stepErr := tr.steps[tgs.CurStep].GetError() if tgs.CurPhase == targetStepPhaseRun { numInFlightTargets++ - if stepErr != xcontext.ErrPaused { + if stepErr != signals.Paused { resumeOk = false } } - if stepErr != nil && stepErr != xcontext.ErrPaused { + if stepErr != nil && stepErr != signals.Paused { resumeOk = false } - ctx.Debugf(" %d target: '%s' step err: '%v', resume ok: '%t'", i, tgs, stepErr, resumeOk) + logging.Debugf(ctx, " %d target: '%s' step err: '%v', resume ok: '%t'", i, tgs, stepErr, resumeOk) } - ctx.Debugf("- %d in flight, ok to resume? %t", numInFlightTargets, resumeOk) - ctx.Debugf("step states:") + logging.Debugf(ctx, "- %d in flight, ok to resume? %t", numInFlightTargets, resumeOk) + logging.Debugf(ctx, "step states:") for i, ss := range tr.steps { - ctx.Debugf(" %d %s %t %t %s", i, ss, ss.stepRunner.Started(), ss.GetError(), stepResumeStates[i]) + logging.Debugf(ctx, " %d %s %t %t %s", i, ss, ss.stepRunner.Started(), ss.GetError(), stepResumeStates[i]) } // Is there a useful error to report? @@ -303,9 +311,9 @@ func (tr *TestRunner) Run( // Have we been asked to pause? If yes, is it safe to do so? select { - case <-ctx.Until(xcontext.ErrPaused): + case <-signaling.Until(ctx, signals.Paused): if !resumeOk { - ctx.Warnf("paused but not ok to resume") + logging.Warnf(ctx, "paused but not ok to resume") break } rs := &resumeStateStruct{ @@ -315,11 +323,11 @@ func (tr *TestRunner) Run( } resumeState, runErr = json.Marshal(rs) if runErr != nil { - ctx.Errorf("unable to serialize the state: %s", runErr) + logging.Errorf(ctx, "unable to serialize the state: %s", runErr) return nil, nil, nil, runErr } - ctx.Debugf("resume state: %s", resumeState) - runErr = xcontext.ErrPaused + logging.Debugf(ctx, "resume state: %s", resumeState) + runErr = signals.Paused default: } @@ -334,8 +342,8 @@ func (tr *TestRunner) Run( return resumeState, targetsResults, stepOutputs, runErr } -func (tr *TestRunner) waitSteps(ctx xcontext.Context) ([]json.RawMessage, error) { - ctx.Debugf("waiting for step runners to finish") +func (tr *TestRunner) waitSteps(ctx context.Context) ([]json.RawMessage, error) { + logging.Debugf(ctx, "waiting for step runners to finish") shutdownCtx, cancel := context.WithTimeout(ctx, tr.shutdownTimeout) defer cancel() @@ -352,9 +360,9 @@ func (tr *TestRunner) waitSteps(ctx xcontext.Context) ([]json.RawMessage, error) if err != nil { stepsNeverReturned = append(stepsNeverReturned, ss.GetTestStepLabel()) ss.SetError(ctx, &cerrors.ErrTestStepsNeverReturned{StepNames: []string{ss.GetTestStepLabel()}}) - // Stop step context, this will help release the reader. + logging.Debugf(ctx, "stopping step context, this will help release the reader") ss.ForceStop() - } else if resultErr == nil && result.Err != nil && result.Err != xcontext.ErrPaused { + } else if resultErr == nil && result.Err != nil && result.Err != signals.Paused { resultErr = result.Err } resumeStates = append(resumeStates, result.ResumeState) @@ -368,18 +376,18 @@ func (tr *TestRunner) waitSteps(ctx xcontext.Context) ([]json.RawMessage, error) // handleTarget takes a single target through each step of the pipeline in sequence. // It injects the target, waits for the result, then moves on to the next step. -func (tr *TestRunner) handleTarget(ctx xcontext.Context, tgs *targetState) error { +func (tr *TestRunner) handleTarget(ctx context.Context, tgs *targetState) error { lastDecremented := tgs.CurStep - 1 defer func() { - ctx.Debugf("%s: target handler finished", tgs) + logging.Debugf(ctx, "%s: target handler finished", tgs) for i := lastDecremented + 1; i < len(tr.steps); i++ { tr.steps[i].DecreaseLeftTargets() } }() - ctx = ctx.WithField("target", tgs.tgt.ID) - ctx.Debugf("%s: target handler active", tgs) + ctx = beltctx.WithField(ctx, "target", tgs.tgt.ID) + logging.Debugf(ctx, "%s: target handler active", tgs) // Preload next steps; this allows plugin to have init-time state that was saved in // previous state pause events. Otherwise, during a resume, any step that had no @@ -391,19 +399,19 @@ func (tr *TestRunner) handleTarget(ctx xcontext.Context, tgs *targetState) error if err := step.Run(ctx); err != nil { switch err { - case xcontext.ErrPaused: - ctx.Debugf("%s: paused", tgs) + case signals.Paused: + logging.Debugf(ctx, "%s: paused", tgs) - case xcontext.ErrCanceled: - ctx.Debugf("%s: canceled", tgs) + case context.Canceled: + logging.Debugf(ctx, "%s: canceled", tgs) default: - ctx.Errorf("Target handler failed: %v", err) + logging.Errorf(ctx, "Target handler failed: %v", err) } return err } - ctx.Infof("%s: step plugin started", bundle.TestStepLabel) + logging.Infof(ctx, "%s: step plugin started", bundle.TestStepLabel) } // NB: CurStep may be non-zero on entry if resumed @@ -411,11 +419,11 @@ loop: for i := tgs.CurStep; i < len(tr.steps); { // Early check for pause or cancellation. select { - case <-ctx.Until(xcontext.ErrPaused): - ctx.Debugf("%s: paused 0", tgs) + case <-signaling.Until(ctx, signals.Paused): + logging.Debugf(ctx, "%s: paused 0", tgs) break loop case <-ctx.Done(): - ctx.Debugf("%s: canceled 0", tgs) + logging.Debugf(ctx, "%s: canceled 0", tgs) break loop default: } @@ -436,13 +444,13 @@ loop: default: tr.mu.Unlock() err := fmt.Errorf("%s: invalid phase %s", tgs, tgs.CurPhase) - ctx.Errorf("%v", err) + logging.Errorf(ctx, "%v", err) return err } tr.mu.Unlock() // Inject the target. - ctx.Debugf("%s: injecting into %s", tgs, ss) + logging.Debugf(ctx, "%s: injecting into %s", tgs, ss) targetNotifier, err := ss.InjectTarget(ctx, tgs.tgt) if err == nil { @@ -464,7 +472,7 @@ loop: // Await result. It will be communicated to us by the step runner and returned in tgs.res. select { case res := <-targetNotifier.NotifyCh(): - ctx.Debugf("Got target result: '%v'", err) + logging.Debugf(ctx, "Got target result: '%v'", err) tr.mu.Lock() if res != nil { @@ -476,7 +484,7 @@ loop: case <-ss.NotifyStopped(): err = ss.GetError() - ctx.Debugf("step runner stopped, err: %w", err) + logging.Debugf(ctx, "step runner stopped, err: %w", err) if err == nil { // StepState.GetError here is misleading, it may return nil // and that's considered "normal stopping". @@ -485,19 +493,19 @@ loop: case <-ctx.Done(): err = ctx.Err() - ctx.Debugf("Canceled target context during waiting for target result") + logging.Debugf(ctx, "Canceled target context during waiting for target result: %v", err) } - case xcontext.ErrPaused: - ctx.Debugf("%s: paused", tgs) + case signals.Paused: + logging.Debugf(ctx, "%s: paused", tgs) return err - case xcontext.ErrCanceled: - ctx.Debugf("%s: canceled", tgs) + case context.Canceled: + logging.Debugf(ctx, "%s: canceled", tgs) return err default: - ctx.Errorf("target handler failed: %w", err) + logging.Errorf(ctx, "target handler failed: %w", err) return err } } diff --git a/pkg/runner/test_runner_test.go b/pkg/runner/test_runner_test.go index 3a1d3160..de7be96e 100644 --- a/pkg/runner/test_runner_test.go +++ b/pkg/runner/test_runner_test.go @@ -6,6 +6,7 @@ package runner import ( + "context" "encoding/json" "flag" "fmt" @@ -21,12 +22,15 @@ import ( "github.com/linuxboot/contest/pkg/cerrors" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/plugins/teststeps" "github.com/linuxboot/contest/tests/common" "github.com/linuxboot/contest/tests/common/goroutine_leak_check" @@ -51,7 +55,7 @@ func TestMain(m *testing.M) { "github.com/linuxboot/contest/tests/plugins/teststeps/noreturn.(*noreturnStep).Run", // No leak in contexts checked with itsown unit-tests - "github.com/linuxboot/contest/pkg/xcontext.(*ctxValue).cloneWithStdContext.func2", + "github.com/linuxboot/contest/pkg/context.(*ctxValue).cloneWithStdContext.func2", ) } @@ -99,7 +103,7 @@ func (s *TestRunnerSuite) SetupTest() { } } -func (s *TestRunnerSuite) newTestStep(ctx xcontext.Context, label string, failPct int, failTargets string, delayTargets string) test.TestStepBundle { +func (s *TestRunnerSuite) newTestStep(ctx context.Context, label string, failPct int, failTargets string, delayTargets string) test.TestStepBundle { return s.NewStep(ctx, label, teststep.Name, test.TestStepParameters{ teststep.FailPctParam: []test.Param{*test.NewParam(fmt.Sprintf("%d", failPct))}, teststep.FailTargetsParam: []test.Param{*test.NewParam(failTargets)}, @@ -107,7 +111,7 @@ func (s *TestRunnerSuite) newTestStep(ctx xcontext.Context, label string, failPc }) } -func (s *TestRunnerSuite) runWithTimeout(ctx xcontext.Context, +func (s *TestRunnerSuite) runWithTimeout(ctx context.Context, tr *TestRunner, resumeState []byte, runID types.RunID, @@ -115,7 +119,9 @@ func (s *TestRunnerSuite) runWithTimeout(ctx xcontext.Context, targets []*target.Target, bundles []test.TestStepBundle, ) ([]byte, map[string]error, *testStepsVariables, error) { - newCtx, cancel := xcontext.WithCancel(ctx) + newCtx, cancel := context.WithCancel(ctx) + defer cancel() + test := &test.Test{ Name: testName, TestStepsBundles: bundles, @@ -138,7 +144,6 @@ func (s *TestRunnerSuite) runWithTimeout(ctx xcontext.Context, select { case res = <-resCh: case <-time.After(timeout): - cancel() assert.FailNow(s.T(), "TestRunner should not time out") } return res.resume, res.targetsResults, res.stepOutputs, res.err @@ -146,8 +151,8 @@ func (s *TestRunnerSuite) runWithTimeout(ctx xcontext.Context, // Simple case: one target, one step, success. func (s *TestRunnerSuite) Test1Step1Success() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, targetsResults, stepOutputs, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -179,8 +184,8 @@ func (s *TestRunnerSuite) Test1Step1Success() { // Simple case: one target, one step that blocks for a bit, success. // We block for longer than the shutdown timeout of the test runner. func (s *TestRunnerSuite) Test1StepLongerThanShutdown1Success() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := NewTestRunnerWithTimeouts(100 * time.Millisecond) _, targetsResults, stepOutputs, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -211,8 +216,8 @@ func (s *TestRunnerSuite) Test1StepLongerThanShutdown1Success() { // Simple case: one target, one step, failure. func (s *TestRunnerSuite) Test1Step1Fail() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, targetsResults, stepOutputs, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -242,8 +247,8 @@ func (s *TestRunnerSuite) Test1Step1Fail() { // One step pipeline with two targets - one fails, one succeeds. func (s *TestRunnerSuite) Test1Step1Success1Fail() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -274,8 +279,8 @@ func (s *TestRunnerSuite) Test1Step1Success1Fail() { // Three-step pipeline, two targets: T1 fails at step 1, T2 fails at step 2, // step 3 is not reached and not even run. func (s *TestRunnerSuite) Test3StepsNotReachedStepNotRun() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -317,8 +322,8 @@ func (s *TestRunnerSuite) Test3StepsNotReachedStepNotRun() { // A misbehaving step that fails to shut down properly after processing targets // and does not return. func (s *TestRunnerSuite) TestNoReturnStepWithCorrectTargetForwarding() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := NewTestRunnerWithTimeouts(200 * time.Millisecond) _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -334,8 +339,8 @@ func (s *TestRunnerSuite) TestNoReturnStepWithCorrectTargetForwarding() { // A misbehaving step that panics. func (s *TestRunnerSuite) TestStepPanics() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -352,8 +357,8 @@ func (s *TestRunnerSuite) TestStepPanics() { // A misbehaving step that closes its output channel. func (s *TestRunnerSuite) TestStepClosesChannels() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -375,8 +380,8 @@ func (s *TestRunnerSuite) TestStepClosesChannels() { // A misbehaving step that yields a result for a target that does not exist. func (s *TestRunnerSuite) TestStepYieldsResultForNonexistentTarget() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -395,8 +400,8 @@ func (s *TestRunnerSuite) TestStepYieldsResultForNonexistentTarget() { // A misbehaving step that yields a duplicate result for a target. func (s *TestRunnerSuite) TestStepYieldsDuplicateResult() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -414,8 +419,8 @@ func (s *TestRunnerSuite) TestStepYieldsDuplicateResult() { // A misbehaving step that loses targets. func (s *TestRunnerSuite) TestStepLosesTargets() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -432,8 +437,8 @@ func (s *TestRunnerSuite) TestStepLosesTargets() { // A misbehaving step that yields a result for a target that does exist // but is not currently waiting for it. func (s *TestRunnerSuite) TestStepYieldsResultForUnexpectedTarget() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() _, _, _, err := s.runWithTimeout(ctx, tr, nil, 1, 2*time.Second, @@ -451,8 +456,8 @@ func (s *TestRunnerSuite) TestStepYieldsResultForUnexpectedTarget() { // Larger, randomized test - a number of steps, some targets failing, some succeeding. func (s *TestRunnerSuite) TestRandomizedMultiStep() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) tr := newTestRunner() var targets []*target.Target @@ -489,15 +494,15 @@ func (s *TestRunnerSuite) TestRandomizedMultiStep() { } func (s *TestRunnerSuite) TestVariables() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) var ( - pause xcontext.CancelFunc + pause signaling.SignalFunc mu sync.Mutex ) require.NoError(s.T(), s.RegisterStateFullStep( - func(ctx xcontext.Context, + func(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -505,7 +510,7 @@ func (s *TestRunnerSuite) TestVariables() { resumeState json.RawMessage, ) (json.RawMessage, error) { _, err := teststeps.ForEachTargetWithResume(ctx, ch, resumeState, 1, - func(ctx xcontext.Context, target *teststeps.TargetWithData) error { + func(ctx context.Context, target *teststeps.TargetWithData) error { require.NoError(s.T(), stepsVars.Add(target.Target.ID, "target_id", target.Target.ID)) var resultValue string @@ -518,14 +523,14 @@ func (s *TestRunnerSuite) TestVariables() { defer mu.Unlock() if pause != nil { pause() - return xcontext.ErrPaused + return signals.Paused } return nil }() }) return nil, err }, - func(ctx xcontext.Context, params test.TestStepParameters) error { + func(ctx context.Context, params test.TestStepParameters) error { return nil }, )) @@ -536,8 +541,8 @@ func (s *TestRunnerSuite) TestVariables() { var resumeState []byte { - ctx1, ctxPause := xcontext.WithNotify(ctx, xcontext.ErrPaused) - ctx1, ctxCancel := xcontext.WithCancel(ctx1) + ctx1, ctxPause := signaling.WithSignal(ctx, signals.Paused) + ctx1, ctxCancel := context.WithCancel(ctx1) defer ctxCancel() mu.Lock() @@ -553,7 +558,7 @@ func (s *TestRunnerSuite) TestVariables() { s.NewStep(ctx, "step2", stateFullStepName, nil), }, ) - require.IsType(s.T(), xcontext.ErrPaused, err) + require.IsType(s.T(), signals.Paused, err) require.NotEmpty(s.T(), resumeState) } @@ -585,8 +590,8 @@ func (s *TestRunnerSuite) TestVariables() { // Test pausing/resuming a naive step that does not cooperate. // In this case we drain input, wait for all targets to emerge and exit gracefully. func (s *TestRunnerSuite) TestPauseResumeSimple() { - ctx, cancel := logrusctx.NewContext(logger.LevelDebug) - defer cancel() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) var err error var resumeState []byte @@ -599,24 +604,24 @@ func (s *TestRunnerSuite) TestPauseResumeSimple() { } { tr1 := newTestRunner() - ctx1, pause := xcontext.WithNotify(ctx, xcontext.ErrPaused) - ctx1, cancel := xcontext.WithCancel(ctx1) + ctx1, pause := signaling.WithSignal(ctx, signals.Paused) + ctx1, cancel := context.WithCancel(ctx1) defer cancel() go func() { time.Sleep(100 * time.Millisecond) - ctx.Infof("TestPauseResumeNaive: pausing") + logging.Infof(ctx, "TestPauseResumeNaive: pausing") pause() }() resumeState, _, _, err = s.runWithTimeout(ctx1, tr1, nil, 1, 2*time.Second, targets, steps) require.Error(s.T(), err) - require.IsType(s.T(), xcontext.ErrPaused, err) + require.IsType(s.T(), signals.Paused, err) require.NotNil(s.T(), resumeState) } - ctx.Debugf("Resume state: %s", string(resumeState)) + logging.Debugf(ctx, "Resume state: %s", string(resumeState)) // Make sure that resume state is validated. { tr := newTestRunner() - ctx, cancel := xcontext.WithCancel(ctx) + ctx, cancel := context.WithCancel(ctx) defer cancel() resumeState2, _, _, err := s.runWithTimeout( ctx, tr, []byte("FOO"), 2, 2*time.Second, targets, steps) @@ -626,7 +631,7 @@ func (s *TestRunnerSuite) TestPauseResumeSimple() { } { tr := newTestRunner() - ctx, cancel := xcontext.WithCancel(ctx) + ctx, cancel := context.WithCancel(ctx) defer cancel() resumeState2 := strings.Replace(string(resumeState), `"V"`, `"XV"`, 1) _, _, _, err := s.runWithTimeout( @@ -638,7 +643,7 @@ func (s *TestRunnerSuite) TestPauseResumeSimple() { // Finally, resume and finish the job. { tr2 := newTestRunner() - ctx2, cancel := xcontext.WithCancel(ctx) + ctx2, cancel := context.WithCancel(ctx) defer cancel() _, _, _, err := s.runWithTimeout(ctx2, tr2, resumeState, 5, 2*time.Second, // Pass exactly the same targets and pipeline to resume properly. diff --git a/pkg/signaling/signaler.go b/pkg/signaling/signaler.go new file mode 100644 index 00000000..731fba06 --- /dev/null +++ b/pkg/signaling/signaler.go @@ -0,0 +1,79 @@ +package signaling + +import ( + "context" + "fmt" + "sync" +) + +type ctxKey[T Signal] struct { + Signal T +} + +// Signal is an interface defining constraints of a type which could be used +// as a signal (in functions WithSignal, Until and IsSignaledWith). +type Signal interface { + error + comparable +} + +type signaler chan struct{} + +func getSignalChan[T Signal](ctx context.Context, signal T) signaler { + signaler, _ := ctx.Value(ctxKey[T]{Signal: signal}).(signaler) + // If a signaller is not defined then a nil is returned, + // and a nil channel is an infinitely open channel without events, + // so it blocks reading forever. + return signaler +} + +func withSignalChan[T Signal](ctx context.Context, signal T) (context.Context, signaler) { + s := make(signaler) + return context.WithValue(ctx, ctxKey[T]{Signal: signal}, s), s +} + +// IsSignaledWith returns true if the context received the signal. +func IsSignaledWith[T Signal](ctx context.Context, signal T) (bool, error) { + return chanIsClosed(getSignalChan(ctx, signal)) +} + +func chanIsClosed(c <-chan struct{}) (bool, error) { + select { + case _, isOpen := <-c: + if isOpen { + // Any signaling here supposed to be broadcast, and the only broadcast + // kind of event on a channel is a closure. So no events should be sent + // through this channel, but it could be closed. + return false, fmt.Errorf("the channel has an event, but is not closed; this was supposed to be impossible") + } + return true, nil + default: + return false, nil + } +} + +// Until works similar to Done(), but waits for a specific signal +// defined via WithSignal function. +func Until[T Signal](ctx context.Context, signal T) <-chan struct{} { + return getSignalChan(ctx, signal) +} + +// SignalFunc is similar to context.CancelFunc, but instead of closing +// the context it sends a signal through it (which could be observed with Until +// and IsSignaledWith). +type SignalFunc func() + +var _ = context.CancelFunc((SignalFunc)(nil)) // check if CancelFunc and SignalFunc has the same signature + +// WithSignal is similar to context.WithCancel, but the returned function +// sends signal through the context (which could be observed with Until +// and IsSignaledWith). +func WithSignal[T Signal](ctx context.Context, signal T) (context.Context, SignalFunc) { + ctx, s := withSignalChan(ctx, signal) + var closeOnce sync.Once + return ctx, func() { + closeOnce.Do(func() { + close(s) + }) + } +} diff --git a/pkg/signaling/signaler_flaky_test.go b/pkg/signaling/signaler_flaky_test.go new file mode 100644 index 00000000..bca6a285 --- /dev/null +++ b/pkg/signaling/signaler_flaky_test.go @@ -0,0 +1,41 @@ +//go:build flakytests + +package signaling + +import ( + "context" + "runtime" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGC(t *testing.T) { + // parent + ctx := context.Background() + ctx, _ = WithSignal(ctx, unitTestCustomSignal0) + + gc := func() { + runtime.GC() + runtime.Gosched() + runtime.GC() + runtime.Gosched() + } + + // mem stats before the child + var ( + memStatsBefore runtime.MemStats + memStatsAfter runtime.MemStats + ) + gc() + runtime.ReadMemStats(&memStatsBefore) + + // short-living child + WithSignal(ctx, unitTestCustomSignal1) + + // mem stats after the child + gc() + runtime.ReadMemStats(&memStatsAfter) + + require.Equal(t, memStatsBefore.HeapInuse, memStatsAfter.HeapInuse) +} diff --git a/pkg/signaling/signaler_test.go b/pkg/signaling/signaler_test.go new file mode 100644 index 00000000..a441c791 --- /dev/null +++ b/pkg/signaling/signaler_test.go @@ -0,0 +1,101 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +package signaling + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +type unitTestCustomSignalType struct { + ID int +} + +func (s unitTestCustomSignalType) Error() string { + return fmt.Sprintf("unit-test custom signal #%d", s.ID) +} + +var unitTestCustomSignal0 = unitTestCustomSignalType{ID: 0} +var unitTestCustomSignal1 = unitTestCustomSignalType{ID: 1} +var unitTestCustomSignal2 = unitTestCustomSignalType{ID: 2} + +func TestBackgroundContext(t *testing.T) { + ctx := context.Background() + + var blocked bool + select { + case <-Until(ctx, unitTestCustomSignal0): + default: + blocked = true + } + + require.True(t, blocked) +} + +func TestSendSignal(t *testing.T) { + ctx, pauseFunc := WithSignal(context.Background(), unitTestCustomSignal0) + require.NotNil(t, ctx) + + pauseFunc() + + <-Until(ctx, unitTestCustomSignal0) + + require.Nil(t, ctx.Err()) + + var canceled bool + select { + case <-ctx.Done(): + canceled = true + default: + } + require.False(t, canceled) +} + +func TestSendMultipleSignals(t *testing.T) { + ctx := context.Background() + ctx, sendSignal0 := WithSignal(ctx, unitTestCustomSignal0) + ctx, sendSignal1 := WithSignal(ctx, unitTestCustomSignal1) + require.NotNil(t, ctx) + + sendSignal1() + sendSignal0() + sendSignal1() + sendSignal0() + + <-Until(ctx, unitTestCustomSignal0) + <-Until(ctx, unitTestCustomSignal1) +} + +func TestGrandGrandGrandChild(t *testing.T) { + type myUniqueType string + ctx0, sendSignal0 := WithSignal(context.Background(), unitTestCustomSignal0) + ctx1, _ := WithSignal(context.WithValue(ctx0, myUniqueType("someKey1"), "someValue1"), unitTestCustomSignal1) + ctx2, _ := WithSignal(context.WithValue(ctx1, myUniqueType("someKey2"), "someValue2"), unitTestCustomSignal2) + + r, err := IsSignaledWith(ctx2, unitTestCustomSignal0) + require.False(t, r) + require.NoError(t, err) + sendSignal0() + <-Until(ctx2, unitTestCustomSignal0) + r, err = IsSignaledWith(ctx2, unitTestCustomSignal0) + require.True(t, r) + require.NoError(t, err) + r, err = IsSignaledWith(ctx2, unitTestCustomSignal1) + require.False(t, r) + require.NoError(t, err) + + select { + case <-Until(ctx2, unitTestCustomSignal1): + require.FailNow(t, "unexpected closed chan for signal1") + case <-Until(ctx2, unitTestCustomSignal2): + require.FailNow(t, "unexpected closed chan for signal2") + default: + } + +} diff --git a/pkg/signals/paused.go b/pkg/signals/paused.go new file mode 100644 index 00000000..86a06645 --- /dev/null +++ b/pkg/signals/paused.go @@ -0,0 +1,10 @@ +package signals + +type pausedType struct{} + +func (pausedType) Error() string { return "paused" } + +// Paused is a signal (signaling.Signal) to notify goroutines +// that the process is trying to pause and all long-running +// routines should save their state (if required) and return. +var Paused = pausedType{} diff --git a/pkg/storage/events.go b/pkg/storage/events.go index 3f421654..98d71937 100644 --- a/pkg/storage/events.go +++ b/pkg/storage/events.go @@ -6,23 +6,23 @@ package storage import ( + "context" "fmt" "time" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/event/testevent" - "github.com/linuxboot/contest/pkg/xcontext" ) type EventStorage interface { // Test events storage interface - StoreTestEvent(ctx xcontext.Context, event testevent.Event) error - GetTestEvents(ctx xcontext.Context, eventQuery *testevent.Query) ([]testevent.Event, error) + StoreTestEvent(ctx context.Context, event testevent.Event) error + GetTestEvents(ctx context.Context, eventQuery *testevent.Query) ([]testevent.Event, error) // Framework events storage interface - StoreFrameworkEvent(ctx xcontext.Context, event frameworkevent.Event) error - GetFrameworkEvent(ctx xcontext.Context, eventQuery *frameworkevent.Query) ([]frameworkevent.Event, error) + StoreFrameworkEvent(ctx context.Context, event frameworkevent.Event) error + GetFrameworkEvent(ctx context.Context, eventQuery *frameworkevent.Query) ([]frameworkevent.Event, error) } // TestEventEmitter implements Emitter interface from the testevent package @@ -46,7 +46,7 @@ type TestEventEmitterFetcher struct { } // Emit emits an event using the selected storage layer -func (e TestEventEmitter) Emit(ctx xcontext.Context, data testevent.Data) error { +func (e TestEventEmitter) Emit(ctx context.Context, data testevent.Data) error { if e.emitterVault == nil { return fmt.Errorf("storage engine storage is not set") } @@ -70,7 +70,7 @@ func (e TestEventEmitter) Emit(ctx xcontext.Context, data testevent.Data) error } // Fetch retrieves events based on QueryFields that are used to build a Query object for TestEvents -func (ev TestEventFetcher) Fetch(ctx xcontext.Context, queryFields ...testevent.QueryField) ([]testevent.Event, error) { +func (ev TestEventFetcher) Fetch(ctx context.Context, queryFields ...testevent.QueryField) ([]testevent.Event, error) { engineType := SyncEngine if !isStronglyConsistent(ctx) { engineType = AsyncEngine @@ -141,7 +141,7 @@ type FrameworkEventEmitterFetcher struct { } // Emit emits an event using the selected storage engine -func (ev FrameworkEventEmitter) Emit(ctx xcontext.Context, event frameworkevent.Event) error { +func (ev FrameworkEventEmitter) Emit(ctx context.Context, event frameworkevent.Event) error { if ev.emitterVault == nil { return fmt.Errorf("storage engine storage is not set") } @@ -158,7 +158,7 @@ func (ev FrameworkEventEmitter) Emit(ctx xcontext.Context, event frameworkevent. } // Fetch retrieves events based on QueryFields that are used to build a Query object for FrameworkEvents -func (ev FrameworkEventFetcher) Fetch(ctx xcontext.Context, queryFields ...frameworkevent.QueryField) ([]frameworkevent.Event, error) { +func (ev FrameworkEventFetcher) Fetch(ctx context.Context, queryFields ...frameworkevent.QueryField) ([]frameworkevent.Event, error) { engineType := SyncEngine if !isStronglyConsistent(ctx) { engineType = AsyncEngine diff --git a/pkg/storage/events_test.go b/pkg/storage/events_test.go index a24c42f2..b3e24476 100644 --- a/pkg/storage/events_test.go +++ b/pkg/storage/events_test.go @@ -6,11 +6,12 @@ package storage import ( + "context" "testing" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/logger" + "github.com/linuxboot/contest/pkg/logging" "github.com/stretchr/testify/require" "github.com/linuxboot/contest/pkg/event" @@ -23,7 +24,7 @@ type testEventEmitterFixture struct { allowedEvents []event.Name allowedMap map[event.Name]bool forbiddenEvents []event.Name - ctx xcontext.Context + ctx context.Context } func mockTestEventEmitterData() *testEventEmitterFixture { @@ -32,7 +33,8 @@ func mockTestEventEmitterData() *testEventEmitterFixture { "TestEventAllowed2", } - ctx, _ := logrusctx.NewContext(logger.LevelDebug) + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + defer beltctx.Flush(ctx) return &testEventEmitterFixture{ header: testevent.Header{ @@ -76,13 +78,12 @@ func TestEmitRestricted(t *testing.T) { } type testEventFetcherFixture struct { - ctx xcontext.Context + ctx context.Context } func mockTestEventFetcherData() *testEventFetcherFixture { - ctx, _ := logrusctx.NewContext(logger.LevelDebug) return &testEventFetcherFixture{ - ctx: ctx, + ctx: logging.WithBelt(context.Background(), logger.LevelDebug), } } diff --git a/pkg/storage/job.go b/pkg/storage/job.go index e0681539..a19cd494 100644 --- a/pkg/storage/job.go +++ b/pkg/storage/job.go @@ -6,24 +6,25 @@ package storage import ( + "context" + "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // JobStorage defines the interface that implements persistence for job // related information type JobStorage interface { // Job request interface - StoreJobRequest(ctx xcontext.Context, request *job.Request) (types.JobID, error) - GetJobRequest(ctx xcontext.Context, jobID types.JobID) (*job.Request, error) + StoreJobRequest(ctx context.Context, request *job.Request) (types.JobID, error) + GetJobRequest(ctx context.Context, jobID types.JobID) (*job.Request, error) // Job report interface - StoreReport(ctx xcontext.Context, report *job.Report) error - GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.JobReport, error) + StoreReport(ctx context.Context, report *job.Report) error + GetJobReport(ctx context.Context, jobID types.JobID) (*job.JobReport, error) // Job enumeration interface - ListJobs(ctx xcontext.Context, query *JobQuery) ([]types.JobID, error) + ListJobs(ctx context.Context, query *JobQuery) ([]types.JobID, error) } // JobStorageManager implements JobStorage interface @@ -32,7 +33,7 @@ type JobStorageManager struct { } // StoreJobRequest submits a job request to the storage layer -func (jsm JobStorageManager) StoreJobRequest(ctx xcontext.Context, request *job.Request) (types.JobID, error) { +func (jsm JobStorageManager) StoreJobRequest(ctx context.Context, request *job.Request) (types.JobID, error) { storage, err := jsm.vault.GetEngine(SyncEngine) if err != nil { return 0, err @@ -42,7 +43,7 @@ func (jsm JobStorageManager) StoreJobRequest(ctx xcontext.Context, request *job. } // GetJobRequest fetches a job request from the storage layer -func (jsm JobStorageManager) GetJobRequest(ctx xcontext.Context, jobID types.JobID) (*job.Request, error) { +func (jsm JobStorageManager) GetJobRequest(ctx context.Context, jobID types.JobID) (*job.Request, error) { engineType := SyncEngine if !isStronglyConsistent(ctx) { engineType = AsyncEngine @@ -56,7 +57,7 @@ func (jsm JobStorageManager) GetJobRequest(ctx xcontext.Context, jobID types.Job } // StoreReport submits a job run or final report to the storage layer -func (jsm JobStorageManager) StoreReport(ctx xcontext.Context, report *job.Report) error { +func (jsm JobStorageManager) StoreReport(ctx context.Context, report *job.Report) error { storage, err := jsm.vault.GetEngine(SyncEngine) if err != nil { return err @@ -66,7 +67,7 @@ func (jsm JobStorageManager) StoreReport(ctx xcontext.Context, report *job.Repor } // GetJobReport fetches a job report from the storage layer -func (jsm JobStorageManager) GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.JobReport, error) { +func (jsm JobStorageManager) GetJobReport(ctx context.Context, jobID types.JobID) (*job.JobReport, error) { engineType := SyncEngine if !isStronglyConsistent(ctx) { engineType = AsyncEngine @@ -80,7 +81,7 @@ func (jsm JobStorageManager) GetJobReport(ctx xcontext.Context, jobID types.JobI } // ListJobs returns list of job IDs matching the query -func (jsm JobStorageManager) ListJobs(ctx xcontext.Context, query *JobQuery) ([]types.JobID, error) { +func (jsm JobStorageManager) ListJobs(ctx context.Context, query *JobQuery) ([]types.JobID, error) { engineType := SyncEngine if !isStronglyConsistent(ctx) { engineType = AsyncEngine diff --git a/pkg/storage/job_test.go b/pkg/storage/job_test.go index 121ee4d7..e414d5eb 100644 --- a/pkg/storage/job_test.go +++ b/pkg/storage/job_test.go @@ -6,27 +6,27 @@ package storage import ( + "context" "testing" + "github.com/facebookincubator/go-belt/tool/logger" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + "github.com/stretchr/testify/require" ) type testJobStorageManagerFixture struct { - ctx xcontext.Context + ctx context.Context jobID types.JobID jobQuery *JobQuery } func mockJobStorageManagerData() *testJobStorageManagerFixture { query, _ := BuildJobQuery() - ctx, _ := logrusctx.NewContext(logger.LevelDebug) return &testJobStorageManagerFixture{ - ctx: ctx, + ctx: logging.WithBelt(context.Background(), logger.LevelDebug), jobID: types.JobID(0), jobQuery: query, } @@ -39,19 +39,19 @@ func TestJobStorageConsistency(t *testing.T) { var cases = []struct { name string - getter func(ctx xcontext.Context, jsm *JobStorageManager) + getter func(ctx context.Context, jsm *JobStorageManager) }{ { "TestGetJobRequest", - func(ctx xcontext.Context, jsm *JobStorageManager) { _, _ = jsm.GetJobRequest(ctx, f.jobID) }, + func(ctx context.Context, jsm *JobStorageManager) { _, _ = jsm.GetJobRequest(ctx, f.jobID) }, }, { "TestGetJobReport", - func(ctx xcontext.Context, jsm *JobStorageManager) { _, _ = jsm.GetJobReport(ctx, f.jobID) }, + func(ctx context.Context, jsm *JobStorageManager) { _, _ = jsm.GetJobReport(ctx, f.jobID) }, }, { "TestListJobs", - func(ctx xcontext.Context, jsm *JobStorageManager) { _, _ = jsm.ListJobs(ctx, f.jobQuery) }, + func(ctx context.Context, jsm *JobStorageManager) { _, _ = jsm.ListJobs(ctx, f.jobQuery) }, }, } diff --git a/pkg/storage/limits/limits_test.go b/pkg/storage/limits/limits_test.go index 9183e9dd..b85b9713 100644 --- a/pkg/storage/limits/limits_test.go +++ b/pkg/storage/limits/limits_test.go @@ -6,6 +6,7 @@ package limits_test import ( + "context" "encoding/json" "errors" "strings" @@ -13,16 +14,16 @@ import ( "testing" "time" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/pkg/api" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/jobmanager" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/pluginregistry" "github.com/linuxboot/contest/pkg/storage/limits" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + "github.com/linuxboot/contest/plugins/reporters/noop" "github.com/linuxboot/contest/plugins/targetmanagers/targetlist" "github.com/linuxboot/contest/plugins/testfetchers/literal" @@ -35,9 +36,7 @@ import ( // This tests are bad, because they touche so may things which are not related to storage limitations and // depend on order of checks in validation code, but this is the price of having them all in one package -var ( - ctx, _ = logrusctx.NewContext(logger.LevelDebug) -) +var ctx = logging.WithBelt(context.Background(), logger.LevelDebug) func TestServerID(t *testing.T) { _, err := api.New(api.OptionServerID(strings.Repeat("A", limits.MaxServerIDLen+1))) @@ -53,7 +52,7 @@ func TestRequestorName(t *testing.T) { apiInst := api.API{} timeout := time.Second err := apiInst.SendEvent(&api.Event{ - Context: xcontext.Background(), + Context: context.Background(), Msg: eventMsg{requestor: api.EventRequestor(strings.Repeat("A", limits.MaxRequestorNameLen+1))}, }, &timeout) assertLenError(t, "Requestor name", err) diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index e61fdf28..44e14f65 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -6,7 +6,9 @@ package storage import ( - "github.com/linuxboot/contest/pkg/xcontext" + "context" + + "github.com/linuxboot/contest/pkg/logging" ) // ConsistencyModel hints at whether queries should go to the primary database @@ -18,7 +20,9 @@ const ( ConsistentEventually ) -const consistencyModelKey = "storage_consistency_model" +type consistencyModelKeyT string + +const consistencyModelKey = consistencyModelKeyT("storage_consistency_model") // Storage defines the interface that storage engines must implement type Storage interface { @@ -47,9 +51,9 @@ type ResettableStorage interface { Reset() error } -func isStronglyConsistent(ctx xcontext.Context) bool { +func isStronglyConsistent(ctx context.Context) bool { value := ctx.Value(consistencyModelKey) - ctx.Debugf("consistency model check: %v", value) + logging.Debugf(ctx, "consistency model check: %v", value) switch model := value.(type) { case ConsistencyModel: @@ -60,6 +64,6 @@ func isStronglyConsistent(ctx xcontext.Context) bool { } } -func WithConsistencyModel(ctx xcontext.Context, model ConsistencyModel) xcontext.Context { - return xcontext.WithValue(ctx, consistencyModelKey, model) +func WithConsistencyModel(ctx context.Context, model ConsistencyModel) context.Context { + return context.WithValue(ctx, consistencyModelKey, model) } diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index e4e79e69..fd494c8a 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -6,13 +6,14 @@ package storage import ( + "context" "testing" "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/stretchr/testify/require" ) @@ -30,23 +31,23 @@ func (n *nullStorage) GetEventRequestCount() int { } // jobs interface -func (n *nullStorage) StoreJobRequest(ctx xcontext.Context, request *job.Request) (types.JobID, error) { +func (n *nullStorage) StoreJobRequest(ctx context.Context, request *job.Request) (types.JobID, error) { n.jobRequestCount++ return types.JobID(0), nil } -func (n *nullStorage) GetJobRequest(ctx xcontext.Context, jobID types.JobID) (*job.Request, error) { +func (n *nullStorage) GetJobRequest(ctx context.Context, jobID types.JobID) (*job.Request, error) { n.jobRequestCount++ return nil, nil } -func (n *nullStorage) StoreReport(ctx xcontext.Context, report *job.Report) error { +func (n *nullStorage) StoreReport(ctx context.Context, report *job.Report) error { n.jobRequestCount++ return nil } -func (n *nullStorage) GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.JobReport, error) { +func (n *nullStorage) GetJobReport(ctx context.Context, jobID types.JobID) (*job.JobReport, error) { n.jobRequestCount++ return nil, nil } -func (n *nullStorage) ListJobs(ctx xcontext.Context, query *JobQuery) ([]types.JobID, error) { +func (n *nullStorage) ListJobs(ctx context.Context, query *JobQuery) ([]types.JobID, error) { n.jobRequestCount++ return nil, nil } @@ -59,19 +60,19 @@ func (n *nullStorage) SetEngineVault(_ EngineVault) { } // events interface -func (n *nullStorage) StoreTestEvent(ctx xcontext.Context, event testevent.Event) error { +func (n *nullStorage) StoreTestEvent(ctx context.Context, event testevent.Event) error { n.eventRequestCount++ return nil } -func (n *nullStorage) GetTestEvents(ctx xcontext.Context, eventQuery *testevent.Query) ([]testevent.Event, error) { +func (n *nullStorage) GetTestEvents(ctx context.Context, eventQuery *testevent.Query) ([]testevent.Event, error) { n.eventRequestCount++ return nil, nil } -func (n *nullStorage) StoreFrameworkEvent(ctx xcontext.Context, event frameworkevent.Event) error { +func (n *nullStorage) StoreFrameworkEvent(ctx context.Context, event frameworkevent.Event) error { n.eventRequestCount++ return nil } -func (n *nullStorage) GetFrameworkEvent(ctx xcontext.Context, eventQuery *frameworkevent.Query) ([]frameworkevent.Event, error) { +func (n *nullStorage) GetFrameworkEvent(ctx context.Context, eventQuery *frameworkevent.Query) ([]frameworkevent.Event, error) { n.eventRequestCount++ return nil, nil } diff --git a/pkg/target/locker.go b/pkg/target/locker.go index d78fcb5d..cb9f1d23 100644 --- a/pkg/target/locker.go +++ b/pkg/target/locker.go @@ -6,10 +6,10 @@ package target import ( + "context" "time" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // locker defines the locking engine used by ConTest. @@ -34,7 +34,7 @@ type Locker interface { // Locks are reentrant, locking existing locks (with the same owner) // extends the deadline. // Passing empty list of targets is allowed and is a no-op. - Lock(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*Target) error + Lock(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*Target) error // TryLock attempts to lock up to limit of the given targets. // The job ID is the owner of the lock. @@ -44,18 +44,18 @@ type Locker interface { // Locks are reentrant, locking existing locks (with the same owner) // extends the deadline. // Passing empty list of targets is allowed and is a no-op. - TryLock(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*Target, limit uint) ([]string, error) + TryLock(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*Target, limit uint) ([]string, error) // Unlock unlocks the specificied targets if they are held by the given owner. // Unlock allows expired locks by the same owner but unlocking a target that wasn't locked // or that is now or has since been locked by a different owner is a failure. // Passing empty list of targets is allowed and is a no-op. - Unlock(ctx xcontext.Context, jobID types.JobID, targets []*Target) error + Unlock(ctx context.Context, jobID types.JobID, targets []*Target) error // RefreshLocks extends existing locks on the given targets for the specified duration. // This call will fail if even a single target is not currently locked by the specified job. // Passing empty list of targets is allowed and is a no-op. - RefreshLocks(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*Target) error + RefreshLocks(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*Target) error // Close finalizes the locker and releases resources. // No API calls must be in flight when this is invoked or afterwards. diff --git a/pkg/target/targetmanager.go b/pkg/target/targetmanager.go index 36280707..4bf4b8f3 100644 --- a/pkg/target/targetmanager.go +++ b/pkg/target/targetmanager.go @@ -6,10 +6,10 @@ package target import ( + "context" "time" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // TargetManagerFactory is a type representing a function which builds @@ -25,8 +25,8 @@ type TargetManagerLoader func() (string, TargetManagerFactory) type TargetManager interface { ValidateAcquireParameters([]byte) (interface{}, error) ValidateReleaseParameters([]byte) (interface{}, error) - Acquire(ctx xcontext.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl Locker) ([]*Target, error) - Release(ctx xcontext.Context, jobID types.JobID, targets []*Target, parameters interface{}) error + Acquire(ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl Locker) ([]*Target, error) + Release(ctx context.Context, jobID types.JobID, targets []*Target, parameters interface{}) error } // TargetManagerBundle bundles the selected TargetManager together with its diff --git a/pkg/test/fetcher.go b/pkg/test/fetcher.go index ac0da0fe..6c57f457 100644 --- a/pkg/test/fetcher.go +++ b/pkg/test/fetcher.go @@ -5,9 +5,7 @@ package test -import ( - "github.com/linuxboot/contest/pkg/xcontext" -) +import "context" // TestFetcherFactory is a type representing a function which builds // a TestFetcher @@ -20,8 +18,8 @@ type TestFetcherLoader func() (string, TestFetcherFactory) // TestFetcher is an interface used to get the test to run on the selected // hosts. type TestFetcher interface { - ValidateFetchParameters(xcontext.Context, []byte, bool) (interface{}, error) - Fetch(xcontext.Context, interface{}) (string, []*TestStepDescriptor, error) + ValidateFetchParameters(context.Context, []byte, bool) (interface{}, error) + Fetch(context.Context, interface{}) (string, []*TestStepDescriptor, error) } // TestFetcherBundle bundles the selected TestFetcher together with its acquire diff --git a/pkg/test/step.go b/pkg/test/step.go index 6c48ae01..260729c4 100644 --- a/pkg/test/step.go +++ b/pkg/test/step.go @@ -6,6 +6,7 @@ package test import ( + "context" "encoding/json" "errors" "fmt" @@ -15,7 +16,6 @@ import ( "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" - "github.com/linuxboot/contest/pkg/xcontext" ) // TestStepParameters represents the parameters that a TestStep should consume @@ -137,12 +137,12 @@ type TestStep interface { // Name returns the name of the step Name() string // Run runs the test step. The test step is expected to be synchronous. - Run(ctx xcontext.Context, ch TestStepChannels, ev testevent.Emitter, + Run(ctx context.Context, ch TestStepChannels, ev testevent.Emitter, stepsVars StepsVariables, params TestStepParameters, resumeState json.RawMessage) (json.RawMessage, error) // ValidateParameters checks that the parameters are correct before passing // them to Run. - ValidateParameters(ctx xcontext.Context, params TestStepParameters) error + ValidateParameters(ctx context.Context, params TestStepParameters) error } var identifierRegexPattern *regexp.Regexp diff --git a/pkg/types/types.go b/pkg/types/types.go index e615d964..7de1ee7c 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -6,9 +6,8 @@ package types import ( + "context" "strconv" - - "github.com/linuxboot/contest/pkg/xcontext" ) // JobID represents a unique job identifier @@ -35,8 +34,8 @@ func (v JobOwnerID) String() string { type key string const ( - KeyJobID = key("job_id") - KeyRunID = key("run_id") + KeyJobID = key("job_id") + KeyRunID = key("run_id") KeyJobOwnerID = key("job_owner_id") ) @@ -44,7 +43,7 @@ const ( // for plugins which need to know which job they are running. // Not all context object everywhere have this set, but this is // guaranteed to work in TargetManagers, TestSteps and Reporters -func JobIDFromContext(ctx xcontext.Context) (JobID, bool) { +func JobIDFromContext(ctx context.Context) (JobID, bool) { v, ok := ctx.Value(KeyJobID).(JobID) return v, ok } @@ -52,7 +51,7 @@ func JobIDFromContext(ctx xcontext.Context) (JobID, bool) { // RunIDFromContext is a helper to get the RunID. // Not all context object everywhere have this set, but this is // guaranteed to work in TargetManagers, TestSteps and RunReporters -func RunIDFromContext(ctx xcontext.Context) (RunID, bool) { +func RunIDFromContext(ctx context.Context) (RunID, bool) { v, ok := ctx.Value(KeyRunID).(RunID) return v, ok } @@ -60,7 +59,7 @@ func RunIDFromContext(ctx xcontext.Context) (RunID, bool) { // JobOwnerIDFromContext is a helper to get the JobOwnerID. // Not all context object everywhere have this set, but this is // guaranteed to work in TargetManagers, TestSteps and RunReporters -func JobOwnerIDFromContext(ctx xcontext.Context) (JobOwnerID, bool) { +func JobOwnerIDFromContext(ctx context.Context) (JobOwnerID, bool) { v, ok := ctx.Value(KeyJobOwnerID).(JobOwnerID) return v, ok } diff --git a/pkg/xcontext/buildinfo/vars.go b/pkg/xcontext/buildinfo/vars.go deleted file mode 100644 index b594229e..00000000 --- a/pkg/xcontext/buildinfo/vars.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package buildinfo - -var ( - // BuildMode is usually "prod" or "dev". - BuildMode string - - // BuildDate is when the binary was built. - BuildDate string - - // Revision is the commit. - Revision string -) diff --git a/pkg/xcontext/bundles/logrusctx/compact_text_formatter.go b/pkg/xcontext/bundles/logrusctx/compact_text_formatter.go deleted file mode 100644 index d24ca72c..00000000 --- a/pkg/xcontext/bundles/logrusctx/compact_text_formatter.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logrusctx - -import ( - "fmt" - "path/filepath" - "sort" - "strings" - "time" - - "github.com/sirupsen/logrus" -) - -var logLevelSymbol []byte - -func init() { - logLevelSymbol = make([]byte, len(logrus.AllLevels)+1) - for _, level := range logrus.AllLevels { - logLevelSymbol[level] = strings.ToUpper(level.String()[:1])[0] - } -} - -type CompactTextFormatter struct { - TimestampFormat string -} - -func (f *CompactTextFormatter) Format(entry *logrus.Entry) ([]byte, error) { - var str, header strings.Builder - timestamp := time.RFC3339 - if f.TimestampFormat != "" { - timestamp = f.TimestampFormat - } - header.WriteString(fmt.Sprintf("%s %c", - entry.Time.Format(timestamp), - logLevelSymbol[entry.Level], - )) - if entry.Caller != nil { - header.WriteString(fmt.Sprintf(" %s:%d", filepath.Base(entry.Caller.File), entry.Caller.Line)) - } - str.WriteString(fmt.Sprintf("[%s] %s", - header.String(), - entry.Message, - )) - - keys := make([]string, 0, len(entry.Data)) - for key := range entry.Data { - keys = append(keys, key) - } - sort.Strings(keys) - - for _, key := range keys { - str.WriteString(fmt.Sprintf("\t%s=%s", key, entry.Data[key])) - } - - str.WriteByte('\n') - return []byte(str.String()), nil -} diff --git a/pkg/xcontext/bundles/logrusctx/compact_text_formatter_test.go b/pkg/xcontext/bundles/logrusctx/compact_text_formatter_test.go deleted file mode 100644 index ef311843..00000000 --- a/pkg/xcontext/bundles/logrusctx/compact_text_formatter_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logrusctx - -import ( - "runtime" - "testing" - "time" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" -) - -func TestCompactTextFormatterFormat(t *testing.T) { - formatter := &CompactTextFormatter{ - TimestampFormat: "05.999999999", - } - - b, err := formatter.Format(&logrus.Entry{ - Data: map[string]interface{}{ - "key0": "value0", - "key1": "value1", - }, - Level: logrus.ErrorLevel, - Time: time.Unix(1, 2), - Caller: &runtime.Frame{ - Function: "func", - File: "/directory/file", - Line: 3, - }, - Message: "message", - }) - require.NoError(t, err) - require.Equal(t, "[01.000000002 E file:3] message\tkey0=value0\tkey1=value1\n", string(b)) -} diff --git a/pkg/xcontext/bundles/logrusctx/new_context.go b/pkg/xcontext/bundles/logrusctx/new_context.go deleted file mode 100644 index 368fbff9..00000000 --- a/pkg/xcontext/bundles/logrusctx/new_context.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logrusctx - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - - "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" - - "github.com/linuxboot/contest/pkg/loggerhook" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles" - "github.com/linuxboot/contest/pkg/xcontext/logger" - logrusadapter "github.com/linuxboot/contest/pkg/xcontext/logger/logadapter/logrus" - prometheusadapter "github.com/linuxboot/contest/pkg/xcontext/metrics/prometheus" -) - -// NewContext is a simple-to-use function to create a context.Context with canceling explicitly -// using logrus as the logger. -// -// Note: the upstream "logrus" is in maintenance-mode. -// A quote from the README.md: -// -// > Logrus is in maintenance-mode. We will not be introducing new features. -// > It's simply too hard to do in a way that won't break many people's -// > projects, which is the last thing you want from your Logging library (again...). -// > -// > This does not mean Logrus is dead. Logrus will continue to be maintained -// > for security, (backwards compatible) bug fixes, and performance (where we -// > are limited by the interface). -// > -// > I believe Logrus' biggest contribution is to have played a part in today's -// > widespread use of structured logging in Golang. There doesn't seem to be -// > a reason to do a major, breaking iteration into Logrus V2, since the -// > fantastic Go community has built those independently. Many fantastic -// > alternatives have sprung up. Logrus would look like those, had it been -// > re-designed with what we know about structured logging in Go today. -// > Check out, for example, Zerolog, Zap, and Apex. -func NewContext(logLevel logger.Level, opts ...bundles.Option) (xcontext.Context, context.CancelFunc) { - cfg := bundles.GetConfig(opts...) - loggerRaw := logrus.New() - loggerRaw.SetLevel(logrusadapter.Adapter.Level(logLevel)) - loggerRaw.ReportCaller = cfg.LoggerReportCaller - entry := logrus.NewEntry(loggerRaw) - - var callerFormatter func(frame *runtime.Frame) (function string, file string) - if !cfg.VerboseCaller { - callerFormatter = func(frame *runtime.Frame) (function string, file string) { - if frame == nil { - return - } - file = fmt.Sprintf("%s:%d", filepath.Base(frame.File), frame.Line) - return - } - } - switch cfg.Format { - case bundles.LogFormatJSON: - entry.Logger.SetFormatter(&logrus.JSONFormatter{ - TimestampFormat: cfg.TimestampFormat, - CallerPrettyfier: callerFormatter, - }) - case bundles.LogFormatPlainTextCompact: - entry.Logger.SetFormatter(&CompactTextFormatter{ - TimestampFormat: cfg.TimestampFormat, - }) - default: - entry.Logger.SetFormatter(&logrus.TextFormatter{ - TimestampFormat: cfg.TimestampFormat, - FullTimestamp: cfg.TimestampFormat != "", - CallerPrettyfier: callerFormatter, - }) - } - - prometheusRegistry := prometheus.NewRegistry() - ctx, cancel := xcontext.WithCancel( - xcontext.NewContext( - context.Background(), "", - logrusadapter.Adapter.Convert(entry), - prometheusadapter.New(prometheusRegistry, prometheusRegistry), - cfg.Tracer, - nil, nil, - ), - ) - - if cfg.HttpLoggerConfig.Addr != "" { - httpHook, err := loggerhook.NewHttpHook(cfg.HttpLoggerConfig) - if err == nil { - // clean the http logger on ctx canceling - go func() { - <-ctx.Done() - httpHook.Close() - }() - - entry.Logger.AddHook(httpHook) - } else { - fmt.Fprintf(os.Stderr, "Error while creating http logger hook: %v", err) - } - } - return ctx, cancel -} diff --git a/pkg/xcontext/bundles/options.go b/pkg/xcontext/bundles/options.go deleted file mode 100644 index 04c8336b..00000000 --- a/pkg/xcontext/bundles/options.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package bundles - -import ( - "github.com/linuxboot/contest/pkg/loggerhook" - "github.com/linuxboot/contest/pkg/xcontext" -) - -// Option is a modifier of what context to construct. -type Option interface { - apply(cfg *Config) -} - -// OptionLoggerReportCaller defines if it is required to determine -// source-code file name and line and report it to logs. -// It negatively affects performance of logging. -type OptionLoggerReportCaller bool - -func (opt OptionLoggerReportCaller) apply(cfg *Config) { - cfg.LoggerReportCaller = bool(opt) -} - -// OptionTracerReportCaller the same as OptionLoggerReportCaller, but -// for a tracer. -type OptionTracerReportCaller bool - -func (opt OptionTracerReportCaller) apply(cfg *Config) { - cfg.TracerReportCaller = bool(opt) -} - -// LogFormat is a selector of an output format. -type LogFormat int - -const ( - // LogFormatPlainText means to write logs as a plain text. - LogFormatPlainText = LogFormat(iota) - - // LogFormatPlainTextCompact means to write logs as a compact plain text. - // - // Falls back to LogFormatPlainText if the compact format is not supported. - LogFormatPlainTextCompact - - // LogFormatJSON means to write logs as JSON objects. - LogFormatJSON -) - -// OptionLogFormat defines the format for logs. -type OptionLogFormat LogFormat - -func (opt OptionLogFormat) apply(cfg *Config) { - cfg.Format = LogFormat(opt) -} - -// OptionTracer defines if a tracer should be added to the context. -type OptionTracer struct { - xcontext.Tracer -} - -func (opt OptionTracer) apply(cfg *Config) { - cfg.Tracer = opt.Tracer -} - -// OptionTimestampFormat defines the format of timestamps while logging. -type OptionTimestampFormat string - -func (opt OptionTimestampFormat) apply(cfg *Config) { - cfg.TimestampFormat = string(opt) -} - -// OptionHttpLoggerConfig is used to define the different config for the http logger -type OptionHttpLoggerConfig loggerhook.Config - -func (opt OptionHttpLoggerConfig) apply(cfg *Config) { - cfg.HttpLoggerConfig = loggerhook.Config(opt) -} - -// Config is a configuration state resulted from Option-s. -type Config struct { - LoggerReportCaller bool - TracerReportCaller bool - TimestampFormat string - VerboseCaller bool - Tracer xcontext.Tracer - Format LogFormat - // http logger specific options - HttpLoggerConfig loggerhook.Config -} - -// GetConfig processes passed Option-s and returns the resulting state as Config. -func GetConfig(opts ...Option) Config { - cfg := Config{ - LoggerReportCaller: true, - TracerReportCaller: true, - } - for _, opt := range opts { - opt.apply(&cfg) - } - return cfg -} diff --git a/pkg/xcontext/bundles/zapctx/new_context.go b/pkg/xcontext/bundles/zapctx/new_context.go deleted file mode 100644 index 3007dbc0..00000000 --- a/pkg/xcontext/bundles/zapctx/new_context.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package zapctx - -import ( - "context" - "time" - - "github.com/prometheus/client_golang/prometheus" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles" - "github.com/linuxboot/contest/pkg/xcontext/logger" - zapadapter "github.com/linuxboot/contest/pkg/xcontext/logger/logadapter/zap" - prometheusadapter "github.com/linuxboot/contest/pkg/xcontext/metrics/prometheus" -) - -// NewContext is a simple-to-use function to create a context.Context -// using zap as the logger. -// -// See also: https://github.com/uber-go/zap -func NewContext(logLevel logger.Level, opts ...bundles.Option) xcontext.Context { - cfg := bundles.GetConfig(opts...) - loggerCfg := zap.Config{ - Level: zap.NewAtomicLevelAt(zapadapter.Adapter.Level(logLevel)), - Development: true, - Encoding: "console", - EncoderConfig: zap.NewProductionEncoderConfig(), - OutputPaths: []string{"stderr"}, - ErrorOutputPaths: []string{"stderr"}, - } - switch cfg.Format { - case bundles.LogFormatPlainText, bundles.LogFormatPlainTextCompact: - loggerCfg.Encoding = "console" - case bundles.LogFormatJSON: - loggerCfg.Encoding = "json" - } - if cfg.TimestampFormat != "" { - loggerCfg.EncoderConfig.EncodeTime = timeEncoder(cfg.TimestampFormat) - } - // TODO: cfg.VerboseCaller is currently ignored, fix it. - var zapOpts []zap.Option - stdCtx := context.Background() - loggerRaw, err := loggerCfg.Build(zapOpts...) - if err != nil { - panic(err) - } - loggerInstance := logger.ConvertLogger(loggerRaw.Sugar()) - prometheusRegistry := prometheus.NewRegistry() - ctx := xcontext.NewContext( - stdCtx, "", - loggerInstance, prometheusadapter.New(prometheusRegistry, prometheusRegistry), cfg.Tracer, - nil, nil) - return ctx -} - -func timeEncoder(layout string) func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { - return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { - type appendTimeEncoder interface { - AppendTimeLayout(time.Time, string) - } - - if enc, ok := enc.(appendTimeEncoder); ok { - enc.AppendTimeLayout(t, layout) - return - } - - enc.AppendString(t.Format(layout)) - } -} diff --git a/pkg/xcontext/context.go b/pkg/xcontext/context.go deleted file mode 100644 index 605d337e..00000000 --- a/pkg/xcontext/context.go +++ /dev/null @@ -1,582 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package xcontext implements a generic context with integrated logger, -// metrics, tracer and recoverer. - -package xcontext - -import ( - "context" - "os" - "os/user" - "runtime" - "sync" - "time" - - "github.com/google/uuid" - "github.com/linuxboot/contest/pkg/xcontext/buildinfo" - "github.com/linuxboot/contest/pkg/xcontext/fields" - "github.com/linuxboot/contest/pkg/xcontext/logger" - "github.com/linuxboot/contest/pkg/xcontext/metrics" -) - -var ( - // DefaultLogTraceID defines if traceID should be logged by default. - // - // If it is disabled, then logging of traceID for a specific - // context could be enforced this way: - // ctx = ctx.WithField("traceID", ctx.TraceID()) - DefaultLogTraceID = false - - // DefaultLogHostname defines if hostname should be logged by default. - DefaultLogHostname = false - - // DefaultLogUsername defines if hostname should be logged by default. - DefaultLogUsername = false -) - -// Fields is a multiple of fields which are attached to logger/tracer messages. -type Fields = fields.Fields - -// TraceID is a passthrough ID used to track a sequence of events across -// multiple processes/services. It is supposed to pass it with Thrift-requests -// through a HTTP-header "X-Trace-Id". -type TraceID string - -// String implements fmt.Stringer. -func (traceID TraceID) String() string { - return string(traceID) -} - -// NewTraceID returns a new random unique TraceID. -func NewTraceID() TraceID { - return TraceID(uuid.New().String()) -} - -// Logger is an abstract logger used by a Context. -type Logger = logger.Logger - -// Context is a generic extension over context.Context with provides also: -// * Logger which allows to send messages to a log. -// * Metrics which allows to update metrics. -// * Tracer which allows to log time spans (to profile delays of the application). -// * TraceID to track across multiple processes. -type Context interface { - context.Context - logger.MinimalLogger - - // Clone just returns a copy of the Context safe to be modified. - Clone() Context - - // TraceID returns the TraceID attached to the Context - TraceID() TraceID - - // WithTraceID returns a clone of the Context, but with passed TraceID. - WithTraceID(TraceID) Context - - // Logger returns the Logger handler attached to the Context - Logger() Logger - - // WithLogger returns a clone of the Context, but with passed Logger handler. - WithLogger(logger Logger) Context - - // Metrics returns the Metrics handler attached to the Context. - Metrics() Metrics - - // WithMetrics returns a clone of the Context, but with passed Metrics handler. - WithMetrics(Metrics) Context - - // Tracer returns the Tracer handler attached to the Context. - Tracer() Tracer - - // WithTracer returns a clone of the Context, but with passed Tracer handler. - WithTracer(Tracer) Context - - // WithTag returns a clone of the context, but with added tag with key - // "key" and value "value". - // - // Note about Tag vs Field: Tag is supposed to be used for limited amount - // of values, while Field is supposed to be used for arbitrary values. - // Basically currentTags are used for everything (Logger, Metrics and Tracer), - // while Fields are used only for Logger and Tracer. - // We cannot use arbitrary values for Metrics because it will create - // "infinite" amount of metrics. - WithTag(key string, value interface{}) Context - - // WithTags returns a clone of the context, but with added tags with - // key and values according to map "Fields". - // - // See also WithTag. - WithTags(Fields) Context - - // WithField returns a clone of the context, but with added field with key - // "key" and value "value". - // - // See also WithTag. - WithField(key string, value interface{}) Context - - // WithFields returns a clone of the context, but with added fields with - // key and values according to map "Fields". - // - // See also WithTag. - WithFields(Fields) Context - - // Until works similar to Done(), but it is possible to specify specific - // signal to wait for. - // - // If err is nil, then waits for any event. - Until(err error) <-chan struct{} - - // StdCtxUntil is the same as Until, but returns a standard context - // instead of a channel. - StdCtxUntil(err error) context.Context - - // IsSignaledWith returns true if the context received a cancel - // or a notification signal equals to any of passed ones. - // - // If errs is empty, then returns true if the context received any - // cancel or notification signal. - IsSignaledWith(errs ...error) bool - - // Notifications returns all the received notifications (including events - // received by parents). - // - // This is a read-only value, do not modify it. - Notifications() []error - - // Recover is use instead of standard "recover()" to also log the panic. - Recover() interface{} - - // private: - - resetEventHandler() - addEventHandler() *eventHandler - addValue(key, value interface{}) - cloneWithStdContext(context.Context) Context -} - -// TimeSpan is the object represents the time span to be reported by a Tracer. -type TimeSpan interface { - // Finish sets the end time of the span to time.Now() and sends - // the time span to the log of the Tracer. - Finish() time.Duration -} - -// Tracer is a handler responsible to track time spans. -// -// Is supposed to be used this way: -// -// defer ctx.Tracer().StartSpan("some label here").Finish() -type Tracer interface { - // StartSpan creates a time span to be reported (if Finish will be called) - // which starts counting time since the moment StartSpan was called. - StartSpan(label string) TimeSpan - - // WithField returns a Tracer with an added field to be reported with the time span (when Finish will be called). - WithField(key string, value interface{}) Tracer - - // WithField returns a Tracer with added fields to be reported with the time span (when Finish will be called). - WithFields(Fields) Tracer -} - -// Metrics is a handler of metrics (like Prometheus, ODS) -type Metrics = metrics.Metrics - -var _ context.Context = &ctxValue{} - -type debugTools struct { - loggerInstance Logger - metricsInstance Metrics - tracerInstance Tracer - pendingFields fields.PendingFields - pendingTags fields.PendingFields -} - -func (tools *debugTools) Clone() *debugTools { - return &debugTools{ - loggerInstance: tools.loggerInstance, - metricsInstance: tools.metricsInstance, - tracerInstance: tools.tracerInstance, - pendingFields: tools.pendingFields.Clone(), - pendingTags: tools.pendingTags.Clone(), - } -} - -type ctxValue struct { - mutationSyncer sync.Once - traceIDValue TraceID - - debugTools *debugTools - valuesHandler - *eventHandler - - // parent is used only to warn the GC to do not run finalizers for eventHandlers-s - // of parents. - parent *ctxValue -} - -var ( - background = NewContext(context.Background(), "", nil, nil, nil, nil, nil) -) - -// Background is analog of standard context.Context which returns just a simple dummy context which does nothing. -func Background() Context { - return background -} - -var ( - hostname string - curUser *user.User -) - -func init() { - hostname, _ = os.Hostname() - curUser, _ = user.Current() -} - -// Extend converts a standard context to an extended one -func Extend(parent context.Context) Context { - return NewContext(parent, "", nil, nil, nil, nil, nil) -} - -// NewContext is a customizable constructor of a context. -// -// It is not intended to be called by an user not familiar with this package, -// there are special helpers for that, see for example bundles.NewContextWithLogrus. -func NewContext( - stdCtx context.Context, - traceID TraceID, - loggerInstance Logger, - metrics Metrics, - tracer Tracer, - tags Fields, - fields Fields, -) Context { - if traceID == "" { - traceID = NewTraceID() - } - if loggerInstance == nil { - loggerInstance = logger.Dummy() - } - - ctx := &ctxValue{ - traceIDValue: traceID, - debugTools: &debugTools{ - loggerInstance: loggerInstance, - metricsInstance: metrics, - tracerInstance: tracer, - }, - } - - if stdCtx != nil && stdCtx != context.Background() { - ctx = ctx.cloneWithStdContext(stdCtx).(*ctxValue) - } - - if tags == nil { - tags = Fields{} - if buildinfo.BuildMode != "" { - tags["buildMode"] = buildinfo.BuildMode - } - if buildinfo.BuildDate != "" { - tags["buildDate"] = buildinfo.BuildDate - } - if buildinfo.Revision != "" { - tags["revision"] = buildinfo.Revision - } - if DefaultLogHostname && hostname != "" { - tags["hostname"] = hostname - } - if DefaultLogUsername && curUser != nil { - tags["username"] = curUser.Name - } - } - if len(tags) > 0 { - ctx.debugTools.pendingTags.AddMultiple(tags) - } - - if fields == nil { - fields = Fields{} - } - if DefaultLogTraceID { - fields["traceID"] = traceID - } - ctx.debugTools.pendingFields.AddMultiple(fields) - - return ctx -} - -type CancelFunc = context.CancelFunc - -func (ctx *ctxValue) clone() *ctxValue { - return &ctxValue{ - traceIDValue: ctx.traceIDValue, - debugTools: ctx.loadDebugTools().Clone(), - valuesHandler: ctx.valuesHandler, - eventHandler: ctx.eventHandler, - parent: ctx, - } -} - -// Clone returns a derivative context in a new scope. Modifications of -// this context will not affect the original one. -func (ctx *ctxValue) Clone() Context { - return ctx.clone() -} - -// TraceID returns the tracing ID of the context. The tracing ID is -// the passing-through ID which is used to identify a flow across multiple -// services. -func (ctx *ctxValue) TraceID() TraceID { - return ctx.traceIDValue -} - -// WithTraceID returns a derivative context with passed tracing ID. -func (ctx *ctxValue) WithTraceID(traceID TraceID) Context { - ctxClone := ctx.clone() - ctxClone.traceIDValue = traceID - return ctxClone.WithField("traceID", traceID) -} - -func (ctx *ctxValue) considerPendingTags() { - oldDebugTools := ctx.loadDebugTools() - if oldDebugTools.pendingTags.Slice == nil { - return - } - - // considerPendingTags could be called simultaneously with - // pendingTags.Clone. - // - // Therefore storePendingTags is in the bottom. - - pendingTags := oldDebugTools.pendingTags.Compile() - - newDebugTools := *oldDebugTools - - if oldDebugTools.loggerInstance != nil { - newDebugTools.loggerInstance = oldDebugTools.loggerInstance.WithFields(pendingTags) - } - if oldDebugTools.tracerInstance != nil { - newDebugTools.tracerInstance = oldDebugTools.tracerInstance.WithFields(pendingTags) - } - if oldDebugTools.metricsInstance != nil { - newDebugTools.metricsInstance = oldDebugTools.metricsInstance.WithTags(pendingTags) - } - - // reset pending tags - newDebugTools.pendingTags = fields.PendingFields{} - - // store - ctx.storeDebugTools(&newDebugTools) -} - -func (ctx *ctxValue) considerPendingFields() { - oldDebugTools := ctx.loadDebugTools() - if oldDebugTools.pendingFields.Slice == nil { - return - } - - // considerPendingFields could be called simultaneously with - // pendingFields.Clone. - // - // Therefore storePendingFields is in the bottom. - - pendingFields := oldDebugTools.pendingFields.Compile() - - newDebugTools := *oldDebugTools - - if oldDebugTools.loggerInstance != nil { - newDebugTools.loggerInstance = oldDebugTools.loggerInstance.WithFields(pendingFields) - } - if oldDebugTools.tracerInstance != nil { - newDebugTools.tracerInstance = oldDebugTools.tracerInstance.WithFields(pendingFields) - } - - // reset pending fields - newDebugTools.pendingFields = fields.PendingFields{} - - // store - ctx.storeDebugTools(&newDebugTools) -} - -func (ctx *ctxValue) considerPending() { - ctx.considerPendingTags() - ctx.considerPendingFields() -} - -// Logger returns a Logger. -func (ctx *ctxValue) Logger() Logger { - loggerInstance := ctx.loadDebugTools().loggerInstance - if loggerInstance == nil { - return nil - } - ctx.mutationSyncer.Do(func() { - ctx.considerPending() - loggerInstance = ctx.loadDebugTools().loggerInstance - }) - return loggerInstance -} - -// WithLogger returns a derivative context with the Logger replaced with -// the passed one. -func (ctx *ctxValue) WithLogger(logger Logger) Context { - ctxClone := ctx.clone() - ctxClone.debugTools.loggerInstance = logger - return ctxClone -} - -// Metrics returns a Metrics handler. -func (ctx *ctxValue) Metrics() Metrics { - metricsInstance := ctx.loadDebugTools().metricsInstance - if metricsInstance == nil { - return nil - } - ctx.mutationSyncer.Do(func() { - ctx.considerPending() - metricsInstance = ctx.loadDebugTools().metricsInstance - }) - return metricsInstance -} - -// WithMetrics returns a derivative context with the Metrics handler replaced with -// the passed one. -func (ctx *ctxValue) WithMetrics(metrics Metrics) Context { - ctxClone := ctx.clone() - ctxClone.debugTools.metricsInstance = metrics - return ctxClone -} - -// Tracer returns a Tracer handler. -func (ctx *ctxValue) Tracer() Tracer { - tracerInstance := ctx.loadDebugTools().tracerInstance - if tracerInstance == nil { - return dummyTracerInstance - } - ctx.mutationSyncer.Do(func() { - ctx.considerPending() - tracerInstance = ctx.loadDebugTools().tracerInstance - }) - return tracerInstance -} - -// WithTracer returns a derivative context with the Tracer handler replaced with -// the passed one. -func (ctx *ctxValue) WithTracer(tracer Tracer) Context { - ctxClone := ctx.clone() - ctxClone.debugTools.tracerInstance = tracer - return ctxClone -} - -// WithTracer returns a derivative context with an added tag. -func (ctx *ctxValue) WithTag(key string, value interface{}) Context { - ctxClone := ctx.clone() - ctxClone.debugTools.pendingTags.AddOne(key, value) - return ctxClone -} - -// WithTracer returns a derivative context with added tags. -func (ctx *ctxValue) WithTags(fields Fields) Context { - ctxClone := ctx.clone() - ctxClone.debugTools.pendingTags.AddMultiple(fields) - return ctxClone -} - -// WithTracer returns a derivative context with an added field. -func (ctx *ctxValue) WithField(key string, value interface{}) Context { - ctxClone := ctx.clone() - ctxClone.debugTools.pendingFields.AddOne(key, value) - return ctxClone -} - -// WithTracer returns a derivative context with added fields. -func (ctx *ctxValue) WithFields(fields Fields) Context { - ctxClone := ctx.clone() - ctxClone.debugTools.pendingFields.AddMultiple(fields) - return ctxClone -} - -// Recover if supposed to be used in defer-s to log and stop panics. -func (ctx *ctxValue) Recover() interface{} { - // TODO: this is a very naive implementation and there's no way to - // inject another handler, yet. - // It makes sense to design and introduce a Sentry-like handling - // of panics. - r := recover() - if r != nil { - b := make([]byte, 65536) - n := runtime.Stack(b, false) - b = b[:n] - ctx.Errorf("received panic: %v\n%s\n", r, b) - } - return r -} - -func (ctx *ctxValue) Value(key interface{}) interface{} { - if ctx.valuesHandler == nil { - return nil - } - return ctx.valuesHandler.Value(key) -} - -// LoggerFrom returns a logger from a context.Context if can find any. And -// returns a dummy logger (which does nothing) if wasn't able to find any. -func LoggerFrom(stdCtx context.Context) Logger { - if stdCtx == nil { - return logger.Dummy() - } - - ctx, ok := stdCtx.(Context) - if !ok { - return logger.Dummy() - } - - return ctx.Logger() -} - -// StdCtxUntil is the same as Until, but returns a standard context -// instead of a channel. -func (ctx *ctxValue) StdCtxUntil(err error) context.Context { - child := ctx.clone() - if child.eventHandler == nil { - return child - } - - // Chain of thoughts: - // * Implement resulting context.Context through an xcontext instance. - // * It will require to wait until ctx.Until(err), but it will require - // an additional routine. - // * We do not want to leak routines, therefore we cancel the routine - // if resulting ctx.Done() is not reachable anymore (GC-ed). Thus - // we exploit SetFinalizer. - // * To make SetFinalizer work we need to have different cancelSignal-s - // in the waiting routine and in the finalizer, otherwise the SetFinalizer - // will wait for a cancelSignal which will be always reachable from the - // goroutine. - // * To make different cancelSignals we create two eventHandlers: one - // will be monitored by SetFinalizer (childHandler), the other will be - // cancelled by the goroutine (parentHandler). And we will return - // the childHandler. - - child.eventHandler = nil - parentHandler := child.addEventHandler() - - childHandler := child.addEventHandler() - - garbageCollected := make(chan struct{}) - runtime.SetFinalizer(&childHandler.cancelSignal, func(*chan struct{}) { - close(garbageCollected) - }) - - go func() { - select { - case <-garbageCollected: - return - case <-ctx.Until(err): - parentHandler.cancel(ErrCanceled) - } - }() - - return child -} diff --git a/pkg/xcontext/context_atomic.go b/pkg/xcontext/context_atomic.go deleted file mode 100644 index a21b2c29..00000000 --- a/pkg/xcontext/context_atomic.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "sync/atomic" - "unsafe" -) - -func (ctx *ctxValue) loadDebugTools() *debugTools { - return (*debugTools)(atomic.LoadPointer((*unsafe.Pointer)((unsafe.Pointer)(&ctx.debugTools)))) -} - -func (ctx *ctxValue) storeDebugTools(newDebugTools *debugTools) { - atomic.StorePointer((*unsafe.Pointer)((unsafe.Pointer)(&ctx.debugTools)), unsafe.Pointer(newDebugTools)) -} diff --git a/pkg/xcontext/context_bench_test.go b/pkg/xcontext/context_bench_test.go deleted file mode 100644 index 570e4ed6..00000000 --- a/pkg/xcontext/context_bench_test.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package xcontext implements a generic context with integrated logger, -// metrics, tracer and recoverer. -package xcontext - -import ( - "context" - "testing" -) - -var ( - testCtx context.Context -) - -func BenchmarkNewContext(b *testing.B) { - bgCtx := context.Background() - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - NewContext(bgCtx, "", nil, nil, nil, nil, nil) - } -} - -func BenchmarkWithCancel(b *testing.B) { - ctx := NewContext(context.Background(), "", nil, nil, nil, nil, nil).WithTag("1", 2) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - WithCancel(ctx) - } -} - -func BenchmarkStdWithCancel(b *testing.B) { - ctx := context.Background() - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, c := context.WithCancel(ctx) - // fighting govet: - _ = c - } -} - -func BenchmarkCtxValue_Clone(b *testing.B) { - ctx := NewContext(context.Background(), "", nil, nil, nil, nil, nil).WithTag("1", 2) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - testCtx = ctx.Clone() - } -} - -func BenchmarkCtxValue_WithTag(b *testing.B) { - ctx := NewContext(context.Background(), "", nil, nil, nil, nil, nil).WithTag("1", 2) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - testCtx = ctx.WithTag("2", 3) - } -} - -func BenchmarkCtxValue_WithTags(b *testing.B) { - ctx := NewContext(context.Background(), "", nil, nil, nil, nil, nil).WithTag("1", 2) - tags := Fields{"2": 3} - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - testCtx = ctx.WithTags(tags) - } -} diff --git a/pkg/xcontext/context_logger.go b/pkg/xcontext/context_logger.go deleted file mode 100644 index 10c97146..00000000 --- a/pkg/xcontext/context_logger.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "github.com/linuxboot/contest/pkg/xcontext/logger" -) - -var _ logger.MinimalLogger = &ctxValue{} - -func (ctx *ctxValue) Debugf(format string, args ...interface{}) { - ctx.Logger().Debugf(format, args...) -} - -func (ctx *ctxValue) Infof(format string, args ...interface{}) { - ctx.Logger().Infof(format, args...) -} - -func (ctx *ctxValue) Warnf(format string, args ...interface{}) { - ctx.Logger().Warnf(format, args...) -} - -func (ctx *ctxValue) Errorf(format string, args ...interface{}) { - ctx.Logger().Errorf(format, args...) -} - -func (ctx *ctxValue) Panicf(format string, args ...interface{}) { - ctx.Logger().Panicf(format, args...) -} - -func (ctx *ctxValue) Fatalf(format string, args ...interface{}) { - ctx.Logger().Panicf(format, args...) -} diff --git a/pkg/xcontext/context_test.go b/pkg/xcontext/context_test.go deleted file mode 100644 index b4b96912..00000000 --- a/pkg/xcontext/context_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "context" - "runtime" - "testing" - - "github.com/stretchr/testify/require" -) - -func tryLeak() { - ctx := Background() - ctx, _ = WithCancel(ctx) - ctx, _ = WithNotify(ctx, ErrPaused) - ctx.Until(nil) - ctx = WithResetSignalers(ctx) - ctx = WithStdContext(ctx, context.Background()) - ctx.StdCtxUntil(nil) - _ = ctx -} - -func gc() { - // GC in Go is very tricky, and to be sure everything - // is cleaned up, we call it few times. - for i := 0; i < 3; i++ { - runtime.GC() - runtime.Gosched() - } -} - -func TestGoroutineLeak(t *testing.T) { - gc() - old := runtime.NumGoroutine() - - for i := 0; i < 3; i++ { - tryLeak() - gc() - } - - stack := make([]byte, 65536) - n := runtime.Stack(stack, true) - stack = stack[:n] - require.GreaterOrEqual(t, old, runtime.NumGoroutine(), string(stack)) -} - -func TestStdCtxUntil(t *testing.T) { - ctx, pauseFn := WithNotify(nil, ErrPaused) - stdCtx := ctx.StdCtxUntil(nil) - - select { - case <-stdCtx.Done(): - t.Fatal("stdCtx should not be Done by now") - default: - } - - pauseFn() - <-stdCtx.Done() -} diff --git a/pkg/xcontext/doc/examples/metrics/README.md b/pkg/xcontext/doc/examples/metrics/README.md deleted file mode 100644 index 3a7d55fb..00000000 --- a/pkg/xcontext/doc/examples/metrics/README.md +++ /dev/null @@ -1,54 +0,0 @@ -This example provides a tiny HTTP server which has metrics and is able to export them. An example session is below - ---- - -Let's get the metrics: -``` -$ curl http://localhost:8080/metrics -$ -``` -No metrics. Makes sense, we haven't triggered anything that makes any metrics. Let's trigger something and try again: -``` -$ curl http://localhost:8080/ -Hello! -``` -``` -$ curl http://localhost:8080/metrics -# HELP concurrent_requests_int -# TYPE concurrent_requests_int gauge -concurrent_requests_int 0 -# HELP hello_requests_count -# TYPE hello_requests_count counter -hello_requests_count 1 -# HELP response_count -# TYPE response_count counter -response_count{status="200"} 1 -$ -``` -OK, now we see metrics. Let's add some more: -``` -$ curl http://localhost:8080/sleep?secs=2.5 -done -$ -``` -``` -$ curl http://localhost:8080/sleep?secs=0.1 -done -$ -``` -$ curl http://localhost:8080/metrics -# HELP concurrent_requests_int -# TYPE concurrent_requests_int gauge -concurrent_requests_int 0 -# HELP hello_requests_count -# TYPE hello_requests_count counter -hello_requests_count 1 -# HELP response_count -# TYPE response_count counter -response_count{status="200"} 3 -# HELP slept_ns_count -# TYPE slept_ns_count counter -slept_ns_count 2.6e+09 -$ -``` -As we can see `response_count{status="200"}` is `3` and `slept_ns_count` is 2.6 seconds. Everything is correct. diff --git a/pkg/xcontext/doc/examples/metrics/main.go b/pkg/xcontext/doc/examples/metrics/main.go deleted file mode 100644 index 785c9328..00000000 --- a/pkg/xcontext/doc/examples/metrics/main.go +++ /dev/null @@ -1,109 +0,0 @@ -// Here we implement a simple HTTP service, which also uses xcontext to handle -// trafficstars metrics - -// This file knows about which metrics implementation do we use, since it is -// the glue code file `main.go`. - -package main - -import ( - "bytes" - "flag" - "log" - "net/http" - - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/logger" - _ "github.com/linuxboot/contest/pkg/xcontext/logger/logadapter/zap" - promadapter "github.com/linuxboot/contest/pkg/xcontext/metrics/prometheus" - "github.com/linuxboot/contest/pkg/xcontext/metrics/simplemetrics" - tsmadapter "github.com/linuxboot/contest/pkg/xcontext/metrics/tsmetrics" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/common/expfmt" - tsmetrics "github.com/xaionaro-go/metrics" - "github.com/xaionaro-go/statuspage" - "go.uber.org/zap" -) - -func main() { - metricsType := MetricsTypePrometheus - flag.Var(&metricsType, "metrics-type", "choose: prometheus, tsmetrics, simple") - flag.Parse() - - zapLogger, err := zap.NewProduction() - if err != nil { - log.Fatal(err) - } - - var prometheusRegistry *prometheus.Registry - ctx := xcontext.Background().WithLogger(logger.ConvertLogger(zapLogger)) - switch metricsType { - case MetricsTypeSimple: - ctx = ctx.WithMetrics(simplemetrics.New()) - case MetricsTypePrometheus: - prometheusRegistry = prometheus.NewRegistry() - ctx = ctx.WithMetrics(promadapter.New(prometheusRegistry, prometheusRegistry)) - case MetricsTypeTSMetrics: - ctx = ctx.WithMetrics(tsmadapter.New()) - default: - ctx.Fatalf("unknown metrics type: %s", metricsType) - } - - srv := newServer(ctx) - mux := http.NewServeMux() - mux.HandleFunc("/", srv.Hello) - mux.HandleFunc("/sleep", srv.Sleep) - mux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) { - switch metricsType { - case MetricsTypeSimple: - exportSimpleMetrics(w) - case MetricsTypePrometheus: - exportPrometheusMetrics(ctx, w, prometheusRegistry) - case MetricsTypeTSMetrics: - tsmetrics.SetDefaultTags(tsmetrics.Tags{}) - exportTSMetrics(w, ctx.Metrics().(*tsmadapter.Metrics)) - default: - ctx.Fatalf("unknown metrics type: %s", metricsType) - } - }) - httpSrv := http.Server{ - Addr: ":8080", - Handler: mux, - } - ctx.Infof("binding to %s", httpSrv.Addr) - ctx.Fatalf("%v", httpSrv.ListenAndServe()) -} - -func exportSimpleMetrics(w http.ResponseWriter) { - // TBD - - w.WriteHeader(http.StatusNotImplemented) -} - -func exportPrometheusMetrics(ctx xcontext.Context, w http.ResponseWriter, registry *prometheus.Registry) { - metrics, err := registry.Gather() - if err != nil { - ctx.Errorf("%v", ctx) - w.WriteHeader(http.StatusInternalServerError) - return - } - - var buf bytes.Buffer - enc := expfmt.NewEncoder(&buf, expfmt.FmtText) - for _, metric := range metrics { - if err := enc.Encode(metric); err != nil { - ctx.Errorf("%v", ctx) - w.WriteHeader(http.StatusInternalServerError) - return - } - } - w.WriteHeader(http.StatusOK) - _, err = w.Write(buf.Bytes()) - if err != nil { - ctx.Errorf("%v", err) - } -} - -func exportTSMetrics(w http.ResponseWriter, metrics *tsmadapter.Metrics) { - statuspage.WriteMetricsPrometheus(w, metrics.Registry) -} diff --git a/pkg/xcontext/doc/examples/metrics/metrics_type.go b/pkg/xcontext/doc/examples/metrics/metrics_type.go deleted file mode 100644 index ff333ad0..00000000 --- a/pkg/xcontext/doc/examples/metrics/metrics_type.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "strings" -) - -type MetricsType int - -const ( - MetricsTypeUndefined = MetricsType(iota) - MetricsTypeSimple - MetricsTypePrometheus - MetricsTypeTSMetrics - endOfMetricsType -) - -var _ flag.Value = (*MetricsType)(nil) - -// String implements flag.Value -func (t MetricsType) String() string { - switch t { - case MetricsTypeUndefined: - return "undefined" - case MetricsTypeSimple: - return "simple" - case MetricsTypePrometheus: - return "prometheus" - case MetricsTypeTSMetrics: - return "tsmetrics" - } - return fmt.Sprintf("unknown_%d", int(t)) -} - -// Set implements flag.Value -func (t *MetricsType) Set(in string) error { - in = strings.Trim(strings.ToLower(in), " ") - for c := MetricsType(0); c < endOfMetricsType; c++ { - if c.String() == in { - *t = c - return nil - } - } - return fmt.Errorf("unknown metrics type: '%s'", t) -} diff --git a/pkg/xcontext/doc/examples/metrics/server.go b/pkg/xcontext/doc/examples/metrics/server.go deleted file mode 100644 index ea700884..00000000 --- a/pkg/xcontext/doc/examples/metrics/server.go +++ /dev/null @@ -1,74 +0,0 @@ -// This file is agnostic of which metrics implementation do we use. - -package main - -import ( - "net/http" - "strconv" - "time" - - "github.com/linuxboot/contest/pkg/xcontext" -) - -type server struct { - BaseContext xcontext.Context -} - -func newServer(ctx xcontext.Context) *server { - return &server{BaseContext: ctx} -} - -func (srv *server) Hello(w http.ResponseWriter, r *http.Request) { - ctx := srv.BaseContext - metrics := ctx.Metrics() - - reqCount := metrics.IntGauge("concurrent_requests") - reqCount.Add(1) - defer reqCount.Add(-1) - - metrics.Count("hello_requests").Add(1) - srv.writeResponse(ctx, w, http.StatusOK, []byte("Hello!\n")) -} - -func (srv *server) Sleep(w http.ResponseWriter, r *http.Request) { - ctx := srv.BaseContext - metrics := ctx.Metrics() - - reqCount := metrics.IntGauge("concurrent_requests") - reqCount.Add(1) - defer reqCount.Add(-1) - - secsVals := r.URL.Query()["secs"] - if len(secsVals) != 1 { - metrics.WithTag("error", "wrong_amount_of_secs").Count("errors").Add(1) - srv.writeResponse(ctx, w, http.StatusBadRequest, []byte("wrong amount of 'secs' parameter\n")) - return - } - sleepSeconds, err := strconv.ParseFloat(secsVals[0], 64) - if err != nil { - metrics.WithTag("error", "invalid_secs").Count("errors").Add(1) - srv.writeResponse(ctx, w, http.StatusBadRequest, []byte("invalid value of the 'secs' parameter\n")) - return - } - sleepDuration := time.Duration(sleepSeconds * float64(time.Second)) - - time.Sleep(sleepDuration) - metrics.Count("slept_ns").Add(uint64(sleepDuration.Nanoseconds())) - srv.writeResponse(ctx, w, http.StatusOK, []byte("done\n")) -} - -func (srv *server) writeResponse( - ctx xcontext.Context, - w http.ResponseWriter, - status int, - body []byte, -) { - ctx = ctx.WithTag("status", status) - ctx.Metrics().Count("response").Add(1) - - w.WriteHeader(status) - _, err := w.Write(body) - if err != nil { - ctx.Errorf("%v", err) - } -} diff --git a/pkg/xcontext/done_errors.go b/pkg/xcontext/done_errors.go deleted file mode 100644 index 9263fe09..00000000 --- a/pkg/xcontext/done_errors.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "context" - "errors" -) - -// ErrCanceled is returned by Context.Err when the context was canceled -var ErrCanceled = context.Canceled - -// ErrDeadlineExceeded is returned by Context.Err when the context reached -// the deadline. -var ErrDeadlineExceeded = context.DeadlineExceeded - -// ErrPaused is returned by Context.Err when the context was paused -var ErrPaused = errors.New("job is paused") diff --git a/pkg/xcontext/dummy_tracer.go b/pkg/xcontext/dummy_tracer.go deleted file mode 100644 index 81929237..00000000 --- a/pkg/xcontext/dummy_tracer.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package xcontext implements a generic context with integrated logger, -// metrics, tracer and recoverer. -package xcontext - -import ( - "time" -) - -type dummyTracer struct{} -type dummyTracedSpan struct { - StartTime time.Time -} - -var ( - dummyTracerInstance = &dummyTracer{} -) - -// StartSpan implements Tracer (see the description there). -func (tracer *dummyTracer) StartSpan(label string) TimeSpan { - return &dummyTracedSpan{ - StartTime: time.Now(), - } -} - -// WithField implements Tracer (see the description there). -func (tracer *dummyTracer) WithField(key string, value interface{}) Tracer { - return tracer -} - -// WithFields implements Tracer (see the description there). -func (tracer *dummyTracer) WithFields(fields Fields) Tracer { - return tracer -} - -// Finish implements TimeSpan (see the description there). -func (span *dummyTracedSpan) Finish() time.Duration { - return time.Since(span.StartTime) -} diff --git a/pkg/xcontext/event_handler.go b/pkg/xcontext/event_handler.go deleted file mode 100644 index 90db166e..00000000 --- a/pkg/xcontext/event_handler.go +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "context" - "errors" - "runtime" - "sync" - "time" -) - -// WithTimeout is analog of context.WithTimeout, but with support of the -// extended Context. -func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { - return WithDeadline(parent, time.Now().Add(timeout)) -} - -// WithDeadline is analog of context.WithDeadline, but with support of the -// extended Context.. -func WithDeadline(parent Context, t time.Time) (Context, CancelFunc) { - if parent == nil { - parent = background - } - - ctx := parent.Clone() - h := ctx.addEventHandler() - h.deadline = &t - time.AfterFunc(time.Until(t), func() { - h.cancel(ErrDeadlineExceeded) - }) - return ctx, func() { - h.cancel(ErrCanceled) - } -} - -// WithCancel is analog of context.WithCancel, but with support of the -// extended Context. -// -// If no errs are passed, then cancel is used. -func WithCancel(parent Context, errs ...error) (Context, CancelFunc) { - if parent == nil { - parent = background - } - - ctx := parent.Clone() - h := ctx.addEventHandler() - return ctx, func() { - h.cancel(errs...) - } -} - -// WithResetSignalers resets all signalers (cancelers and notifiers). -func WithResetSignalers(parent Context) Context { - if parent == nil { - parent = background - } - - ctx := parent.Clone() - ctx.resetEventHandler() - return ctx -} - -// WithNotify is analog WithCancel, but does a notification signal instead -// (which does not close the context). -// -// Panics if no errs are passed. -func WithNotify(parent Context, errs ...error) (Context, CancelFunc) { - if len(errs) == 0 { - panic("len(errs) == 0") - } - if parent == nil { - parent = background - } - - ctx := parent.Clone() - h := ctx.addEventHandler() - return ctx, func() { - h.notify(errs...) - } -} - -// WithStdContext adds events and values of a standard context. -func WithStdContext(parent Context, stdCtx context.Context) Context { - if parent == nil { - parent = background - } - - return parent.cloneWithStdContext(stdCtx) -} - -func (ctx *ctxValue) cloneWithStdContext(stdCtx context.Context) Context { - child := ctx.clone() - - if child.valuesHandler != nil { - child.valuesHandler = valuesMerger{ - outer: stdCtx, - inner: child.valuesHandler, - } - } else { - child.valuesHandler = stdCtx - } - - h := child.addEventHandler() - - child = child.clone() - - stopListening := make(chan struct{}) - runtime.SetFinalizer(child, func(ctx *ctxValue) { - close(stopListening) - }) - go func() { - select { - case <-stdCtx.Done(): - h.cancel(stdCtx.Err()) - case <-stopListening: - } - }() - - return child -} - -type eventHandler struct { - // cancelSignal is closed when a new cancel signal is arrived - cancelSignal chan struct{} - - // children is all eventHandlers derived from this one. And for example - // if this one will receive a close signal, then all children will - // also receive a close signal. - children map[*eventHandler]struct{} - - // locker is used exclude concurrent access to any data below (in this - // structure). - locker sync.Mutex - - // firstCancel is the first cancel signal ever received for the whole. - // context tree. - // - // It is used to implement method Err compatible with the co-named method - // of the original context.Context. - firstCancel error - - // receivedCancels is only the cancel signals received by this node. - receivedCancels []error - - // receivedNotifications same as receivedCancels, but for notification signals. - receivedNotifications []error - - // notifySignal same as cancelSignal, but for notification signals. - notifySignal map[error]chan struct{} - - // deadline is when the context will be closed by exceeding a timeout. - // - // If nil then never. - deadline *time.Time -} - -func (ctx *ctxValue) resetEventHandler() { - ctx.eventHandler = nil -} - -func (ctx *ctxValue) addEventHandler() *eventHandler { - parent := ctx.eventHandler - h := &eventHandler{ - notifySignal: make(map[error]chan struct{}), - children: map[*eventHandler]struct{}{}, - } - ctx.eventHandler = h - - if parent == nil { - return h - } - - parent.locker.Lock() - h.firstCancel = parent.firstCancel - h.receivedNotifications = make([]error, len(parent.receivedNotifications)) - copy(h.receivedNotifications, parent.receivedNotifications) - h.receivedCancels = make([]error, len(parent.receivedCancels)) - copy(h.receivedCancels, parent.receivedCancels) - parent.children[h] = struct{}{} - parent.locker.Unlock() - - runtime.SetFinalizer(ctx, func(ctx *ctxValue) { - parent.locker.Lock() - delete(parent.children, h) - parent.locker.Unlock() - }) - - return h -} - -// IsSignaledWith returns true if the context received a cancel -// or a notification signal equals to any of passed ones. -// -// If errs is empty, then returns true if the context received any -// cancel or notification signal. -func (h *eventHandler) IsSignaledWith(errs ...error) bool { - if h == nil { - return false - } - - h.locker.Lock() - defer h.locker.Unlock() - - return h.isSignaledWith(errs...) -} - -func (h *eventHandler) isSignaledWith(errs ...error) bool { - if len(errs) == 0 && (len(h.receivedCancels) != 0 || len(h.receivedNotifications) != 0) { - return true - } - - for _, receivedErr := range h.receivedCancels { - for _, err := range errs { - if errors.Is(receivedErr, err) { - return true - } - } - } - - for _, receivedErr := range h.receivedNotifications { - for _, err := range errs { - if errors.Is(receivedErr, err) { - return true - } - } - } - - return false -} - -// Err implements context.Context.Err -func (h *eventHandler) Err() error { - if h == nil { - return nil - } - - h.locker.Lock() - defer h.locker.Unlock() - if h.firstCancel != nil { - return h.firstCancel - } - return nil -} - -func (h *eventHandler) cancel(errs ...error) { - h.locker.Lock() - defer h.locker.Unlock() - - if len(errs) == 0 { - h.receivedCancels = append(h.receivedCancels, ErrCanceled) - } else { - h.receivedCancels = append(h.receivedCancels, errs...) - } - if h.firstCancel == nil { - h.firstCancel = h.receivedCancels[0] - } - - if h.cancelSignal != nil { - cancelSignal := h.cancelSignal - h.cancelSignal = nil - close(cancelSignal) - } - - for _, err := range errs { - if h.notifySignal[err] == nil { - continue - } - close(h.notifySignal[err]) - h.notifySignal[err] = nil - } - - if h.notifySignal[nil] != nil { - close(h.notifySignal[nil]) - h.notifySignal[nil] = nil - } - - for child := range h.children { - child.cancel(errs...) - } -} - -func (h *eventHandler) notify(errs ...error) { - h.locker.Lock() - defer h.locker.Unlock() - - h.receivedNotifications = append(h.receivedNotifications, errs...) - - for _, err := range errs { - if h.notifySignal[err] == nil { - continue - } - close(h.notifySignal[err]) - h.notifySignal[err] = nil - } - - if h.notifySignal[nil] != nil { - close(h.notifySignal[nil]) - h.notifySignal[nil] = nil - } - - for child := range h.children { - child.notify(errs...) - } -} - -// Notifications returns all the received notifications (including events -// received by parents). -// -// This is a read-only value, do not modify it. -func (h *eventHandler) Notifications() []error { - if h == nil { - return nil - } - - h.locker.Lock() - defer h.locker.Unlock() - - return h.receivedNotifications -} - -var ( - openChan = make(chan struct{}) - closedChan = make(chan struct{}) -) - -func init() { - close(closedChan) -} - -// Done implements context.Context.Done -func (h *eventHandler) Done() <-chan struct{} { - if h == nil { - return nil - } - - h.locker.Lock() - defer h.locker.Unlock() - - if h.firstCancel != nil { - return closedChan - } - - if h.cancelSignal == nil { - h.cancelSignal = make(chan struct{}) - } - return h.cancelSignal -} - -// Until works similar to Done(), but it is possible to specify specific -// signal to wait for. -// -// If err is nil, then waits for any event. -func (h *eventHandler) Until(err error) <-chan struct{} { - if h == nil { - return openChan - } - return h.newWaiter(err) -} - -// Deadline implements context.Context.Deadline -func (h *eventHandler) Deadline() (deadline time.Time, ok bool) { - if h == nil { - return - } - - h.locker.Lock() - defer h.locker.Unlock() - - if h.deadline == nil { - return - } - - return *h.deadline, true -} - -func (h *eventHandler) newWaiter(err error) <-chan struct{} { - h.locker.Lock() // is unlocked in the go func() below - defer h.locker.Unlock() - if (err == nil && h.isSignaledWith()) || (err != nil && h.isSignaledWith(err)) { - return closedChan - } - - if h.notifySignal[err] == nil { - h.notifySignal[err] = make(chan struct{}) - } - return h.notifySignal[err] -} diff --git a/pkg/xcontext/event_handler_cancel_test.go b/pkg/xcontext/event_handler_cancel_test.go deleted file mode 100644 index d9936c7e..00000000 --- a/pkg/xcontext/event_handler_cancel_test.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestCancellation(t *testing.T) { - ctx, cancelFunc := WithCancel(Background()) - require.NotNil(t, ctx) - - ctx, customCancelFunc := WithCancel(ctx, errors.New("custom-signal")) - - var blocked bool - select { - case <-ctx.Done(): - blocked = true - default: - } - require.False(t, blocked) - - cancelFunc() - <-ctx.Done() - require.Equal(t, ErrCanceled, ctx.Err()) - - // further cancels do not affect the error code - customCancelFunc() - require.Equal(t, ErrCanceled, ctx.Err()) -} - -func TestAbstractParentContext(t *testing.T) { - parCtx, parCancel := context.WithCancel(context.Background()) - ctx := NewContext(parCtx, "", nil, nil, nil, nil, nil) - child, cancelFunc := WithCancel(ctx, errors.New("custom-signal")) - - parCancel() - <-ctx.Done() - <-child.Done() - require.Equal(t, context.Canceled, child.Err()) - - cancelFunc() - require.Equal(t, context.Canceled, child.Err()) -} - -func TestCancelContextAsParentContext(t *testing.T) { - t.Run("parent_cancel_propagated", func(t *testing.T) { - parCtx, parCancelFunc0 := WithCancel(Background()) - parCtx, parCancelFunc1 := WithCancel(parCtx, errors.New("custom-signal")) - ctx, ctxCancelFunc := WithCancel(parCtx.Clone(), errors.New("custom-signal")) - - parCancelFunc0() - <-ctx.Done() - require.Equal(t, ErrCanceled, ctx.Err()) - - parCancelFunc1() - ctxCancelFunc() - require.Equal(t, ErrCanceled, ctx.Err()) - }) - - t.Run("child_cancel_does_not_affect_parent", func(t *testing.T) { - customSignal := errors.New("custom-signal") - - parCtx, parCancelFunc := WithCancel(Background(), customSignal) - ctx, ctxCancelFunc := WithCancel(parCtx.Clone()) - - ctxCancelFunc() - <-ctx.Done() - require.Equal(t, ErrCanceled, ctx.Err()) - - var blocked bool - select { - case <-parCtx.Done(): - default: - blocked = true - } - require.True(t, blocked) - require.Nil(t, parCtx.Err()) - - parCancelFunc() - <-parCtx.Done() - require.Equal(t, customSignal, parCtx.Err()) - require.Equal(t, ErrCanceled, ctx.Err()) - }) -} - -func TestParentInitiallyCancelled(t *testing.T) { - t.Run("unknown_parent_context", func(t *testing.T) { - customSignal := errors.New("custom-signal") - - parCtx, parCancel := context.WithCancel(context.Background()) - parCancel() - - ctx, cancelFunc := WithCancel(Extend(parCtx), customSignal) - require.NotNil(t, ctx) - - <-ctx.Done() - require.Equal(t, context.Canceled, ctx.Err()) - - cancelFunc() // should be no effect - require.Equal(t, context.Canceled, ctx.Err()) - }) - - t.Run("cancel_grand_parent_context", func(t *testing.T) { - customSignal := errors.New("custom-signal") - - parCtx, parCancelFunc := WithCancel(nil) - parCancelFunc() - - ctx, cancelFunc := WithCancel(parCtx.Clone(), customSignal) - require.NotNil(t, ctx) - - <-ctx.Done() - require.Equal(t, ErrCanceled, ctx.Err()) - - cancelFunc() // should be no effect - require.Equal(t, ErrCanceled, ctx.Err()) - }) -} diff --git a/pkg/xcontext/event_handler_test.go b/pkg/xcontext/event_handler_test.go deleted file mode 100644 index b983bfc8..00000000 --- a/pkg/xcontext/event_handler_test.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "runtime" - "sync" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestBackgroundContext(t *testing.T) { - ctx := Background() - - var blocked bool - select { - case <-ctx.Until(nil): - default: - blocked = true - } - - require.True(t, blocked) - require.Nil(t, ctx.Err()) - require.Nil(t, ctx.Notifications()) -} - -func TestWaiterGC(t *testing.T) { - goroutines := runtime.NumGoroutine() - - ctx, cancelFunc := WithCancel(nil) - var wg sync.WaitGroup - wg.Add(1) - readyToSelect := make(chan struct{}) - startSelect := make(chan struct{}) - go func() { - defer wg.Done() - ch := ctx.Until(nil) - runtime.GC() - select { - case <-ch: - t.Fail() - default: - } - close(readyToSelect) - <-startSelect - <-ch - }() - <-readyToSelect - cancelFunc() - close(startSelect) - wg.Wait() - - runtime.GC() - require.GreaterOrEqual(t, goroutines, runtime.NumGoroutine()) -} - -func TestContextCanceled(t *testing.T) { - ctx, cancelFunc := WithCancel(nil) - require.NotNil(t, ctx) - - cancelFunc() - - <-ctx.Done() - <-ctx.Until(nil) - - require.Equal(t, ErrCanceled, ctx.Err()) - require.Nil(t, ctx.Notifications()) - - var paused bool - select { - case <-ctx.Until(ErrPaused): - paused = true - default: - } - require.False(t, paused) -} - -func TestContextPaused(t *testing.T) { - ctx, pauseFunc := WithNotify(nil, ErrPaused) - require.NotNil(t, ctx) - - pauseFunc() - - <-ctx.Until(ErrPaused) - <-ctx.Until(nil) - - require.Nil(t, ctx.Err()) - require.Equal(t, []error{ErrPaused}, ctx.Notifications()) - - var canceled bool - select { - case <-ctx.Done(): - canceled = true - default: - } - require.False(t, canceled) -} - -func TestMultipleCancelPause(t *testing.T) { - ctx, cancelFunc := WithCancel(nil) - ctx, pauseFunc := WithNotify(ctx, ErrPaused) - require.NotNil(t, ctx) - - pauseFunc() - cancelFunc() - pauseFunc() - cancelFunc() - - <-ctx.Done() - <-ctx.Until(nil) - <-ctx.Until(ErrPaused) - - require.Equal(t, ErrCanceled, ctx.Err()) - require.Equal(t, []error{ErrPaused, ErrPaused}, ctx.Notifications()) -} - -func TestGrandGrandGrandChild(t *testing.T) { - ctx0, notifyFunc := WithNotify(nil, ErrPaused) - ctx1, _ := WithCancel(ctx0.Clone()) - ctx2, _ := WithNotify(ctx1.Clone(), ErrPaused) - - require.False(t, ctx2.IsSignaledWith(ErrPaused)) - notifyFunc() - <-ctx2.Until(ErrPaused) -} - -func TestWithParent(t *testing.T) { - t.Run("pause_propagated", func(t *testing.T) { - parentCtx, pauseFunc := WithNotify(nil, ErrPaused) - childCtx := parentCtx.Clone() - - pauseFunc() - <-childCtx.Until(ErrPaused) - require.Equal(t, []error{ErrPaused}, childCtx.Notifications()) - <-childCtx.Until(nil) - - require.Nil(t, childCtx.Err()) - }) - t.Run("cancel_propagated", func(t *testing.T) { - parentCtx, parentCancelFunc := WithCancel(nil) - childCtx := parentCtx.Clone() - - parentCancelFunc() - <-childCtx.Done() - require.Equal(t, ErrCanceled, childCtx.Err()) - <-childCtx.Until(nil) - - require.Nil(t, childCtx.Notifications()) - }) - t.Run("pause_cancel_happened_before_context_created", func(t *testing.T) { - parentCtx, cancelFunc := WithCancel(nil) - parentCtx, pauseFunc := WithNotify(parentCtx, ErrPaused) - pauseFunc() - cancelFunc() - - childCtx := parentCtx.Clone() - <-childCtx.Done() - <-childCtx.Until(ErrPaused) - <-childCtx.Until(nil) - - require.Equal(t, ErrCanceled, childCtx.Err()) - require.Equal(t, []error{ErrPaused}, childCtx.Notifications()) - }) - t.Run("child_pause_cancel_do_not_affect_parent", func(t *testing.T) { - parentCtxs := map[string]Context{} - parentCtxs["background"] = Background() - parentCtxs["with_cancel"], _ = WithCancel(nil) - for parentName, parentCtx := range parentCtxs { - t.Run(parentName, func(t *testing.T) { - childCtx, cancelFunc := WithCancel(parentCtx.Clone()) - _, pauseFunc := WithNotify(childCtx, ErrPaused) - - pauseFunc() - cancelFunc() - - var blocked bool - select { - case <-parentCtx.Until(nil): - default: - blocked = true - } - - require.True(t, blocked) - }) - } - }) -} diff --git a/pkg/xcontext/fields/fields.go b/pkg/xcontext/fields/fields.go deleted file mode 100644 index 92e7bcb7..00000000 --- a/pkg/xcontext/fields/fields.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package fields - -// Fields is a multiple of fields which are attached to logger/tracer messages. -type Fields map[string]interface{} diff --git a/pkg/xcontext/fields/pending_fields.go b/pkg/xcontext/fields/pending_fields.go deleted file mode 100644 index 33d88204..00000000 --- a/pkg/xcontext/fields/pending_fields.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package fields - -// PendingField is a one entry of a history of added fields. -// -// PendingField is focused on high-performance Clone method, for details -// see PendingFields. -type PendingField struct { - parentPendingFields Slice - - // In current implementation oneFieldKey and multipleFields are never - // used together, but still we preserve oneFieldKey and oneFieldValue due - // to performance reasons (see the description of PendingFields), it - // allows to avoid allocating and accessing a map for a single field. - oneFieldKey string - oneFieldValue interface{} - multipleFields map[string]interface{} -} - -// Slice is a set of entries of a history of added fields. -// -// See PendingFields. -type Slice []PendingField - -// PendingFields is a history of added fields. It is focused on cheap -// cloning and adding new entries avoiding extra copy all the data on each -// adding of key-values. Therefore it is so-so performance-safe to -// use it for scoped contexts. -// -// A resulting value could be received (compiled) on-need-basis using method Compile. -// -// See also benchmark comments in pending_fields_test.go. -type PendingFields struct { - Slice Slice - IsReadOnly bool -} - -// Clone returns a "copy" of PendingFields. It is safe to add new entries -// to this "copy" (it will not affect the original). -func (pendingFields PendingFields) Clone() PendingFields { - if pendingFields.Slice != nil { - pendingFields.IsReadOnly = true - } - return pendingFields -} - -// Compile constructs Fields from PendingFields. -func (pendingFields PendingFields) Compile() Fields { - return pendingFields.Slice.compile(nil) -} - -// CompileWithStorage is the same as Compile, but allows to pass a storage -// to save values to. It could be used, for example, to reuse existing storages -// to reduce pressure on GC. -func (pendingFields PendingFields) CompileWithStorage(m Fields) Fields { - return pendingFields.Slice.compile(m) -} - -func (pendingFields Slice) compile(result Fields) Fields { - for _, item := range pendingFields { - switch { - case item.parentPendingFields != nil: - if result == nil { - result = make(Fields, len(pendingFields)+len(item.parentPendingFields)-1) - } - - item.parentPendingFields.compile(result) - - case item.multipleFields != nil: - if result == nil { - result = item.multipleFields - continue - } - for k, v := range item.multipleFields { - result[k] = v - } - - default: - if result == nil { - result = make(Fields, len(pendingFields)) - } - result[item.oneFieldKey] = item.oneFieldValue - } - } - - return result -} - -// AddOne adds one field. -func (pendingFields *PendingFields) AddOne(key string, value interface{}) { - if pendingFields.IsReadOnly { - newPendingFields := PendingFields{Slice: make([]PendingField, 1, 2)} - newPendingFields.Slice[0] = PendingField{parentPendingFields: pendingFields.Slice} - *pendingFields = newPendingFields - } - pendingFields.Slice = append(pendingFields.Slice, PendingField{ - oneFieldKey: key, - oneFieldValue: value, - }) -} - -// AddMultiple adds a set of fields. -func (pendingFields *PendingFields) AddMultiple(fields Fields) { - if fields == nil { - return - } - if pendingFields.IsReadOnly { - newPendingFields := PendingFields{Slice: make([]PendingField, 1, 2)} - newPendingFields.Slice[0] = PendingField{parentPendingFields: pendingFields.Slice} - *pendingFields = newPendingFields - } - pendingFields.Slice = append(pendingFields.Slice, PendingField{ - multipleFields: fields, - }) -} diff --git a/pkg/xcontext/fields/pending_fields_test.go b/pkg/xcontext/fields/pending_fields_test.go deleted file mode 100644 index 61d491ff..00000000 --- a/pkg/xcontext/fields/pending_fields_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package fields - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -var ( - testPendingFields = PendingFields{ - Slice: Slice{ - { - parentPendingFields: Slice{{ - oneFieldKey: "1", - oneFieldValue: 2, - }}, - }, - { - oneFieldKey: "3", - oneFieldValue: 4, - }, - { - multipleFields: map[string]interface{}{ - "5": 6, - }, - }, - }, - } -) - -var v PendingFields - -func BenchmarkPendingFields_Clone(b *testing.B) { - // Last benchmark: BenchmarkPendingFields_Clone-8 967913209 1.12 ns/op 0 B/op 0 allocs/op - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - v = testPendingFields.Clone() - } -} - -func BenchmarkPendingFields_CloneAndAddOne(b *testing.B) { - // Last benchmark: BenchmarkPendingFields_CloneAndAddOne-8 17389500 74.5 ns/op 128 B/op 1 allocs - // - // This allocation and CPU consumption could be reduced via sync.Pool, - // but for now it is a premature optimization (there was no request on - // such performance). - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - f := testPendingFields.Clone() - f.AddOne("1", "2") - } -} - -func BenchmarkPendingFields_CloneAndAddOneAsMultiple(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - f := testPendingFields.Clone() - f.AddMultiple(Fields{"1": "2"}) - } -} - -func BenchmarkPendingFields_Compile(b *testing.B) { - // Last benchmark: BenchmarkPendingFields_Compile-8 4787438 251 ns/op 336 B/op 2 allocs - // - // Could be performed the same optimization as for BenchmarkPendingFields_CloneAndAddOne - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - testPendingFields.Compile() - } -} - -func TestPendingFields_Compile(t *testing.T) { - require.Equal(t, Fields{ - "1": 2, - "3": 4, - "5": 6, - }, testPendingFields.Compile()) -} - -func TestPendingFields_Clone(t *testing.T) { - t.Run("safeScoping", func(t *testing.T) { - v0 := testPendingFields.Clone() - v1 := v0.Clone() - v0.AddOne("k", "v") - require.Equal(t, testPendingFields.Compile(), v1.Compile()) - require.NotEqual(t, v0.Compile(), v1.Compile()) - }) -} diff --git a/pkg/xcontext/logger/internal/dummy_logger.go b/pkg/xcontext/logger/internal/dummy_logger.go deleted file mode 100644 index 2431de64..00000000 --- a/pkg/xcontext/logger/internal/dummy_logger.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. -package internal - -var ( - _ MinimalLoggerCompact = DummyLogger{} -) - -// DummyLogger is just a logger which does nothing. -// To do not duplicate anything we just implement MinimalLoggerCompact -// and the rest methods could be added using wrappers (see logger.ConvertLogger). -type DummyLogger struct{} - -// Logf implements MinimalLoggerCompact. -func (DummyLogger) Logf(_ Level, _ string, _ ...interface{}) {} diff --git a/pkg/xcontext/logger/internal/extend_wrapper.go b/pkg/xcontext/logger/internal/extend_wrapper.go deleted file mode 100644 index a6b7a890..00000000 --- a/pkg/xcontext/logger/internal/extend_wrapper.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. -package internal - -import ( - "fmt" -) - -var ( - _ Logger = ExtendWrapper{} -) - -// ExtendWrapper implements Logger based on MinimalLogger. -// -// Thus if you have only a MinimalLogger, you can extend it to a Logger -// using this wrapper. -// -// It is called ExtendWrapper because it actually implements -// only LoggerExtensions. -type ExtendWrapper struct { - MinimalLogger - Prefix string - CurLevel Level -} - -// OriginalLogger implements LoggerExtensions. -func (l ExtendWrapper) OriginalLogger() interface{} { - if backend, _ := l.MinimalLogger.(interface{ OriginalLogger() interface{} }); backend != nil { - return backend.OriginalLogger() - } - - return l.MinimalLogger -} - -// WithField implements LoggerExtensions. -func (l ExtendWrapper) WithField(key string, value interface{}) Logger { - l.Prefix += fmt.Sprintf("%s = %v ", key, value) - return l -} - -// WithFields implements LoggerExtensions. -func (l ExtendWrapper) WithFields(fields Fields) Logger { - for key, value := range fields { - l.Prefix += fmt.Sprintf("%s = %v ", key, value) - } - return l -} - -// WithLevel implements LoggerExtensions. -func (l ExtendWrapper) WithLevel(level Level) Logger { - l.CurLevel = level - return l -} - -// Level implements LoggerExtensions. -func (l ExtendWrapper) Level() Level { - return l.CurLevel -} - -// Debugf implements MinimalLogger. -// -// It calls the backend ExtendWrapper.MinimalLogger.Debugf but also checks -// if the logging level is satisfied. -func (l ExtendWrapper) Debugf(format string, args ...interface{}) { - if l.CurLevel < LevelDebug { - return - } - l.MinimalLogger.Debugf("%s"+format, append([]interface{}{l.Prefix}, args...)...) -} - -// Infof implements MinimalLogger. -// -// It calls the backend ExtendWrapper.MinimalLogger.Infof but also checks -// if the logging level is satisfied. -func (l ExtendWrapper) Infof(format string, args ...interface{}) { - if l.CurLevel < LevelInfo { - return - } - l.MinimalLogger.Infof("%s"+format, append([]interface{}{l.Prefix}, args...)...) -} - -// Warnf implements MinimalLogger. -// -// It calls the backend ExtendWrapper.MinimalLogger.Warnf but also checks -// if the logging level is satisfied. -func (l ExtendWrapper) Warnf(format string, args ...interface{}) { - if l.CurLevel < LevelWarning { - return - } - l.MinimalLogger.Warnf("%s"+format, append([]interface{}{l.Prefix}, args...)...) -} - -// Errorf implements MinimalLogger. -// -// It calls the backend ExtendWrapper.MinimalLogger.Errorf but also checks -// if the logging level is satisfied. -func (l ExtendWrapper) Errorf(format string, args ...interface{}) { - if l.CurLevel < LevelError { - return - } - l.MinimalLogger.Errorf("%s"+format, append([]interface{}{l.Prefix}, args...)...) -} - -// Panicf implements MinimalLogger. -// -// It calls the backend ExtendWrapper.MinimalLogger.Panicf but also checks -// if the logging level is satisfied. -func (l ExtendWrapper) Panicf(format string, args ...interface{}) { - if l.CurLevel < LevelPanic { - return - } - l.MinimalLogger.Panicf("%s"+format, append([]interface{}{l.Prefix}, args...)...) -} - -// Fatalf implements MinimalLogger. -// -// It calls the backend ExtendWrapper.MinimalLogger.Fatalf but also checks -// if the logging level is satisfied. -func (l ExtendWrapper) Fatalf(format string, args ...interface{}) { - if l.CurLevel < LevelFatal { - return - } - l.MinimalLogger.Fatalf("%s"+format, append([]interface{}{l.Prefix}, args...)...) -} diff --git a/pkg/xcontext/logger/internal/extend_wrapper_test.go b/pkg/xcontext/logger/internal/extend_wrapper_test.go deleted file mode 100644 index c07233d9..00000000 --- a/pkg/xcontext/logger/internal/extend_wrapper_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package internal - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -var ( - _ MinimalLogger = &testMinimalLogger{} -) - -type out struct { - Format string - Args []interface{} -} - -type testMinimalLogger struct { - debugs []out - infos []out - warns []out - errors []out - panics []out - fatals []out -} - -func (l *testMinimalLogger) Debugf(format string, args ...interface{}) { - l.debugs = append(l.debugs, out{ - Format: format, - Args: args, - }) -} - -func (l *testMinimalLogger) Infof(format string, args ...interface{}) { - l.infos = append(l.infos, out{ - Format: format, - Args: args, - }) -} - -func (l *testMinimalLogger) Warnf(format string, args ...interface{}) { - l.warns = append(l.warns, out{ - Format: format, - Args: args, - }) -} - -func (l *testMinimalLogger) Errorf(format string, args ...interface{}) { - l.errors = append(l.errors, out{ - Format: format, - Args: args, - }) -} - -func (l *testMinimalLogger) Panicf(format string, args ...interface{}) { - l.panics = append(l.panics, out{ - Format: format, - Args: args, - }) -} - -func (l *testMinimalLogger) Fatalf(format string, args ...interface{}) { - l.fatals = append(l.fatals, out{ - Format: format, - Args: args, - }) -} - -func TestExtendWrapper(t *testing.T) { - m := testMinimalLogger{} - w := ExtendWrapper{ - MinimalLogger: &m, - Prefix: "prefix", - } - - // Dataset is to verify if the correct level is used and if loglevels conditions - // are complied. - w.WithLevel(LevelDebug).Debugf("debug", "ok") - w.WithLevel(LevelInfo).Debugf("debug", "not ok") - w.WithLevel(LevelInfo).Infof("info", "ok") - w.WithLevel(LevelWarning).Infof("info", "not ok") - w.WithLevel(LevelWarning).Warnf("warn", "ok") - w.WithLevel(LevelError).Warnf("warn", "not ok") - w.WithLevel(LevelError).Errorf("error", "ok") - w.WithLevel(LevelPanic).Errorf("error", "not ok") - w.WithLevel(LevelPanic).Panicf("panic", "ok") - w.WithLevel(LevelFatal).Panicf("panic", "not ok") - w.WithLevel(LevelFatal).Fatalf("fatal", "ok") - - outss := map[string][]out{ - "debug": m.debugs, - "info": m.infos, - "warn": m.warns, - "error": m.errors, - "panic": m.panics, - "fatal": m.fatals, - } - - for levelName, outs := range outss { - require.Len(t, outs, 1, levelName) - for _, out := range outs { - require.Equal(t, "%s"+levelName, out.Format) - require.Equal(t, w.Prefix, out.Args[0]) - require.Equal(t, "ok", out.Args[1]) - } - } - - require.Equal(t, &m, w.OriginalLogger()) -} diff --git a/pkg/xcontext/logger/internal/interfaces.go b/pkg/xcontext/logger/internal/interfaces.go deleted file mode 100644 index dedffa71..00000000 --- a/pkg/xcontext/logger/internal/interfaces.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. -package internal - -import ( - "github.com/linuxboot/contest/pkg/xcontext/fields" -) - -// Fields is a multiple of fields which are attached to logger/tracer messages. -type Fields = fields.Fields - -// Logger is the interface of a logger provided by an extended context. -// -// This is the complete logger with all the required methods/features. -type Logger interface { - MinimalLogger - LoggerExtensions -} - -// LoggerCompact is a kind of logger with one method Logf(level, ...) instead -// of separate methods Debugf(...), Infof(...), Warnf(...) and so on. -type LoggerCompact interface { - MinimalLoggerCompact - LoggerExtensions -} - -// LoggerExtensions includes all the features required for a Logger over -// MinimalLogger. -type LoggerExtensions interface { - // OriginalLogger returns the original logger without wrappers added - // by this package. - OriginalLogger() interface{} - - WithLevels - WithFields -} - -// WithLevels requires methods of a logger with support of logging levels. -type WithLevels interface { - // Level returns the current logging level. - Level() Level - - // WithLevel returns a logger with logger level set to the passed argument. - WithLevel(Level) Logger -} - -// WithFields requires methods of a logger with support of structured logging. -type WithFields interface { - // WithField returns a logger with added field (used for structured logging). - WithField(key string, value interface{}) Logger - - // WithFields returns a logger with added fields (used for structured logging). - WithFields(fields Fields) Logger -} - -// MinimalLogger is a simple logger, for example logrus.Entry or zap.SugaredLogger -// could be candidates of an implementation of this interfaces. -// -// Note: logrus.Entry and zap.SugaredLogger supports structured logging and -// they have With* methods, but the API is different, so we do not require -// that methods here. We add support of builtin structured logging and -// logging levels through logadapter-s, see for example -// logadapter/logrus.Adapter.Convert. -type MinimalLogger interface { - Debugf(format string, args ...interface{}) - Infof(format string, args ...interface{}) - Warnf(format string, args ...interface{}) - Errorf(format string, args ...interface{}) - Panicf(format string, args ...interface{}) - Fatalf(format string, args ...interface{}) -} - -type MinimalLoggerCompact interface { - Logf(logLevel Level, format string, args ...interface{}) -} diff --git a/pkg/xcontext/logger/internal/log_level.go b/pkg/xcontext/logger/internal/log_level.go deleted file mode 100644 index 8e1b8e70..00000000 --- a/pkg/xcontext/logger/internal/log_level.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. -package internal - -import ( - "fmt" - "strings" -) - -// Level is used to define severity of messages to be reported. -type Level int - -const ( - // LevelUndefined is the erroneous value of log-level which corresponds - // to zero-value. - LevelUndefined = Level(iota) - - // LevelFatal will report about Fatalf-s only. - LevelFatal - - // LevelPanic will report about Panicf-s and Fatalf-s only. - LevelPanic - - // LevelError will report about Errorf-s, Panicf-s, ... - LevelError - - // LevelWarning will report about Warningf-s, Errorf-s, ... - LevelWarning - - // LevelInfo will report about Infof-s, Warningf-s, ... - LevelInfo - - // LevelDebug will report about Debugf-s, Infof-s, ... - LevelDebug -) - -// String just implements fmt.Stringer, flag.Value and pflag.Value. -func (logLevel Level) String() string { - switch logLevel { - case LevelUndefined: - return "undefined" - case LevelDebug: - return "debug" - case LevelInfo: - return "info" - case LevelWarning: - return "warning" - case LevelError: - return "error" - case LevelPanic: - return "panic" - case LevelFatal: - return "fatal" - } - return "unknown" -} - -// Set updates the logging level values based on the passed string value. -// This method just implements flag.Value and pflag.Value. -func (logLevel *Level) Set(value string) error { - newLogLevel, err := ParseLogLevel(value) - if err != nil { - return err - } - *logLevel = newLogLevel - return nil -} - -// Type just implements pflag.Value. -func (logLevel *Level) Type() string { - return "Level" -} - -// ParseLogLevel parses incoming string into a Level and returns -// LevelUndefined with an error if an unknown logging level was passed. -func ParseLogLevel(in string) (Level, error) { - switch strings.ToLower(in) { - case "d", "debug": - return LevelDebug, nil - case "i", "info": - return LevelInfo, nil - case "w", "warn", "warning": - return LevelWarning, nil - case "e", "err", "error": - return LevelError, nil - case "p", "panic": - return LevelPanic, nil - case "f", "fatal": - return LevelFatal, nil - } - var allowedValues []string - for logLevel := LevelFatal; logLevel <= LevelDebug; logLevel++ { - allowedValues = append(allowedValues, logLevel.String()) - } - return LevelUndefined, fmt.Errorf("unknown logging level '%s', known values are: %s", - in, strings.Join(allowedValues, ", ")) -} diff --git a/pkg/xcontext/logger/internal/log_level_test.go b/pkg/xcontext/logger/internal/log_level_test.go deleted file mode 100644 index e819a5a9..00000000 --- a/pkg/xcontext/logger/internal/log_level_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package internal - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestParseLogLevel(t *testing.T) { - tryParseLevel := func(expectedLevel Level, input string) { - level, err := ParseLogLevel(input) - if assert.NoError(t, err, input) { - assert.Equal(t, expectedLevel, level, input) - } - - reparsedLevel, err := ParseLogLevel(level.String()) - if assert.NoError(t, err, input) { - assert.Equal(t, level, reparsedLevel, input) - } - } - tryParseLevel(LevelDebug, "debug") - tryParseLevel(LevelDebug, "dEbug") - tryParseLevel(LevelInfo, "info") - tryParseLevel(LevelWarning, "warn") - tryParseLevel(LevelError, "error") - tryParseLevel(LevelPanic, "panic") - tryParseLevel(LevelFatal, "fatal") - level, err := ParseLogLevel("unknown") - assert.Error(t, err) - assert.Equal(t, LevelUndefined, level) -} diff --git a/pkg/xcontext/logger/internal/minimal_logger.go b/pkg/xcontext/logger/internal/minimal_logger.go deleted file mode 100644 index 4bee54f5..00000000 --- a/pkg/xcontext/logger/internal/minimal_logger.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. -package internal - -// MinimalLoggerLogf is an implementation of method Logf (of interface -// MinimalLoggerCompact) based on MinimalLogger. -// -// This function is implemented here to deduplicate code among logadapter-s. -func MinimalLoggerLogf( - l MinimalLogger, - level Level, - format string, - args ...interface{}, -) { - var logf func(string, ...interface{}) - switch level { - case LevelDebug: - logf = l.Debugf - case LevelInfo: - logf = l.Infof - case LevelWarning: - logf = l.Warnf - case LevelError: - logf = l.Errorf - case LevelPanic: - logf = l.Panicf - case LevelFatal: - logf = l.Fatalf - default: - return - } - logf(format, args...) -} diff --git a/pkg/xcontext/logger/internal/minimal_logger_test.go b/pkg/xcontext/logger/internal/minimal_logger_test.go deleted file mode 100644 index 1471452d..00000000 --- a/pkg/xcontext/logger/internal/minimal_logger_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package internal - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestMinimalLoggerLogf(t *testing.T) { - m := testMinimalLogger{} - - for level := LevelFatal; level <= LevelDebug; level++ { - MinimalLoggerLogf(&m, level, level.String(), level) - } - - outss := map[string][]out{ - "debug": m.debugs, - "info": m.infos, - "warning": m.warns, - "error": m.errors, - "panic": m.panics, - "fatal": m.fatals, - } - - for levelName, outs := range outss { - require.Len(t, outs, 1, levelName) - for _, out := range outs { - require.Equal(t, levelName, out.Format) - require.Len(t, out.Args, 1, levelName) - require.IsType(t, Level(0), out.Args[0], levelName) - require.IsType(t, levelName, out.Args[0].(Level).String()) - } - } -} diff --git a/pkg/xcontext/logger/internal/uncompact.go b/pkg/xcontext/logger/internal/uncompact.go deleted file mode 100644 index 029ed91d..00000000 --- a/pkg/xcontext/logger/internal/uncompact.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. -package internal - -var ( - _ MinimalLogger = UncompactMinimalLoggerCompact{} -) - -// UncompactMinimalLoggerCompact converts MinimalLoggerCompact to MinimalLogger. -type UncompactMinimalLoggerCompact struct { - MinimalLoggerCompact -} - -// Debugf implements MinimalLogger. -func (l UncompactMinimalLoggerCompact) Debugf(format string, args ...interface{}) { - l.Logf(LevelDebug, format, args...) -} - -// Infof implements MinimalLogger. -func (l UncompactMinimalLoggerCompact) Infof(format string, args ...interface{}) { - l.Logf(LevelInfo, format, args...) -} - -// Warnf implements MinimalLogger. -func (l UncompactMinimalLoggerCompact) Warnf(format string, args ...interface{}) { - l.Logf(LevelWarning, format, args...) -} - -// Errorf implements MinimalLogger. -func (l UncompactMinimalLoggerCompact) Errorf(format string, args ...interface{}) { - l.Logf(LevelError, format, args...) -} - -// Panicf implements MinimalLogger. -func (l UncompactMinimalLoggerCompact) Panicf(format string, args ...interface{}) { - l.Logf(LevelPanic, format, args...) -} - -// Fatalf implements MinimalLogger. -func (l UncompactMinimalLoggerCompact) Fatalf(format string, args ...interface{}) { - l.Logf(LevelFatal, format, args...) -} - -// OriginalLogger implements LoggerExtensions. -func (l UncompactMinimalLoggerCompact) OriginalLogger() interface{} { - if backend, _ := l.MinimalLoggerCompact.(interface{ OriginalLogger() interface{} }); backend != nil { - return backend.OriginalLogger() - } - - return l.MinimalLoggerCompact -} - -var ( - _ Logger = UncompactLoggerCompact{} -) - -// UncompactLoggerCompact converts LoggerCompact to Logger. -type UncompactLoggerCompact struct { - LoggerCompact -} - -// Debugf implements MinimalLogger. -func (l UncompactLoggerCompact) Debugf(format string, args ...interface{}) { - l.Logf(LevelDebug, format, args...) -} - -// Infof implements MinimalLogger. -func (l UncompactLoggerCompact) Infof(format string, args ...interface{}) { - l.Logf(LevelInfo, format, args...) -} - -// Warnf implements MinimalLogger. -func (l UncompactLoggerCompact) Warnf(format string, args ...interface{}) { - l.Logf(LevelWarning, format, args...) -} - -// Errorf implements MinimalLogger. -func (l UncompactLoggerCompact) Errorf(format string, args ...interface{}) { - l.Logf(LevelError, format, args...) -} - -// Panicf implements MinimalLogger. -func (l UncompactLoggerCompact) Panicf(format string, args ...interface{}) { - l.Logf(LevelPanic, format, args...) -} - -// Fatalf implements MinimalLogger. -func (l UncompactLoggerCompact) Fatalf(format string, args ...interface{}) { - l.Logf(LevelFatal, format, args...) -} - -// OriginalLogger implements LoggerExtensions. -func (l UncompactLoggerCompact) OriginalLogger() interface{} { - if backend, _ := l.LoggerCompact.(interface{ OriginalLogger() interface{} }); backend != nil { - return backend.OriginalLogger() - } - - return l.LoggerCompact -} diff --git a/pkg/xcontext/logger/internal/uncompact_test.go b/pkg/xcontext/logger/internal/uncompact_test.go deleted file mode 100644 index 1cf02a7d..00000000 --- a/pkg/xcontext/logger/internal/uncompact_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package internal - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -var ( - _ MinimalLoggerCompact = &testLoggerCompact{} -) - -type testLoggerCompact struct { - outs [LevelDebug + 1][]out -} - -func (l *testLoggerCompact) Logf(level Level, format string, args ...interface{}) { - l.outs[level] = append(l.outs[level], out{ - Format: format, - Args: args, - }) -} - -func TestUncompactMinimalLoggerCompact(t *testing.T) { - m := testLoggerCompact{} - w := UncompactMinimalLoggerCompact{ - MinimalLoggerCompact: &m, - } - - w.Debugf("debug", "DEBUG") - w.Infof("info", "INFO") - w.Warnf("warning", "WARNING") - w.Errorf("error", "ERROR") - w.Panicf("panic", "PANIC") - w.Fatalf("fatal", "FATAL") - - for level := LevelFatal; level <= LevelDebug; level++ { - assert.Len(t, m.outs[level], 1, level) - assert.Equal(t, level.String(), m.outs[level][0].Format, level) - assert.Len(t, m.outs[level][0].Args, 1, level) - assert.Equal(t, strings.ToUpper(level.String()), m.outs[level][0].Args[0], level) - } - - assert.Equal(t, &m, w.OriginalLogger()) -} diff --git a/pkg/xcontext/logger/internal/wrap_minimal_logger.go b/pkg/xcontext/logger/internal/wrap_minimal_logger.go deleted file mode 100644 index 37ebf294..00000000 --- a/pkg/xcontext/logger/internal/wrap_minimal_logger.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. -package internal - -// WrapMinimalLogger wraps a MinimalLogger to provide a Logger. -func WrapMinimalLogger(logger MinimalLogger) Logger { - return ExtendWrapper{ - MinimalLogger: logger, - Prefix: "", - CurLevel: LevelWarning, - } -} diff --git a/pkg/xcontext/logger/internal/wrap_minimal_logger_compact.go b/pkg/xcontext/logger/internal/wrap_minimal_logger_compact.go deleted file mode 100644 index 876b987d..00000000 --- a/pkg/xcontext/logger/internal/wrap_minimal_logger_compact.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. - -package internal - -// WrapMinimalLoggerCompact wraps a MinimalLoggerCompact to provide a Logger. -func WrapMinimalLoggerCompact(logger MinimalLoggerCompact) Logger { - return ExtendWrapper{ - MinimalLogger: UncompactMinimalLoggerCompact{ - MinimalLoggerCompact: logger, - }, - Prefix: "", - CurLevel: LevelWarning, - } -} diff --git a/pkg/xcontext/logger/internal/wrap_printf.go b/pkg/xcontext/logger/internal/wrap_printf.go deleted file mode 100644 index 6045052d..00000000 --- a/pkg/xcontext/logger/internal/wrap_printf.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -// Package internal of logger unifies different types of loggers into -// interfaces Logger. For example it allows to upgrade simple fmt.Printf -// to be a fully functional Logger. Therefore multiple wrappers are implemented -// here to provide different functions which could be missing in some loggers. -package internal - -// WrapPrintf wraps a Printf-like function to provide a Logger. -func WrapPrintf(fn func(format string, args ...interface{})) Logger { - return ExtendWrapper{ - MinimalLogger: UncompactMinimalLoggerCompact{ - MinimalLoggerCompact: printfWrapper{ - Func: fn, - }, - }, - Prefix: "", - CurLevel: LevelWarning, - } -} - -var ( - _ MinimalLoggerCompact = printfWrapper{} -) - -// printfWrapper converts a Printf-like function to a MinimalLoggerCompact. -type printfWrapper struct { - Func func(format string, args ...interface{}) -} - -// Logf implements MinimalLoggerCompact. -func (l printfWrapper) Logf(level Level, format string, args ...interface{}) { - l.Func("["+level.String()+"] "+format, args...) -} - -// OriginalLogger implements LoggerExtensions. -func (l printfWrapper) OriginalLogger() interface{} { - return l.Func -} diff --git a/pkg/xcontext/logger/internal/wrap_printf_test.go b/pkg/xcontext/logger/internal/wrap_printf_test.go deleted file mode 100644 index a6b11ca7..00000000 --- a/pkg/xcontext/logger/internal/wrap_printf_test.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package internal - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestWrapPrintf(t *testing.T) { - var outs []out - - l := WrapPrintf(func(format string, args ...interface{}) { - outs = append(outs, out{ - Format: format, - Args: args, - }) - }) - - l.Debugf("should not be added, since default logging level is WARN", ":(") - - l.WithLevel(LevelDebug).Debugf("test", ":)") - require.Len(t, outs, 1) - require.Equal(t, outs[0].Format, "[debug] %stest") - require.Len(t, outs[0].Args, 2) - require.Equal(t, outs[0].Args[0], "") // empty prefix added by ExtendWrapper - require.Equal(t, outs[0].Args[1], ":)") -} diff --git a/pkg/xcontext/logger/log_level.go b/pkg/xcontext/logger/log_level.go deleted file mode 100644 index 9077dd90..00000000 --- a/pkg/xcontext/logger/log_level.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logger - -import ( - "github.com/linuxboot/contest/pkg/xcontext/logger/internal" -) - -// Level is used to define severity of messages to be reported. -type Level = internal.Level - -const ( - // LevelUndefined is the erroneous value of log-level which corresponds - // to zero-value. - LevelUndefined = internal.LevelUndefined - - // LevelFatal will report about Fatalf-s only. - LevelFatal = internal.LevelFatal - - // LevelPanic will report about Panicf-s and Fatalf-s only. - LevelPanic = internal.LevelPanic - - // LevelError will report about Errorf-s, Panicf-s, ... - LevelError = internal.LevelError - - // LevelWarning will report about Warningf-s, Errorf-s, ... - LevelWarning = internal.LevelWarning - - // LevelInfo will report about Infof-s, Warningf-s, ... - LevelInfo = internal.LevelInfo - - // LevelDebug will report about Debugf-s, Infof-s, ... - LevelDebug = internal.LevelDebug - - // EndOfLevel is just used as a limiter for `for`-s. - EndOfLevel -) - -// ParseLogLevel parses incoming string into a Level and returns -// LevelUndefined with an error if an unknown logging level was passed. -func ParseLogLevel(in string) (Level, error) { - return internal.ParseLogLevel(in) -} diff --git a/pkg/xcontext/logger/logadapter/logrus/adapter.go b/pkg/xcontext/logger/logadapter/logrus/adapter.go deleted file mode 100644 index 4a0b98f9..00000000 --- a/pkg/xcontext/logger/logadapter/logrus/adapter.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logrus - -import ( - "github.com/sirupsen/logrus" - - "github.com/linuxboot/contest/pkg/xcontext/logger" -) - -func init() { - logger.RegisterAdapter(Adapter) -} - -type adapter struct{} - -var ( - _ logger.Adapter = Adapter -) - -// Adapter is implementation of logger.Adapter for logrus. -var Adapter = (*adapter)(nil) - -// Convert implements logger.Adapter. -func (_ *adapter) Convert(backend interface{}) logger.Logger { - switch backend := backend.(type) { - case *logrus.Entry: - return wrap(backend) - case *logrus.Logger: - return wrap(logrus.NewEntry(backend)) - } - return nil -} - -// Level converts our logging level to logrus logging level. -func (_ *adapter) Level(level logger.Level) logrus.Level { - switch level { - case logger.LevelDebug: - return logrus.DebugLevel - case logger.LevelInfo: - return logrus.InfoLevel - case logger.LevelWarning: - return logrus.WarnLevel - case logger.LevelError: - return logrus.ErrorLevel - case logger.LevelPanic: - return logrus.PanicLevel - case logger.LevelFatal: - return logrus.FatalLevel - case logger.LevelUndefined: - } - - return logrus.PanicLevel -} - -// Level converts logrus logging level to our logging level. -func (_ *adapter) ConvertLevel(level logrus.Level) logger.Level { - switch level { - case logrus.DebugLevel: - return logger.LevelDebug - case logrus.InfoLevel: - return logger.LevelInfo - case logrus.WarnLevel: - return logger.LevelWarning - case logrus.ErrorLevel: - return logger.LevelError - case logrus.PanicLevel: - return logger.LevelPanic - case logrus.FatalLevel: - return logger.LevelFatal - - } - return logger.LevelUndefined -} diff --git a/pkg/xcontext/logger/logadapter/logrus/fix_caller_hook.go b/pkg/xcontext/logger/logadapter/logrus/fix_caller_hook.go deleted file mode 100644 index 1c5efcbb..00000000 --- a/pkg/xcontext/logger/logadapter/logrus/fix_caller_hook.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logrus - -import ( - "runtime" - "strings" - - "github.com/sirupsen/logrus" -) - -const ( - // maxCallerScanDepths defines maximum possible depth of calls of - // logger-related functions inside the `xcontext` code. - // - // More this value is, slower the logger works. - maxCallerScanDepth = 16 -) - -var _ logrus.Hook = fixCallerHook{} - -// fixCallerHook is a hook which makes the value of entry.Caller -// more meaningful, otherwise the whole log has the same values of "file" -// and "func", like here: -// -// "file": "github.com/linuxboot/contest/pkg/xcontext/logger/internal/minimal_logger.go:34", -// "func": "github.com/linuxboot/contest/pkg/xcontext/logger/internal.MinimalLoggerLogf", -type fixCallerHook struct{} - -func (fixCallerHook) Levels() []logrus.Level { - return logrus.AllLevels -} - -func (fixCallerHook) Fire(entry *logrus.Entry) error { - if entry.Caller == nil { - // if entry.Logger.ReportCaller is false, then there's nothing to do - return nil - } - - if !strings.Contains(entry.Caller.Function, "github.com/linuxboot/contest/pkg/xcontext") { - // if the value is already correct, then there's nothing to do. - return nil - } - - programCounters := make([]uintptr, maxCallerScanDepth) - // we skip first two entries to skip "runtime.Callers" and "fixCallerHook.Fire". - n := runtime.Callers(2, programCounters) - frames := runtime.CallersFrames(programCounters[0:n]) - for { - frame, more := frames.Next() - if !strings.Contains(frame.Function, "github.com/linuxboot/contest/pkg/xcontext") && - !strings.Contains(strings.ToLower(frame.Function), "github.com/sirupsen/logrus") { - entry.Caller = &frame - return nil - } - - if !more { - // Unable to get out of the `xcontext` code, so using the earliest - // function. - // - // If this happened consider increasing of maxCallerScanDepth - entry.Caller = &frame - return nil - } - } -} diff --git a/pkg/xcontext/logger/logadapter/logrus/fix_caller_hook_test.go b/pkg/xcontext/logger/logadapter/logrus/fix_caller_hook_test.go deleted file mode 100644 index 75cdd784..00000000 --- a/pkg/xcontext/logger/logadapter/logrus/fix_caller_hook_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logrus - -import ( - "runtime" - "testing" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" -) - -func dummyFunc(fn func()) { - fn() -} - -func TestFixCallerHook(t *testing.T) { - programCounters := make([]uintptr, 1) - n := runtime.Callers(1, programCounters) - require.Equal(t, 1, n) - frames := runtime.CallersFrames(programCounters) - frame, more := frames.Next() - require.False(t, more) - entry := &logrus.Entry{Caller: &frame} - dummyFunc(func() { - err := fixCallerHook{}.Fire(entry) - require.NoError(t, err) - }) - - // testing.tRunner is the function which calls TestFixCallerHook - require.Equal(t, "testing.tRunner", entry.Caller.Func.Name()) -} diff --git a/pkg/xcontext/logger/logadapter/logrus/wrapper.go b/pkg/xcontext/logger/logadapter/logrus/wrapper.go deleted file mode 100644 index ed36f053..00000000 --- a/pkg/xcontext/logger/logadapter/logrus/wrapper.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logrus - -import ( - "context" - - "github.com/linuxboot/contest/pkg/xcontext/logger" - "github.com/linuxboot/contest/pkg/xcontext/logger/internal" - "github.com/sirupsen/logrus" -) - -var ( - _ internal.LoggerCompact = Wrapper{} -) - -type Fields = internal.Fields - -func wrap(backend *logrus.Entry) logger.Logger { - // Each structured logger has own types and we do intermediate methods - // to convert one types to another. And to do not duplicate - // Debugf/Infof/... in each such adapter we define only Logf - // and unroll it using internal.UncompactLoggerCompact. - - // Since we do all this wrapping the caller-detection in LogRus works - // wrong. To fix it we use a special hook `fixCallerHook`. But to do not - // define it multiple times on each wrapping of the logger, we recheck - // if it is already set. - foundTheHook := false - for _, hook := range backend.Logger.Hooks[logrus.ErrorLevel] { - _, foundTheHook = hook.(fixCallerHook) - if foundTheHook { - break - } - } - if !foundTheHook { - backend.Logger.AddHook(fixCallerHook{}) - } - - // And here we do the main idea of this function (`wrap`): - return internal.UncompactLoggerCompact{ - LoggerCompact: Wrapper{ - Backend: backend, - }, - } -} - -// Wrapper converts *logrus.Entry to internal.LoggerCompact (which could be -// easily converted to logger.Logger). -type Wrapper struct { - Backend *logrus.Entry -} - -type contextKey string - -// ContextKeyFormat is the key to extract log format from a log entry context. -const ContextKeyFormat = contextKey("format") - -// Logf implements internal.MinimalLoggerCompact. -func (l Wrapper) Logf(level logger.Level, format string, args ...interface{}) { - // Passing through "format" for better automatic error categorization - // by Sentry-like services. This way we can detect which exactly - // Errorf line was used even when lines being shifted up and down. - ctx := l.Backend.Context - if ctx == nil { - ctx = context.Background() - } - ctx = context.WithValue(ctx, ContextKeyFormat, format) - internal.MinimalLoggerLogf(l.Backend.WithContext(ctx), level, format, args...) -} - -// OriginalLogger implements internal.LoggerExtensions. -func (l Wrapper) OriginalLogger() interface{} { - return l.Backend -} - -// Level implements internal.WithLevels. -func (l Wrapper) Level() logger.Level { - return Adapter.ConvertLevel(l.Backend.Logger.Level) -} - -// WithLevel implements internal.WithLevels. -func (l Wrapper) WithLevel(logLevel logger.Level) logger.Logger { - // I haven't found an easier way to change loglevel for a child logger, - // but not to affect the loglevel of the parent. - newLogger := &logrus.Logger{ - Out: l.Backend.Logger.Out, - Hooks: l.Backend.Logger.Hooks, - Formatter: l.Backend.Logger.Formatter, - ReportCaller: l.Backend.Logger.ReportCaller, - Level: l.Backend.Logger.Level, - ExitFunc: l.Backend.Logger.ExitFunc, - } - newLogger.SetLevel(Adapter.Level(logLevel)) - return internal.UncompactLoggerCompact{LoggerCompact: Wrapper{ - Backend: &logrus.Entry{ - Logger: newLogger, - Data: l.Backend.Data, - Time: l.Backend.Time, - Context: l.Backend.Context, - }, - }} -} - -// WithField implements internal.WithFields. -func (l Wrapper) WithField(field string, value interface{}) logger.Logger { - return wrap(l.Backend.WithField(field, value)) -} - -// WithFields implements internal.WithFields. -func (l Wrapper) WithFields(fields Fields) logger.Logger { - return wrap(l.Backend.WithFields(map[string]interface{}(fields))) -} diff --git a/pkg/xcontext/logger/logadapter/zap/adapter.go b/pkg/xcontext/logger/logadapter/zap/adapter.go deleted file mode 100644 index 462b33d6..00000000 --- a/pkg/xcontext/logger/logadapter/zap/adapter.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package zap - -import ( - "fmt" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - - "github.com/linuxboot/contest/pkg/xcontext/logger" -) - -func init() { - logger.RegisterAdapter(Adapter) -} - -type adapter struct{} - -var ( - _ logger.Adapter = Adapter -) - -// Adapter is implementation of logger.Adapter for zap. -var Adapter = (*adapter)(nil) - -// Convert implements logger.Adapter. -func (_ *adapter) Convert(backend interface{}) logger.Logger { - switch backend := backend.(type) { - case *zap.Logger: - return wrap(backend.Sugar()) - case *zap.SugaredLogger: - return wrap(backend) - } - return nil -} - -// Level converts our logging level to zap logging level. -func (_ *adapter) Level(logLevel logger.Level) zapcore.Level { - switch logLevel { - case logger.LevelDebug: - return zapcore.DebugLevel - case logger.LevelInfo: - return zapcore.InfoLevel - case logger.LevelWarning: - return zapcore.WarnLevel - case logger.LevelError: - return zapcore.ErrorLevel - case logger.LevelPanic: - return zapcore.DPanicLevel - case logger.LevelFatal: - return zapcore.FatalLevel - default: - panic(fmt.Sprintf("should never happened: %v", logLevel)) - } -} - -// Level converts zap logging level to our logging level. -func (_ *adapter) ConvertLevel(level zapcore.Level) logger.Level { - switch level { - case zapcore.DebugLevel: - return logger.LevelDebug - case zapcore.InfoLevel: - return logger.LevelInfo - case zapcore.WarnLevel: - return logger.LevelWarning - case zapcore.ErrorLevel: - return logger.LevelError - case zapcore.PanicLevel, zapcore.DPanicLevel: - return logger.LevelPanic - case zapcore.FatalLevel: - return logger.LevelFatal - - } - return logger.LevelUndefined -} diff --git a/pkg/xcontext/logger/logadapter/zap/wrapper.go b/pkg/xcontext/logger/logadapter/zap/wrapper.go deleted file mode 100644 index 6a0d076c..00000000 --- a/pkg/xcontext/logger/logadapter/zap/wrapper.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package zap - -import ( - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - - "github.com/linuxboot/contest/pkg/xcontext/fields" - "github.com/linuxboot/contest/pkg/xcontext/logger" - "github.com/linuxboot/contest/pkg/xcontext/logger/internal" -) - -var ( - _ internal.LoggerCompact = Wrapper{} -) - -type Fields = fields.Fields - -func wrap(backend *zap.SugaredLogger) logger.Logger { - // Each structured logger has own types and we do intermediate methods - // to convert one types to another. And to do not duplicate - // Debugf/Infof/... in each such adapter we define only Logf - // and unroll it using internal.UncompactLoggerCompact. - return internal.UncompactLoggerCompact{ - LoggerCompact: Wrapper{ - Backend: backend, - }, - } -} - -// Wrapper converts *zap.SugaredLogger to internal.LoggerCompact (which could be -// easily converted to logger.Logger). -type Wrapper struct { - Backend *zap.SugaredLogger -} - -// Logf implements internal.MinimalLoggerCompact. -func (l Wrapper) Logf(level logger.Level, format string, args ...interface{}) { - // Passing through "format" for better automatic error categorization - // by Sentry-like services. This way we can detect which exactly - // Errorf line was used even when lines being shifted up and down. - internal.MinimalLoggerLogf(l.Backend.Named(format), level, format, args...) -} - -// OriginalLogger implements internal.LoggerExtensions. -func (l Wrapper) OriginalLogger() interface{} { - return l.Backend -} - -// Level implements internal.WithLevels. -func (l Wrapper) Level() logger.Level { - enabledFn := l.Backend.Desugar().Core().Enabled - for _, level := range []zapcore.Level{ - zap.DebugLevel, - zap.InfoLevel, - zap.WarnLevel, - zap.ErrorLevel, - zap.DPanicLevel, - zap.PanicLevel, - zap.FatalLevel, - } { - if enabledFn(level) { - return Adapter.ConvertLevel(level) - } - } - - return logger.LevelUndefined -} - -// WithLevel implements internal.WithLevels. -func (l Wrapper) WithLevel(logLevel logger.Level) logger.Logger { - return wrap( - l.Backend.Desugar(). - WithOptions( - zap.IncreaseLevel(Adapter.Level(logLevel)), - ).Sugar(), - ) -} - -// WithField implements internal.WithFields. -func (l Wrapper) WithField(field string, value interface{}) logger.Logger { - return wrap(l.Backend.With(field, value)) -} - -// WithFields implements internal.WithFields. -func (l Wrapper) WithFields(fields Fields) logger.Logger { - args := make([]interface{}, 0, len(fields)*2) - for k, v := range fields { - args = append(args, k, v) - } - return wrap(l.Backend.With(args...)) -} diff --git a/pkg/xcontext/logger/logger.go b/pkg/xcontext/logger/logger.go deleted file mode 100644 index 1f13bd65..00000000 --- a/pkg/xcontext/logger/logger.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logger - -import ( - "github.com/linuxboot/contest/pkg/xcontext/logger/internal" -) - -// Logger is the interface of a logger provided by an extended context. -// -// This is the complete logger with all the required methods/features. -type Logger = internal.Logger - -// MinimalLogger is the interfaces of a logger without contextual methods. -type MinimalLogger = internal.MinimalLogger - -// ConvertLogger converts arbitrary logger to Logger. If it was unable to -// then it returns a nil. -// -// To enable logadapter-s for this converter add imports, for example: -// -// import _ "github.com/linuxboot/contest/pkg/xcontext/logger/logadapter/logrus" -// import _ "github.com/linuxboot/contest/pkg/xcontext/logger/logadapter/zap" -func ConvertLogger(logger interface{}) Logger { - if l, ok := logger.(Logger); ok { - return l - } - - for _, adapter := range adapters { - if convertedLogger := adapter.Convert(logger); convertedLogger != nil { - return convertedLogger - } - } - - switch logger := logger.(type) { - case internal.MinimalLogger: - return internal.WrapMinimalLogger(logger) - case internal.MinimalLoggerCompact: - return internal.WrapMinimalLoggerCompact(logger) - case func(format string, args ...interface{}): - return internal.WrapPrintf(logger) - case func(format string, args ...interface{}) (int, error): - return internal.WrapPrintf(func(format string, args ...interface{}) { - _, _ = logger(format, args...) - }) - } - - return nil -} - -// Adapter defines an adapter to convert a logger to Logger. -type Adapter interface { - Convert(backend interface{}) Logger -} - -var ( - adapters []Adapter -) - -// RegisterAdapter registers an Adapter to be used by ConvertLogger. -func RegisterAdapter(adapter Adapter) { - adapters = append(adapters, adapter) -} - -// Dummy returns a dummy logger which implements Logger, but does nothing. -func Dummy() Logger { - return ConvertLogger(internal.DummyLogger{}) -} diff --git a/pkg/xcontext/logger/logger_test.go b/pkg/xcontext/logger/logger_test.go deleted file mode 100644 index 9f975d85..00000000 --- a/pkg/xcontext/logger/logger_test.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package logger - -import ( - "fmt" - "testing" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" - "go.uber.org/zap" -) - -func TestConvertLogger(t *testing.T) { - require.NotNil(t, ConvertLogger(fmt.Printf)) - require.NotNil(t, ConvertLogger(logrus.New())) - require.NotNil(t, ConvertLogger(zap.NewExample().Sugar())) - require.Nil(t, ConvertLogger(zap.NewExample())) -} diff --git a/pkg/xcontext/metrics/interface.go b/pkg/xcontext/metrics/interface.go deleted file mode 100644 index 1de58c21..00000000 --- a/pkg/xcontext/metrics/interface.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package metrics - -import ( - "github.com/linuxboot/contest/pkg/xcontext/fields" -) - -type Fields = fields.Fields - -// Metrics is a handler of metrics (like Prometheus, ODS) -type Metrics interface { - // Gauge returns the float64 gauge metric with key "key". - Gauge(key string) Gauge - - // IntGauge returns the int64 gauge metric with key "key". - IntGauge(key string) IntGauge - - // Count returns the counter metric with key "key". - Count(key string) Count - - // WithTag returns scoped Metrics with an added tag to be reported with the metrics. - // - // In terms of Prometheus the "tags" are called "labels". - WithTag(key string, value interface{}) Metrics - - // WithTags returns scoped Metrics with added tags to be reported with the metrics. - // - // In terms of Prometheus the "tags" are called "labels". - // - // Value "nil" resets tags. - WithTags(fields Fields) Metrics -} - -// Gauge is a float64 gauge metric. -// -// See also https://prometheus.io/docs/concepts/metric_types/ -type Gauge interface { - // Add adds value "v" to the metric and returns the result. - Add(v float64) float64 - - // WithOverriddenTags returns scoped Gauge with replaced tags to be reported with the metrics. - // - // In terms of Prometheus the "tags" are called "labels". - WithOverriddenTags(fields.Fields) Gauge -} - -// IntGauge is a int64 gauge metric. -// -// See also https://prometheus.io/docs/concepts/metric_types/ -type IntGauge interface { - // Add adds value "v" to the metric and returns the result. - Add(v int64) int64 - - // WithOverriddenTags returns scoped IntGauge with replaced tags to be reported with the metrics. - // - // In terms of Prometheus the "tags" are called "labels". - WithOverriddenTags(Fields) IntGauge -} - -// Count is a counter metric. -// -// See also https://prometheus.io/docs/concepts/metric_types/ -type Count interface { - // Add adds value "v" to the metric and returns the result. - Add(v uint64) uint64 - - // WithOverriddenTags returns scoped Count with replaced tags to be reported with the metrics. - // - // In terms of Prometheus the "tags" are called "labels". - WithOverriddenTags(Fields) Count -} diff --git a/pkg/xcontext/metrics/prometheus/count.go b/pkg/xcontext/metrics/prometheus/count.go deleted file mode 100644 index b1e3aee8..00000000 --- a/pkg/xcontext/metrics/prometheus/count.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package prometheus - -import ( - "sync" - - "github.com/linuxboot/contest/pkg/xcontext/metrics" - "github.com/prometheus/client_golang/prometheus" - io_prometheus_client "github.com/prometheus/client_model/go" -) - -var ( - _ metrics.Count = &Count{} -) - -// Count is an implementation of metrics.Count. -type Count struct { - sync.Mutex - *Metrics - Key string - *CounterVec - io_prometheus_client.Metric - prometheus.Counter -} - -// Add implementations metrics.Count. -func (metric *Count) Add(delta uint64) uint64 { - metric.Counter.Add(float64(delta)) - metric.Lock() - defer metric.Unlock() - err := metric.Write(&metric.Metric) - if err != nil { - panic(err) - } - return uint64(*metric.Metric.Counter.Value) -} - -// WithOverriddenTags implementations metrics.Count. -func (metric *Count) WithOverriddenTags(tags Fields) metrics.Count { - result, err := metric.CounterVec.GetMetricWith(tagsToLabels(tags)) - if err == nil { - return &Count{Metrics: metric.Metrics, Key: metric.Key, CounterVec: metric.CounterVec, Counter: result} - } - - return metric.Metrics.WithTags(nil).WithTags(tags).Count(metric.Key) -} diff --git a/pkg/xcontext/metrics/prometheus/gauge.go b/pkg/xcontext/metrics/prometheus/gauge.go deleted file mode 100644 index f55a3770..00000000 --- a/pkg/xcontext/metrics/prometheus/gauge.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package prometheus - -import ( - "sync" - - "github.com/linuxboot/contest/pkg/xcontext/metrics" - "github.com/prometheus/client_golang/prometheus" - io_prometheus_client "github.com/prometheus/client_model/go" -) - -var ( - _ metrics.Gauge = &Gauge{} -) - -// Gauge is an implementation of metrics.Gauge. -type Gauge struct { - sync.Mutex - *Metrics - Key string - *GaugeVec - io_prometheus_client.Metric - prometheus.Gauge -} - -// Add implementations metrics.Count. -func (metric *Gauge) Add(delta float64) float64 { - metric.Gauge.Add(delta) - metric.Lock() - defer metric.Unlock() - err := metric.Write(&metric.Metric) - if err != nil { - panic(err) - } - return *metric.Metric.Gauge.Value -} - -// WithOverriddenTags implementations metrics.Count. -func (metric *Gauge) WithOverriddenTags(tags Fields) metrics.Gauge { - result, err := metric.GaugeVec.GetMetricWith(tagsToLabels(tags)) - if err == nil { - return &Gauge{Metrics: metric.Metrics, Key: metric.Key, GaugeVec: metric.GaugeVec, Gauge: result} - } - - return metric.Metrics.WithTags(nil).WithTags(tags).Gauge(metric.Key) -} diff --git a/pkg/xcontext/metrics/prometheus/gauge_int.go b/pkg/xcontext/metrics/prometheus/gauge_int.go deleted file mode 100644 index 68a7c6e7..00000000 --- a/pkg/xcontext/metrics/prometheus/gauge_int.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package prometheus - -import ( - "sync" - - "github.com/linuxboot/contest/pkg/xcontext/metrics" - "github.com/prometheus/client_golang/prometheus" - io_prometheus_client "github.com/prometheus/client_model/go" -) - -var ( - _ metrics.IntGauge = &IntGauge{} -) - -// IntGauge is an implementation of metrics.IntGauge. -type IntGauge struct { - sync.Mutex - *Metrics - Key string - *GaugeVec - io_prometheus_client.Metric - prometheus.Gauge -} - -// Add implementations metrics.Count. -func (metric *IntGauge) Add(delta int64) int64 { - metric.Gauge.Add(float64(delta)) - metric.Lock() - defer metric.Unlock() - err := metric.Write(&metric.Metric) - if err != nil { - panic(err) - } - return int64(*metric.Metric.Gauge.Value) -} - -// WithOverriddenTags implementations metrics.Count. -func (metric *IntGauge) WithOverriddenTags(tags Fields) metrics.IntGauge { - result, err := metric.GaugeVec.GetMetricWith(tagsToLabels(tags)) - if err == nil { - return &IntGauge{Metrics: metric.Metrics, Key: metric.Key, GaugeVec: metric.GaugeVec, Gauge: result} - } - - return metric.Metrics.WithTags(nil).WithTags(tags).IntGauge(metric.Key) -} diff --git a/pkg/xcontext/metrics/prometheus/hacks.go b/pkg/xcontext/metrics/prometheus/hacks.go deleted file mode 100644 index 3a55aac6..00000000 --- a/pkg/xcontext/metrics/prometheus/hacks.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package prometheus - -import ( - "sync" - - "github.com/prometheus/client_golang/prometheus" - "github.com/xaionaro-go/unsafetools" -) - -// prometheus does not support full unregister. Therefore we add code -// to do so. -// -// See also: https://github.com/prometheus/client_golang/issues/203 -func unregister(registerer prometheus.Registerer, c prometheus.Collector) bool { - if !registerer.Unregister(c) { - return false - } - - descChan := make(chan *prometheus.Desc, 10) - go func() { - c.Describe(descChan) - close(descChan) - }() - - locker := unsafetools.FieldByName(registerer, "mtx").(*sync.RWMutex) - - dimHashesByName := *unsafetools.FieldByName(registerer, "dimHashesByName").(*map[string]uint64) - - locker.Lock() - defer locker.Unlock() - - for desc := range descChan { - delete(dimHashesByName, *unsafetools.FieldByName(desc, "fqName").(*string)) - } - - return true -} diff --git a/pkg/xcontext/metrics/prometheus/metrics.go b/pkg/xcontext/metrics/prometheus/metrics.go deleted file mode 100644 index ce0574bc..00000000 --- a/pkg/xcontext/metrics/prometheus/metrics.go +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package prometheus - -import ( - "fmt" - "sort" - "strconv" - "strings" - "sync" - - "github.com/linuxboot/contest/pkg/xcontext/fields" - "github.com/linuxboot/contest/pkg/xcontext/metrics" - "github.com/prometheus/client_golang/prometheus" -) - -var _ metrics.Metrics = &Metrics{} - -type Fields = fields.Fields - -func mergeSortedStrings(dst []string, add ...string) []string { - if len(add) == 0 { - return dst - } - if len(dst) == 0 { - return append([]string{}, add...) - } - - dstLen := len(dst) - - if !sort.StringsAreSorted(dst) || !sort.StringsAreSorted(add) { - panic(fmt.Sprintf("%v %v", sort.StringsAreSorted(dst), sort.StringsAreSorted(add))) - } - - i, j := 0, 0 - for i < dstLen && j < len(add) { - switch strings.Compare(dst[i], add[j]) { - case -1: - i++ - case 0: - i++ - j++ - case 1: - dst = append(dst, add[j]) - j++ - } - } - dst = append(dst, add[j:]...) - sort.Strings(dst) - return dst -} - -func labelsWithPlaceholders(labels prometheus.Labels, placeholders []string) prometheus.Labels { - if len(labels) == len(placeholders) { - return labels - } - result := make(prometheus.Labels, len(placeholders)) - for k, v := range labels { - result[k] = v - } - for _, s := range placeholders { - if _, ok := result[s]; ok { - continue - } - result[s] = "" - } - return result -} - -type CounterVec struct { - *prometheus.CounterVec - Key string - PossibleLabels []string -} - -func (v *CounterVec) AddPossibleLabels(newLabels []string) { - v.PossibleLabels = mergeSortedStrings(v.PossibleLabels, newLabels...) -} - -func (v *CounterVec) GetMetricWith(labels prometheus.Labels) (prometheus.Counter, error) { - return v.CounterVec.GetMetricWith(labelsWithPlaceholders(labels, v.PossibleLabels)) -} - -type GaugeVec struct { - *prometheus.GaugeVec - Key string - PossibleLabels []string -} - -func (v *GaugeVec) AddPossibleLabels(newLabels []string) { - v.PossibleLabels = mergeSortedStrings(v.PossibleLabels, newLabels...) -} - -func (v *GaugeVec) GetMetricWith(labels prometheus.Labels) (prometheus.Gauge, error) { - return v.GaugeVec.GetMetricWith(labelsWithPlaceholders(labels, v.PossibleLabels)) -} - -type persistentData struct { - storage - config -} - -type storage struct { - locker sync.Mutex - registerer prometheus.Registerer - gatherer prometheus.Gatherer - count map[string]*CounterVec - gauge map[string]*GaugeVec - intGauge map[string]*GaugeVec -} - -// Metrics implements a wrapper of prometheus metrics to implement -// metrics.Metrics. -// -// Pretty slow and naive implementation. Could be improved by on-need basis. -// If you need a faster implementation, then try `tsmetrics`. -// -// Warning! This implementation does not remove automatically metrics, thus -// if a metric was created once, it will be kept in memory forever. -// If you need a version of metrics which automatically removes metrics -// non-used for a long time, then try `tsmetrics`. -// -// Warning! Prometheus does not support changing amount of labels for a metric, -// therefore we delete and create a metric from scratch if it is required to -// extend the set of labels. This procedure leads to a reset of the metric -// value. -// If you need a version of metrics which does not have such flaw, then -// try `tsmetrics` or `simplemetrics`. -type Metrics struct { - *persistentData - labels prometheus.Labels - labelNames []string -} - -// New returns a new instance of Metrics -func New(registerer prometheus.Registerer, gatherer prometheus.Gatherer, opts ...Option) *Metrics { - m := &Metrics{ - persistentData: &persistentData{ - storage: storage{ - registerer: registerer, - gatherer: gatherer, - count: map[string]*CounterVec{}, - gauge: map[string]*GaugeVec{}, - intGauge: map[string]*GaugeVec{}, - }, - config: options(opts).Config(), - }, - } - return m -} - -func (m *Metrics) List() []prometheus.Collector { - m.storage.locker.Lock() - defer m.storage.locker.Unlock() - result := make([]prometheus.Collector, 0, len(m.storage.count)+len(m.storage.gauge)+len(m.storage.intGauge)) - - for _, count := range m.storage.count { - result = append(result, count.CounterVec) - } - - for _, gauge := range m.storage.gauge { - result = append(result, gauge.GaugeVec) - } - - for _, intGauge := range m.storage.intGauge { - result = append(result, intGauge.GaugeVec) - } - - return result -} - -func (m *Metrics) Registerer() prometheus.Registerer { - return m.registerer -} - -// Added the Gatherer, so that the metric can be easily exported -func (m *Metrics) Gatherer() prometheus.Gatherer { - return m.gatherer -} - -func (m *Metrics) getOrCreateCountVec(key string, possibleLabelNames []string) *CounterVec { - counterVec := m.count[key] - if counterVec != nil { - return counterVec - } - - counterVec = &CounterVec{ - CounterVec: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: key + "_count", - }, possibleLabelNames), - Key: key, - PossibleLabels: possibleLabelNames, - } - - m.count[key] = counterVec - - if m.registerer != nil { - err := m.registerer.Register(counterVec) - if err != nil { - panic(fmt.Sprintf("key: '%v', err: %v", key, err)) - } - } - - return counterVec -} - -func (m *Metrics) deleteCountVec(counterVec *CounterVec) { - if m.registerer != nil { - if !unregister(m.registerer, counterVec.CounterVec) { - panic(counterVec) - } - } - delete(m.count, counterVec.Key) -} - -// Count implements context.Metrics (see the description in the interface). -func (m *Metrics) Count(key string) metrics.Count { - m.storage.locker.Lock() - defer m.storage.locker.Unlock() - - counterVec := m.getOrCreateCountVec(key, m.labelNames) - - counter, err := counterVec.GetMetricWith(m.labels) - if err != nil { - m.deleteCountVec(counterVec) - counterVec.AddPossibleLabels(m.labelNames) - counterVec = m.getOrCreateCountVec(key, counterVec.PossibleLabels) - counter, err = counterVec.GetMetricWith(m.labels) - if err != nil { - panic(err) - } - } - - return &Count{Metrics: m, Key: key, CounterVec: counterVec, Counter: counter} -} - -func (m *Metrics) getOrCreateGaugeVec(key string, possibleLabelNames []string) *GaugeVec { - gaugeVec := m.gauge[key] - if gaugeVec != nil { - return gaugeVec - } - - _gaugeVec := prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Name: key + "_float", - }, possibleLabelNames) - - gaugeVec = &GaugeVec{ - GaugeVec: _gaugeVec, - Key: key, - PossibleLabels: possibleLabelNames, - } - - m.gauge[key] = gaugeVec - - if m.registerer != nil { - err := m.registerer.Register(gaugeVec) - if err != nil { - panic(fmt.Sprintf("key: '%v', err: %v", key, err)) - } - } - - return gaugeVec -} - -func (m *Metrics) deleteGaugeVec(gaugeVec *GaugeVec) { - if m.registerer != nil { - if !unregister(m.registerer, gaugeVec.GaugeVec) { - panic(gaugeVec) - } - } - delete(m.gauge, gaugeVec.Key) -} - -// Gauge implements context.Metrics (see the description in the interface). -func (m *Metrics) Gauge(key string) metrics.Gauge { - m.storage.locker.Lock() - defer m.storage.locker.Unlock() - - gaugeVec := m.getOrCreateGaugeVec(key, m.labelNames) - - gauge, err := gaugeVec.GetMetricWith(m.labels) - if err != nil { - m.deleteGaugeVec(gaugeVec) - gaugeVec.AddPossibleLabels(m.labelNames) - gaugeVec = m.getOrCreateGaugeVec(key, gaugeVec.PossibleLabels) - gauge, err = gaugeVec.GetMetricWith(m.labels) - if err != nil { - panic(err) - } - } - - return &Gauge{Metrics: m, Key: key, GaugeVec: gaugeVec, Gauge: gauge} -} - -func (m *Metrics) getOrCreateIntGaugeVec(key string, possibleLabelNames []string) *GaugeVec { - gaugeVec := m.intGauge[key] - if gaugeVec != nil { - return gaugeVec - } - - _gaugeVec := prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Name: key + "_int", - }, possibleLabelNames) - - gaugeVec = &GaugeVec{ - GaugeVec: _gaugeVec, - Key: key, - PossibleLabels: possibleLabelNames, - } - - m.intGauge[key] = gaugeVec - - if m.registerer != nil { - err := m.registerer.Register(gaugeVec) - if err != nil { - panic(fmt.Sprintf("key: '%v', err: %v", key, err)) - } - } - - return gaugeVec -} - -func (m *Metrics) deleteIntGaugeVec(intGaugeVec *GaugeVec) { - if m.registerer != nil { - if !unregister(m.registerer, intGaugeVec) { - panic(intGaugeVec) - } - } - delete(m.intGauge, intGaugeVec.Key) -} - -// IntGauge implements context.Metrics (see the description in the interface). -func (m *Metrics) IntGauge(key string) metrics.IntGauge { - m.storage.locker.Lock() - defer m.storage.locker.Unlock() - - gaugeVec := m.getOrCreateIntGaugeVec(key, m.labelNames) - - gauge, err := gaugeVec.GetMetricWith(m.labels) - if err != nil { - m.deleteIntGaugeVec(gaugeVec) - gaugeVec.AddPossibleLabels(m.labelNames) - gaugeVec = m.getOrCreateIntGaugeVec(key, gaugeVec.PossibleLabels) - gauge, err = gaugeVec.GetMetricWith(m.labels) - if err != nil { - panic(err) - } - } - - return &IntGauge{Metrics: m, Key: key, GaugeVec: gaugeVec, Gauge: gauge} -} - -// WithTag implements context.Metrics (see the description in the interface). -func (m *Metrics) WithTag(key string, value interface{}) metrics.Metrics { - if m.config.DisableLabels { - return m - } - - result := &Metrics{ - persistentData: m.persistentData, - } - - result.labels = make(prometheus.Labels, len(m.labels)) - for k, v := range m.labels { - result.labels[k] = v - } - - result.labels[key] = TagValueToString(value) - - labelNames := make([]string, 0, len(result.labels)) - for k := range result.labels { - labelNames = append(labelNames, k) - } - sort.Strings(labelNames) - result.labelNames = labelNames - - return result -} - -// WithTags implements context.Metrics (see the description in the interface). -func (m *Metrics) WithTags(tags Fields) metrics.Metrics { - if m.config.DisableLabels { - return m - } - - result := &Metrics{ - persistentData: m.persistentData, - } - if tags == nil { - return result - } - - result.labels = make(prometheus.Labels, len(m.labels)+len(tags)) - for k, v := range m.labels { - result.labels[k] = v - } - for k, v := range tags { - result.labels[k] = TagValueToString(v) - } - - labelNames := make([]string, 0, len(result.labels)) - for k := range result.labels { - labelNames = append(labelNames, k) - } - sort.Strings(labelNames) - result.labelNames = labelNames - - return result -} - -func tagsToLabels(tags Fields) prometheus.Labels { - labels := make(prometheus.Labels, len(tags)) - for k, v := range tags { - labels[k] = TagValueToString(v) - } - return labels -} - -const prebakeMax = 65536 - -var prebackedString [prebakeMax * 2]string - -func init() { - for i := -prebakeMax; i < prebakeMax; i++ { - prebackedString[i+prebakeMax] = strconv.FormatInt(int64(i), 10) - } -} - -func getPrebakedString(v int32) string { - if v >= prebakeMax || -v <= -prebakeMax { - return "" - } - return prebackedString[v+prebakeMax] -} - -// TagValueToString converts any value to a string, which could be used -// as label value in prometheus. -func TagValueToString(vI interface{}) string { - switch v := vI.(type) { - case int: - r := getPrebakedString(int32(v)) - if len(r) != 0 { - return r - } - return strconv.FormatInt(int64(v), 10) - case uint64: - r := getPrebakedString(int32(v)) - if len(r) != 0 { - return r - } - return strconv.FormatUint(v, 10) - case int64: - r := getPrebakedString(int32(v)) - if len(r) != 0 { - return r - } - return strconv.FormatInt(v, 10) - case string: - return strings.Replace(v, ",", "_", -1) - case bool: - switch v { - case true: - return "true" - case false: - return "false" - } - case []byte: - return string(v) - case nil: - return "null" - case interface{ String() string }: - return strings.Replace(v.String(), ",", "_", -1) - } - - return "" -} diff --git a/pkg/xcontext/metrics/prometheus/metrics_test.go b/pkg/xcontext/metrics/prometheus/metrics_test.go deleted file mode 100644 index 113fa361..00000000 --- a/pkg/xcontext/metrics/prometheus/metrics_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package prometheus - -import ( - "sort" - "strings" - "testing" - - "github.com/linuxboot/contest/pkg/xcontext/fields" - "github.com/linuxboot/contest/pkg/xcontext/metrics" - metricstester "github.com/linuxboot/contest/pkg/xcontext/metrics/test" - "github.com/prometheus/client_golang/prometheus" - "github.com/stretchr/testify/require" -) - -func TestMetrics(t *testing.T) { - for name, registerer := range map[string]prometheus.Registerer{ - "WithRegisterer": prometheus.NewRegistry(), - "WithoutRegisterer": nil, - } { - t.Run(name, func(t *testing.T) { - metricstester.TestMetrics(t, func() metrics.Metrics { - // Current implementation resets metrics if new label appears, - // thus some unit-tests fails (and the should). Specifically - // for prometheus we decided to tolerate this problem, therefore - // adding hacks to prevent a wrong values: pre-register metrics - // with all the labels beforehand. - m := New(registerer, nil) - m.WithTags(Fields{"testField": "", "anotherField": ""}).Count("WithOverriddenTags") - m.WithTags(Fields{"testField": "", "anotherField": ""}).Gauge("WithOverriddenTags") - m.WithTags(Fields{"testField": "", "anotherField": ""}).IntGauge("WithOverriddenTags") - - return m - }) - }) - } -} - -func TestMetricsList(t *testing.T) { - m := New(nil, nil) - m.WithTags(Fields{"testField": "", "anotherField": ""}).Count("test") - m.WithTags(Fields{"testField": "", "anotherField": ""}).Gauge("test") - m.WithTags(Fields{"testField": "", "anotherField": ""}).IntGauge("test") - m.WithTags(Fields{"testField": "a", "anotherField": ""}).Count("test") - m.WithTags(Fields{"testField": "b", "anotherField": ""}).Gauge("test") - m.WithTags(Fields{"testField": "c", "anotherField": ""}).IntGauge("test") - - list := m.List() - require.Len(t, list, 3) - for _, c := range list { - ch := make(chan prometheus.Metric, 10) - c.Collect(ch) - close(ch) - - count := 0 - for range ch { - count++ - } - require.Equal(t, 2, count) - } -} - -func TestMetricsRegistererDoubleUse(t *testing.T) { - registry := prometheus.NewRegistry() - metrics0 := New(registry, nil) - metrics1 := New(registry, nil) - - // these test cases should panic: - - t.Run("Count", func(t *testing.T) { - defer func() { - require.NotNil(t, recover()) - }() - - metrics0.Count("test") - metrics1.Count("test") - }) - - t.Run("Gauge", func(t *testing.T) { - defer func() { - require.NotNil(t, recover()) - }() - - metrics0.Gauge("test") - metrics1.Gauge("test") - }) - - t.Run("IntGauge", func(t *testing.T) { - defer func() { - require.NotNil(t, recover()) - }() - - metrics0.IntGauge("test") - metrics1.IntGauge("test") - }) -} - -func TestMergeSortedStrings(t *testing.T) { - slices := [][]string{ - {"a", "b", "c"}, - {"r", "a", "n", "d", "o", "m"}, - {"a", "rb", "", "it", "r", "ary"}, - } - for idx := range slices { - sort.Strings(slices[idx]) - } - for _, a := range slices { - for _, b := range slices { - t.Run(strings.Join(a, "-")+"_"+strings.Join(b, "-"), func(t *testing.T) { - m := map[string]struct{}{} - for _, aItem := range a { - m[aItem] = struct{}{} - } - for _, bItem := range b { - m[bItem] = struct{}{} - } - expected := make([]string, 0, len(m)) - for k := range m { - expected = append(expected, k) - } - sort.Strings(expected) - - require.Equal(t, expected, mergeSortedStrings(a, b...)) - }) - } - } -} - -func TestDisabledLabels(t *testing.T) { - registry := prometheus.NewRegistry() - var m metrics.Metrics = New(registry, nil, OptionDisableLabels(true)) - m = m.WithTag("1", 2) - c := m.Count("someCount") - require.Len(t, c.(*Count).labelNames, 0) - c = c.WithOverriddenTags(fields.Fields{"3": 4}) - require.Len(t, c.(*Count).labelNames, 0) -} diff --git a/pkg/xcontext/metrics/prometheus/option.go b/pkg/xcontext/metrics/prometheus/option.go deleted file mode 100644 index 396b5bfb..00000000 --- a/pkg/xcontext/metrics/prometheus/option.go +++ /dev/null @@ -1,29 +0,0 @@ -package prometheus - -// Option is an optional argument to function New, that changes the behavior of the metrics handler. -type Option interface { - apply(*config) -} - -type options []Option - -func (s options) Config() config { - var cfg config - for _, opt := range s { - opt.apply(&cfg) - } - return cfg -} - -type config struct { - DisableLabels bool -} - -// OptionDisableLabels disables the labels (tags) and makes all the metrics flat. -// Attempts to get a metrics with the same key but different tags will result into -// getting the same metric. And all the metrics will be registered without labels. -type OptionDisableLabels bool - -func (opt OptionDisableLabels) apply(cfg *config) { - cfg.DisableLabels = bool(opt) -} diff --git a/pkg/xcontext/metrics/simplemetrics/count.go b/pkg/xcontext/metrics/simplemetrics/count.go deleted file mode 100644 index 399e6b9a..00000000 --- a/pkg/xcontext/metrics/simplemetrics/count.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package simplemetrics - -import ( - "sync" - - "github.com/linuxboot/contest/pkg/xcontext/metrics" - "go.uber.org/atomic" -) - -var ( - _ metrics.Count = &Count{} -) - -type countFamily struct { - sync.RWMutex - Metrics map[string]*Count -} - -func (family *countFamily) get(tags tags) metrics.Count { - tagsKey := tagsToString(tags) - - family.RLock() - metric := family.Metrics[tagsKey] - family.RUnlock() - if metric != nil { - return metric - } - - family.Lock() - defer family.Unlock() - - metric = family.Metrics[tagsKey] - if metric != nil { - return metric - } - - metric = &Count{ - family: family, - } - family.Metrics[tagsKey] = metric - - return metric -} - -// Count is a naive implementation of Count. -type Count struct { - family *countFamily - atomic.Uint64 -} - -// WithOverriddenTags implements Count. -func (metric *Count) WithOverriddenTags(overrideTags Fields) metrics.Count { - var tags tags - tags.AddMultiple(overrideTags) - return metric.family.get(tags) -} diff --git a/pkg/xcontext/metrics/simplemetrics/gauge.go b/pkg/xcontext/metrics/simplemetrics/gauge.go deleted file mode 100644 index 38d5fd8f..00000000 --- a/pkg/xcontext/metrics/simplemetrics/gauge.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package simplemetrics - -import ( - "sync" - - "github.com/linuxboot/contest/pkg/xcontext/metrics" - "go.uber.org/atomic" -) - -var ( - _ metrics.Gauge = &Gauge{} -) - -type gaugeFamily struct { - sync.RWMutex - Metrics map[string]*Gauge -} - -func (family *gaugeFamily) get(tags tags) metrics.Gauge { - tagsKey := tagsToString(tags) - - family.RLock() - metric := family.Metrics[tagsKey] - family.RUnlock() - if metric != nil { - return metric - } - - family.Lock() - defer family.Unlock() - metric = family.Metrics[tagsKey] - if metric != nil { - return metric - } - - metric = &Gauge{ - Family: family, - } - family.Metrics[tagsKey] = metric - - return metric -} - -// Gauge is a naive implementation of Gauge. -type Gauge struct { - Family *gaugeFamily - atomic.Float64 -} - -// WithOverriddenTags implements Gauge. -func (metric *Gauge) WithOverriddenTags(overrideTags Fields) metrics.Gauge { - var tags tags - tags.AddMultiple(overrideTags) - return metric.Family.get(tags) -} diff --git a/pkg/xcontext/metrics/simplemetrics/int_gauge.go b/pkg/xcontext/metrics/simplemetrics/int_gauge.go deleted file mode 100644 index 021106d2..00000000 --- a/pkg/xcontext/metrics/simplemetrics/int_gauge.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package simplemetrics - -import ( - "sync" - - "github.com/linuxboot/contest/pkg/xcontext/metrics" - "go.uber.org/atomic" -) - -var ( - _ metrics.IntGauge = &IntGauge{} -) - -type intGaugeFamily struct { - sync.RWMutex - Metrics map[string]*IntGauge -} - -func (family *intGaugeFamily) get(tags tags) metrics.IntGauge { - tagsKey := tagsToString(tags) - - family.RLock() - metric := family.Metrics[tagsKey] - family.RUnlock() - if metric != nil { - return metric - } - - family.Lock() - defer family.Unlock() - metric = family.Metrics[tagsKey] - if metric != nil { - return metric - } - - metric = &IntGauge{ - Family: family, - } - family.Metrics[tagsKey] = metric - - return metric -} - -// IntGauge is a naive implementation of IntGauge. -type IntGauge struct { - Family *intGaugeFamily - atomic.Int64 -} - -// WithOverriddenTags implements IntGauge. -func (metric *IntGauge) WithOverriddenTags(overrideTags Fields) metrics.IntGauge { - var tags tags - tags.AddMultiple(overrideTags) - return metric.Family.get(tags) -} diff --git a/pkg/xcontext/metrics/simplemetrics/metrics.go b/pkg/xcontext/metrics/simplemetrics/metrics.go deleted file mode 100644 index e8011a38..00000000 --- a/pkg/xcontext/metrics/simplemetrics/metrics.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package simplemetrics - -import ( - "fmt" - "sort" - "strings" - "sync" - - "github.com/linuxboot/contest/pkg/xcontext/fields" - "github.com/linuxboot/contest/pkg/xcontext/metrics" -) - -type Fields = fields.Fields -type tags = fields.PendingFields - -var _ metrics.Metrics = &Metrics{} - -type storage struct { - locker sync.RWMutex - intGaugeFamilies map[string]*intGaugeFamily - gaugeFamilies map[string]*gaugeFamily - countFamilies map[string]*countFamily -} - -// Metrics is a naive implementation of Metrics -type Metrics struct { - *storage - currentTags tags -} - -// New returns an instance of Metrics. -func New() *Metrics { - return &Metrics{ - storage: &storage{ - intGaugeFamilies: make(map[string]*intGaugeFamily), - gaugeFamilies: make(map[string]*gaugeFamily), - countFamilies: make(map[string]*countFamily), - }, - } -} - -func tagsToString(tags tags) string { - m := tags.Compile() - tagStrings := make([]string, 0, len(m)) - for key, value := range m { - tagStrings = append(tagStrings, strings.ReplaceAll(fmt.Sprintf("%s=%v", key, value), ",", "_")) - } - sort.Slice(tagStrings, func(i, j int) bool { - return tagStrings[i] < tagStrings[j] - }) - return strings.Join(tagStrings, ",") -} - -// Count returns Count. -// -// This method implements Metrics. -func (metrics *Metrics) Count(key string) metrics.Count { - metrics.storage.locker.RLock() - family := metrics.countFamilies[key] - metrics.storage.locker.RUnlock() - if family != nil { - return family.get(metrics.currentTags) - } - - metrics.storage.locker.Lock() - defer metrics.storage.locker.Unlock() - family = metrics.countFamilies[key] - if family != nil { - return family.get(metrics.currentTags) - } - - family = &countFamily{ - Metrics: make(map[string]*Count), - } - metrics.countFamilies[key] = family - - return family.get(metrics.currentTags) -} - -// Gauge returns Gauge. -// -// This method implements Metrics. -func (metrics *Metrics) Gauge(key string) metrics.Gauge { - metrics.storage.locker.RLock() - family := metrics.gaugeFamilies[key] - metrics.storage.locker.RUnlock() - if family != nil { - return family.get(metrics.currentTags) - } - - metrics.storage.locker.Lock() - defer metrics.storage.locker.Unlock() - family = metrics.gaugeFamilies[key] - if family != nil { - return family.get(metrics.currentTags) - } - - family = &gaugeFamily{ - Metrics: make(map[string]*Gauge), - } - metrics.gaugeFamilies[key] = family - - return family.get(metrics.currentTags) -} - -// IntGauge returns IntGauge. -// -// This method implements Metrics. -func (metrics *Metrics) IntGauge(key string) metrics.IntGauge { - metrics.storage.locker.RLock() - family := metrics.intGaugeFamilies[key] - metrics.storage.locker.RUnlock() - if family != nil { - return family.get(metrics.currentTags) - } - - metrics.storage.locker.Lock() - defer metrics.storage.locker.Unlock() - family = metrics.intGaugeFamilies[key] - if family != nil { - return family.get(metrics.currentTags) - } - - family = &intGaugeFamily{ - Metrics: make(map[string]*IntGauge), - } - metrics.intGaugeFamilies[key] = family - - return family.get(metrics.currentTags) -} - -// WithTag returns a scope of Metrics with added field. -// -// This method implements Metrics. -func (metrics Metrics) WithTag(key string, value interface{}) metrics.Metrics { - if metrics.currentTags.Slice != nil { - metrics.currentTags.IsReadOnly = true - } - metrics.currentTags.AddOne(key, value) - return &metrics -} - -// WithTags returns a scope of Metrics with added fields. -// -// This method implements Metrics. -func (metrics Metrics) WithTags(tags Fields) metrics.Metrics { - if tags == nil { - metrics.currentTags.IsReadOnly = false - metrics.currentTags.Slice = nil - return &metrics - } - if metrics.currentTags.Slice != nil { - metrics.currentTags.IsReadOnly = true - } - metrics.currentTags.AddMultiple(tags) - return &metrics -} diff --git a/pkg/xcontext/metrics/simplemetrics/metrics_test.go b/pkg/xcontext/metrics/simplemetrics/metrics_test.go deleted file mode 100644 index c9083d94..00000000 --- a/pkg/xcontext/metrics/simplemetrics/metrics_test.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package simplemetrics - -import ( - "testing" - - "github.com/linuxboot/contest/pkg/xcontext/metrics" - metricstester "github.com/linuxboot/contest/pkg/xcontext/metrics/test" -) - -func TestMetrics(t *testing.T) { - metricstester.TestMetrics(t, func() metrics.Metrics { - return New() - }) -} diff --git a/pkg/xcontext/metrics/test/test_utils.go b/pkg/xcontext/metrics/test/test_utils.go deleted file mode 100644 index 5d9da7d8..00000000 --- a/pkg/xcontext/metrics/test/test_utils.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package metricstester - -import ( - "testing" - - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/metrics" - "github.com/stretchr/testify/require" -) - -type Fields = xcontext.Fields - -// testMetric tests metric and returns the resulting value of the metric -func testMetric(t *testing.T, metrics metrics.Metrics, key string, tags Fields, overrideTags Fields, metricType string, expectedValue float64) float64 { - switch metricType { - case "Count": - metric := metrics.WithTags(tags).Count(key) - if overrideTags != nil { - metric = metric.WithOverriddenTags(overrideTags) - } - require.Equal(t, uint64(expectedValue+1), metric.Add(1)) - metric = metrics.WithTags(tags).Count(key) - if overrideTags != nil { - metric = metric.WithOverriddenTags(overrideTags) - } - require.Equal(t, uint64(expectedValue+2), metric.Add(1)) - scope := metrics - if overrideTags != nil { - scope = scope.WithTags(nil) - tags = overrideTags - } - for k, v := range tags { - scope = scope.WithTag(k, v) - } - metric = scope.Count(key) - require.Equal(t, uint64(expectedValue+3), metric.Add(1)) - return float64(metric.Add(0)) - case "Gauge": - metric := metrics.WithTags(tags).Gauge(key) - if overrideTags != nil { - metric = metric.WithOverriddenTags(overrideTags) - } - require.Equal(t, expectedValue-1.5, metric.Add(-1.5)) - metric = metrics.WithTags(tags).Gauge(key) - if overrideTags != nil { - metric = metric.WithOverriddenTags(overrideTags) - } - require.Equal(t, expectedValue-0.5, metric.Add(1)) - scope := metrics - if overrideTags != nil { - scope = scope.WithTags(nil) - tags = overrideTags - } - for k, v := range tags { - scope = scope.WithTag(k, v) - } - metric = scope.Gauge(key) - require.Equal(t, expectedValue+0.5, metric.Add(1)) - require.Equal(t, expectedValue, metric.Add(-0.5)) - return metric.Add(0) - case "IntGauge": - metric := metrics.WithTags(tags).IntGauge(key) - if overrideTags != nil { - metric = metric.WithOverriddenTags(overrideTags) - } - require.Equal(t, int64(-1), metric.Add(-1)) - metric = metrics.WithTags(tags).IntGauge(key) - if overrideTags != nil { - metric = metric.WithOverriddenTags(overrideTags) - } - require.Equal(t, int64(0), metric.Add(1)) - scope := metrics - if overrideTags != nil { - scope = scope.WithTags(nil) - tags = overrideTags - } - for k, v := range tags { - scope = scope.WithTag(k, v) - } - metric = scope.IntGauge(key) - require.Equal(t, int64(2), metric.Add(2)) - require.Equal(t, int64(0), metric.Add(-2)) - return float64(metric.Add(0)) - } - - panic(metricType) -} - -func TestMetrics(t *testing.T, metricsFactory func() metrics.Metrics) { - m := metricsFactory() - - for _, metricType := range []string{"Count", "Gauge", "IntGauge"} { - t.Run(metricType, func(t *testing.T) { - t.Run("hello_world", func(t *testing.T) { - testMetric(t, m, "hello_world", nil, nil, metricType, 0) - testMetric(t, m, "hello_world", Fields{ - "testField": "testValue", - }, nil, metricType, 0) - testMetric(t, m, "hello_world", Fields{ - "testField": "anotherValue", - }, nil, metricType, 0) - testMetric(t, m, "hello_world", Fields{ - "anotherField": "testValue", - }, nil, metricType, 0) - testMetric(t, m, "hello_world", Fields{ - "testField": "testValue", - "anotherField": "anotherValue", - }, nil, metricType, 0) - }) - t.Run("WithOverriddenTags", func(t *testing.T) { - key := "WithOverriddenTags" - tags := Fields{ - "testField": "testValue", - } - prevResult := testMetric(t, m, key, tags, nil, metricType, 0) - - wrongTags := Fields{ - "testField": "anotherValue", - } - prevResult = testMetric(t, m, key, wrongTags, tags, metricType, prevResult) - - wrongTags = Fields{ - "anotherField": "anotherValue", - } - testMetric(t, m, key, wrongTags, tags, metricType, prevResult) - }) - }) - } -} diff --git a/pkg/xcontext/metrics/tsmetrics/count.go b/pkg/xcontext/metrics/tsmetrics/count.go deleted file mode 100644 index b946f67b..00000000 --- a/pkg/xcontext/metrics/tsmetrics/count.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package tsmetrics - -import ( - "github.com/linuxboot/contest/pkg/xcontext/metrics" - tsmetrics "github.com/xaionaro-go/metrics" -) - -var ( - _ metrics.Count = &Count{} -) - -// Count is an implementation of metrics.Count. -type Count struct { - *Metrics - *tsmetrics.MetricCount -} - -// Add implementations metrics.Count. -func (metric Count) Add(delta uint64) uint64 { - return uint64(metric.MetricCount.Add(int64(delta))) -} - -// WithOverriddenTags implementations metrics.Count. -func (metric Count) WithOverriddenTags(tags Fields) metrics.Count { - key := metric.MetricCount.GetName() - return Count{ - Metrics: metric.Metrics, - MetricCount: metric.Metrics.Registry.Count(key, tsmetrics.Tags(tags)), - } -} diff --git a/pkg/xcontext/metrics/tsmetrics/gauge.go b/pkg/xcontext/metrics/tsmetrics/gauge.go deleted file mode 100644 index 98f5bc4b..00000000 --- a/pkg/xcontext/metrics/tsmetrics/gauge.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package tsmetrics - -import ( - "github.com/linuxboot/contest/pkg/xcontext/metrics" - tsmetrics "github.com/xaionaro-go/metrics" -) - -var ( - _ metrics.Gauge = &Gauge{} -) - -// Gauge is an implementation of metrics.Gauge. -type Gauge struct { - *Metrics - *tsmetrics.MetricGaugeFloat64 -} - -// Add implementations metrics.Count. -func (metric Gauge) Add(delta float64) float64 { - return metric.MetricGaugeFloat64.Add(delta) -} - -// WithOverriddenTags implementations metrics.Count. -func (metric Gauge) WithOverriddenTags(tags Fields) metrics.Gauge { - key := metric.MetricGaugeFloat64.GetName() - return Gauge{ - Metrics: metric.Metrics, - MetricGaugeFloat64: metric.Metrics.Registry.GaugeFloat64(key, tsmetrics.Tags(tags)), - } -} diff --git a/pkg/xcontext/metrics/tsmetrics/gauge_int.go b/pkg/xcontext/metrics/tsmetrics/gauge_int.go deleted file mode 100644 index c33f98c9..00000000 --- a/pkg/xcontext/metrics/tsmetrics/gauge_int.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package tsmetrics - -import ( - "github.com/linuxboot/contest/pkg/xcontext/metrics" - tsmetrics "github.com/xaionaro-go/metrics" -) - -var ( - _ metrics.IntGauge = &IntGauge{} -) - -// IntGauge is an implementation of metrics.IntGauge. -type IntGauge struct { - *Metrics - *tsmetrics.MetricGaugeInt64 -} - -// Add implementations metrics.Count. -func (metric IntGauge) Add(delta int64) int64 { - return metric.MetricGaugeInt64.Add(delta) -} - -// WithOverriddenTags implementations metrics.Count. -func (metric IntGauge) WithOverriddenTags(tags Fields) metrics.IntGauge { - key := metric.MetricGaugeInt64.GetName() - return IntGauge{ - Metrics: metric.Metrics, - MetricGaugeInt64: metric.Metrics.Registry.GaugeInt64(key, tsmetrics.Tags(tags)), - } -} diff --git a/pkg/xcontext/metrics/tsmetrics/metrics.go b/pkg/xcontext/metrics/tsmetrics/metrics.go deleted file mode 100644 index 3a42758b..00000000 --- a/pkg/xcontext/metrics/tsmetrics/metrics.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package tsmetrics - -import ( - "github.com/linuxboot/contest/pkg/xcontext/fields" - "github.com/linuxboot/contest/pkg/xcontext/metrics" - tsmetrics "github.com/xaionaro-go/metrics" -) - -var _ metrics.Metrics = &Metrics{} - -type Fields = fields.Fields - -// Metrics implements a wrapper of github.com/xaionaro-go/metrics to implement -// metrics.Metrics. -type Metrics struct { - Registry *tsmetrics.Registry - Tags *tsmetrics.FastTags -} - -// New returns a new instance of Metrics -func New() *Metrics { - m := &Metrics{ - Registry: tsmetrics.New(), - Tags: tsmetrics.NewFastTags().(*tsmetrics.FastTags), - } - m.Registry.SetDefaultGCEnabled(true) - m.Registry.SetDefaultIsRan(true) - m.Registry.SetSender(nil) - return m -} - -// Count implements context.Metrics (see the description in the interface). -func (m *Metrics) Count(key string) metrics.Count { - return Count{Metrics: m, MetricCount: m.Registry.Count(key, m.Tags)} -} - -// Gauge implements context.Metrics (see the description in the interface). -func (m *Metrics) Gauge(key string) metrics.Gauge { - return Gauge{Metrics: m, MetricGaugeFloat64: m.Registry.GaugeFloat64(key, m.Tags)} -} - -// IntGauge implements context.Metrics (see the description in the interface). -func (m *Metrics) IntGauge(key string) metrics.IntGauge { - return IntGauge{Metrics: m, MetricGaugeInt64: m.Registry.GaugeInt64(key, m.Tags)} -} - -// WithTag implements context.Metrics (see the description in the interface). -func (m *Metrics) WithTag(key string, value interface{}) metrics.Metrics { - newTags := tsmetrics.NewFastTags().(*tsmetrics.FastTags) - newTags.Slice = make([]*tsmetrics.FastTag, len(m.Tags.Slice)) - copy(newTags.Slice, m.Tags.Slice) - newTags.Set(key, value) - return &Metrics{ - Registry: m.Registry, - Tags: newTags, - } -} - -// WithTags implements context.Metrics (see the description in the interface). -func (m *Metrics) WithTags(tags Fields) metrics.Metrics { - newTags := tsmetrics.NewFastTags().(*tsmetrics.FastTags) - newTags.Slice = make([]*tsmetrics.FastTag, len(m.Tags.Slice)) - copy(newTags.Slice, m.Tags.Slice) - for k, v := range tags { - newTags.Set(k, v) - } - return &Metrics{ - Registry: m.Registry, - Tags: newTags, - } -} diff --git a/pkg/xcontext/metrics/tsmetrics/metrics_test.go b/pkg/xcontext/metrics/tsmetrics/metrics_test.go deleted file mode 100644 index 70045f4a..00000000 --- a/pkg/xcontext/metrics/tsmetrics/metrics_test.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package tsmetrics - -import ( - "testing" - - "github.com/linuxboot/contest/pkg/xcontext/metrics" - metricstester "github.com/linuxboot/contest/pkg/xcontext/metrics/test" -) - -func TestMetrics(t *testing.T) { - metricstester.TestMetrics(t, func() metrics.Metrics { - return New() - }) -} diff --git a/pkg/xcontext/values_handler.go b/pkg/xcontext/values_handler.go deleted file mode 100644 index 8c6c1560..00000000 --- a/pkg/xcontext/values_handler.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "context" -) - -type valuesHandler interface { - Value(key interface{}) interface{} -} - -var _ valuesHandler = &valuesCtx{} - -type valuesCtx struct { - parent valuesHandler - key interface{} - value interface{} -} - -// WithValue is analog of of context.WithValue but for extended context. -func WithValue(parent context.Context, key, value interface{}) Context { - if parent, ok := parent.(Context); ok { - return withValue(parent, key, value) - } - - return withValue(NewContext(parent, "", nil, nil, nil, nil, nil), key, value) -} - -func withValue(parent Context, key, value interface{}) Context { - ctx := parent.Clone() - ctx.addValue(key, value) - return ctx -} - -func (ctx *ctxValue) addValue(key, value interface{}) { - ctx.valuesHandler = &valuesCtx{ - parent: ctx.valuesHandler, - key: key, - value: value, - } -} - -func (h *valuesCtx) Value(key interface{}) interface{} { - if h.key == key { - return h.value - } - if h.parent != nil { - return h.parent.Value(key) - } - return nil -} - -type valuesMerger struct { - outer valuesHandler - inner valuesHandler -} - -func (m valuesMerger) Value(key interface{}) interface{} { - v := m.outer.Value(key) - if v != nil { - return v - } - - return m.inner.Value(key) -} diff --git a/pkg/xcontext/values_handler_test.go b/pkg/xcontext/values_handler_test.go deleted file mode 100644 index 855ae77f..00000000 --- a/pkg/xcontext/values_handler_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package xcontext - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" -) - -type keyType string - -func TestWithValue(t *testing.T) { - stdCtx := context.Background() - stdCtx = context.WithValue(stdCtx, keyType("key0"), "value0") - stdCtx = context.WithValue(stdCtx, keyType("key1"), "value1") - ctx := NewContext(stdCtx, "", nil, nil, nil, nil, nil) - ctx = WithValue(ctx, keyType("key2"), "value2") - ctx = WithValue(ctx, keyType("key3"), "value3") - require.Equal(t, "value0", ctx.Value(keyType("key0"))) - require.Equal(t, "value1", ctx.Value(keyType("key1"))) - require.Equal(t, "value2", ctx.Value(keyType("key2"))) - require.Equal(t, "value3", ctx.Value(keyType("key3"))) - require.Equal(t, nil, ctx.Value("key3")) - require.Equal(t, nil, ctx.Value(keyType("key4"))) -} - -func BenchmarkWithValue(b *testing.B) { - key := keyType("key") - value := "value" - ctx := Background() - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - ctx = WithValue(ctx, key, value) - } -} - -func BenchmarkStdWithValue(b *testing.B) { - key := keyType("key") - value := "value" - ctx := context.Background() - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - ctx = context.WithValue(ctx, key, value) - } -} diff --git a/plugins/listeners/httplistener/httplistener.go b/plugins/listeners/httplistener/httplistener.go index f4f686bf..1ae5f531 100644 --- a/plugins/listeners/httplistener/httplistener.go +++ b/plugins/listeners/httplistener/httplistener.go @@ -7,6 +7,7 @@ package httplistener import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -15,12 +16,14 @@ import ( "strings" "time" + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/experimental/metrics" "github.com/linuxboot/contest/pkg/api" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // HTTPListener implements the api.Listener interface. @@ -82,14 +85,14 @@ func strToJobID(s string) (types.JobID, error) { } type apiHandler struct { - ctx xcontext.Context + ctx context.Context api *api.API } func (h *apiHandler) reply(w http.ResponseWriter, status int, msg string) { w.WriteHeader(status) if _, err := fmt.Fprint(w, msg); err != nil { - h.ctx.Debugf("Cannot write to client socket: %v", err) + logging.Debugf(h.ctx, "Cannot write to client socket: %v", err) } } @@ -111,10 +114,10 @@ func (h *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { jobDesc := r.PostFormValue("jobDesc") requestor := api.EventRequestor(r.PostFormValue("requestor")) - ctx := h.ctx.WithTags(xcontext.Fields{ - "http_verb": verb, - "http_requestor": requestor, - }).WithField("http_job_id", jobIDStr) + ctx := h.ctx + ctx = beltctx.WithField(ctx, "http_verb", verb, metrics.FieldPropInclude) + ctx = beltctx.WithField(ctx, "http_requestor", requestor, metrics.FieldPropInclude) + ctx = beltctx.WithField(ctx, "http_job_id", jobIDStr) switch verb { case "start": @@ -218,7 +221,7 @@ func (h *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.reply(w, httpStatus, string(msg)) } -func listenWithCancellation(ctx xcontext.Context, s *http.Server) error { +func listenWithCancellation(ctx context.Context, s *http.Server) error { var ( errCh = make(chan error, 1) ) @@ -227,20 +230,20 @@ func listenWithCancellation(ctx xcontext.Context, s *http.Server) error { go func() { errCh <- s.ListenAndServe() }() - ctx.Infof("Started HTTP API listener on %s", s.Addr) + logging.Infof(ctx, "Started HTTP API listener on %s", s.Addr) // wait for cancellation or for completion select { case err := <-errCh: return err case <-ctx.Done(): - ctx.Debugf("Received server shut down request") + logging.Debugf(ctx, "Received server shut down request") return s.Close() } } // Serve implements the api.Listener.Serve interface method. It starts an HTTP // API listener and returns an api.Event channel that the caller can iterate on. -func (h *HTTPListener) Serve(ctx xcontext.Context, a *api.API) error { +func (h *HTTPListener) Serve(ctx context.Context, a *api.API) error { if a == nil { return errors.New("API object is nil") } @@ -250,7 +253,7 @@ func (h *HTTPListener) Serve(ctx xcontext.Context, a *api.API) error { ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, } - ctx.Debugf("Serving a listener") + logging.Debugf(ctx, "Serving a listener") if err := listenWithCancellation(ctx, &s); err != nil { return fmt.Errorf("HTTP listener failed: %v", err) } diff --git a/plugins/reporters/noop/noop.go b/plugins/reporters/noop/noop.go index d97a1005..c9bec911 100644 --- a/plugins/reporters/noop/noop.go +++ b/plugins/reporters/noop/noop.go @@ -6,9 +6,10 @@ package noop import ( + "context" + "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name defines the name of the reporter used within the plugin registry @@ -35,12 +36,12 @@ func (n *Noop) Name() string { } // RunReport calculates the report to be associated with a job run. -func (n *Noop) RunReport(ctx xcontext.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { +func (n *Noop) RunReport(ctx context.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { return true, "I did nothing", nil } // FinalReport calculates the final report to be associated to a job. -func (n *Noop) FinalReport(ctx xcontext.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { +func (n *Noop) FinalReport(ctx context.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { return true, "I did nothing at the end, all good", nil } diff --git a/plugins/reporters/targetsuccess/targetsuccess.go b/plugins/reporters/targetsuccess/targetsuccess.go index 899e243a..550acaf0 100644 --- a/plugins/reporters/targetsuccess/targetsuccess.go +++ b/plugins/reporters/targetsuccess/targetsuccess.go @@ -6,13 +6,13 @@ package targetsuccess import ( + "context" "encoding/json" "fmt" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/lib/comparison" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name defines the name of the reporter used within the plugin registry @@ -73,7 +73,7 @@ func (ts *TargetSuccessReporter) Name() string { } // RunReport calculates the report to be associated with a job run. -func (ts *TargetSuccessReporter) RunReport(ctx xcontext.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { +func (ts *TargetSuccessReporter) RunReport(ctx context.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { var ( success, fail uint64 @@ -125,7 +125,7 @@ func (ts *TargetSuccessReporter) RunReport(ctx xcontext.Context, parameters inte } // FinalReport calculates the final report to be associated to a job. -func (ts *TargetSuccessReporter) FinalReport(ctx xcontext.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { +func (ts *TargetSuccessReporter) FinalReport(ctx context.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { return false, nil, fmt.Errorf("final reporting not implemented yet in %s", Name) } diff --git a/plugins/storage/memory/memory.go b/plugins/storage/memory/memory.go index 026fd7a7..b3ff0b6f 100644 --- a/plugins/storage/memory/memory.go +++ b/plugins/storage/memory/memory.go @@ -6,6 +6,7 @@ package memory import ( + "context" "encoding/json" "fmt" "sort" @@ -17,9 +18,9 @@ import ( "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" "golang.org/x/exp/slices" ) @@ -60,7 +61,7 @@ func emptyTestEventQuery(eventQuery *testevent.Query) bool { } // StoreTestEvent stores a test event into the database -func (m *Memory) StoreTestEvent(_ xcontext.Context, event testevent.Event) error { +func (m *Memory) StoreTestEvent(_ context.Context, event testevent.Event) error { m.lock.Lock() defer m.lock.Unlock() event.SequenceID = uint64(len(m.testEvents)) + 1 @@ -121,7 +122,7 @@ func eventTestStepMatch(queryTestStepLabel, testStepLabel string) bool { } // GetTestEvents returns all test events that match the given query. -func (m *Memory) GetTestEvents(_ xcontext.Context, eventQuery *testevent.Query) ([]testevent.Event, error) { +func (m *Memory) GetTestEvents(_ context.Context, eventQuery *testevent.Query) ([]testevent.Event, error) { m.lock.Lock() defer m.lock.Unlock() @@ -156,7 +157,7 @@ func (m *Memory) Reset() error { } // StoreJobRequest stores a new job request -func (m *Memory) StoreJobRequest(_ xcontext.Context, request *job.Request) (types.JobID, error) { +func (m *Memory) StoreJobRequest(_ context.Context, request *job.Request) (types.JobID, error) { m.lock.Lock() defer m.lock.Unlock() @@ -176,7 +177,7 @@ func (m *Memory) StoreJobRequest(_ xcontext.Context, request *job.Request) (type } // GetJobRequest retrieves a job request from the in memory list -func (m *Memory) GetJobRequest(_ xcontext.Context, jobID types.JobID) (*job.Request, error) { +func (m *Memory) GetJobRequest(_ context.Context, jobID types.JobID) (*job.Request, error) { m.lock.Lock() defer m.lock.Unlock() v := m.jobInfo[jobID] @@ -188,7 +189,7 @@ func (m *Memory) GetJobRequest(_ xcontext.Context, jobID types.JobID) (*job.Requ // StoreReport stores a report associated to a job. Returns an error if there is // already a report associated with this run. -func (m *Memory) StoreReport(_ xcontext.Context, report *job.Report) error { +func (m *Memory) StoreReport(_ context.Context, report *job.Report) error { m.lock.Lock() defer m.lock.Unlock() ji := m.jobInfo[report.JobID] @@ -205,7 +206,7 @@ func (m *Memory) StoreReport(_ xcontext.Context, report *job.Report) error { } // GetJobReport returns the report associated to a given job -func (m *Memory) GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.JobReport, error) { +func (m *Memory) GetJobReport(ctx context.Context, jobID types.JobID) (*job.JobReport, error) { m.lock.Lock() defer m.lock.Unlock() jr := &job.JobReport{JobID: jobID} @@ -227,7 +228,7 @@ func (m *Memory) GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.Job } else { i := int(r.RunID) - 1 if i > len(jr.RunReports) { - ctx.Errorf("Incomplete set of run reports for job %d", jobID) + logging.Errorf(ctx, "Incomplete set of run reports for job %d", jobID) break } if i == len(jr.RunReports) { @@ -239,7 +240,7 @@ func (m *Memory) GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.Job return jr, nil } -func (m *Memory) ListJobs(_ xcontext.Context, query *storage.JobQuery) ([]types.JobID, error) { +func (m *Memory) ListJobs(_ context.Context, query *storage.JobQuery) ([]types.JobID, error) { m.lock.Lock() defer m.lock.Unlock() res := []types.JobID{} @@ -295,7 +296,7 @@ jobLoop: } // StoreFrameworkEvent stores a framework event into the database -func (m *Memory) StoreFrameworkEvent(_ xcontext.Context, event frameworkevent.Event) error { +func (m *Memory) StoreFrameworkEvent(_ context.Context, event frameworkevent.Event) error { m.lock.Lock() defer m.lock.Unlock() event.SequenceID = uint64(len(m.frameworkEvents)) + 1 @@ -304,7 +305,7 @@ func (m *Memory) StoreFrameworkEvent(_ xcontext.Context, event frameworkevent.Ev } // GetFrameworkEvent retrieves a framework event from storage -func (m *Memory) GetFrameworkEvent(_ xcontext.Context, eventQuery *frameworkevent.Query) ([]frameworkevent.Event, error) { +func (m *Memory) GetFrameworkEvent(_ context.Context, eventQuery *frameworkevent.Query) ([]frameworkevent.Event, error) { m.lock.Lock() defer m.lock.Unlock() diff --git a/plugins/storage/memory/memory_test.go b/plugins/storage/memory/memory_test.go index 3b6bf406..4fdc09b3 100644 --- a/plugins/storage/memory/memory_test.go +++ b/plugins/storage/memory/memory_test.go @@ -6,18 +6,19 @@ package memory import ( + "context" "sort" "testing" "time" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/pkg/event/testevent" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + "github.com/linuxboot/contest/pkg/logging" "github.com/stretchr/testify/require" ) var ( - ctx, _ = logrusctx.NewContext(logger.LevelDebug) + ctx = logging.WithBelt(context.Background(), logger.LevelDebug) ) func TestMemory_GetTestEvents(t *testing.T) { diff --git a/plugins/storage/rdbms/events.go b/plugins/storage/rdbms/events.go index 2c32610c..2541737c 100644 --- a/plugins/storage/rdbms/events.go +++ b/plugins/storage/rdbms/events.go @@ -6,6 +6,7 @@ package rdbms import ( + "context" "database/sql" "encoding/json" "fmt" @@ -14,9 +15,9 @@ import ( "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" "github.com/google/go-safeweb/safesql" ) @@ -206,7 +207,7 @@ func TestEventEmitTime(ev testevent.Event) interface{} { // StoreTestEvent appends an event to the internal buffer and triggers a flush // when the internal storage utilization goes beyond `testEventsFlushSize` -func (r *RDBMS) StoreTestEvent(_ xcontext.Context, event testevent.Event) error { +func (r *RDBMS) StoreTestEvent(_ context.Context, event testevent.Event) error { defer r.testEventsLock.Unlock() r.testEventsLock.Lock() @@ -255,7 +256,7 @@ func (r *RDBMS) flushTestEvents() error { } // GetTestEvents retrieves test events matching the query fields provided -func (r *RDBMS) GetTestEvents(ctx xcontext.Context, eventQuery *testevent.Query) ([]testevent.Event, error) { +func (r *RDBMS) GetTestEvents(ctx context.Context, eventQuery *testevent.Query) ([]testevent.Event, error) { // Flush pending events before Get operations err := r.flushTestEvents() @@ -274,7 +275,7 @@ func (r *RDBMS) GetTestEvents(ctx xcontext.Context, eventQuery *testevent.Query) } var results []testevent.Event - ctx.Debugf("Executing query: %s, fields: %v", query, fields) + logging.Debugf(ctx, "Executing query: %s, fields: %v", query, fields) rows, err := r.db.Query(query, fields...) if err != nil { return nil, err @@ -289,7 +290,7 @@ func (r *RDBMS) GetTestEvents(ctx xcontext.Context, eventQuery *testevent.Query) defer func() { err := rows.Close() if err != nil { - ctx.Warnf("could not close rows for test events: %v", err) + logging.Warnf(ctx, "could not close rows for test events: %v", err) } }() for rows.Next() { @@ -353,7 +354,7 @@ func FrameworkEventEmitTime(ev frameworkevent.Event) interface{} { // StoreFrameworkEvent appends an event to the internal buffer and triggers a flush // when the internal storage utilization goes beyond `frameworkEventsFlushSize` -func (r *RDBMS) StoreFrameworkEvent(ctx xcontext.Context, event frameworkevent.Event) error { +func (r *RDBMS) StoreFrameworkEvent(ctx context.Context, event frameworkevent.Event) error { defer r.frameworkEventsLock.Unlock() r.frameworkEventsLock.Lock() @@ -410,7 +411,7 @@ func (r *RDBMS) flushFrameworkEvents() error { } // GetFrameworkEvent retrieves framework events matching the query fields provided -func (r *RDBMS) GetFrameworkEvent(ctx xcontext.Context, eventQuery *frameworkevent.Query) ([]frameworkevent.Event, error) { +func (r *RDBMS) GetFrameworkEvent(ctx context.Context, eventQuery *frameworkevent.Query) ([]frameworkevent.Event, error) { // Flush pending events before Get operations err := r.flushFrameworkEvents() @@ -427,7 +428,7 @@ func (r *RDBMS) GetFrameworkEvent(ctx xcontext.Context, eventQuery *frameworkeve return nil, fmt.Errorf("could not execute select query for test events: %v", err) } results := []frameworkevent.Event{} - ctx.Debugf("Executing query: %s, fields: %v", query, fields) + logging.Debugf(ctx, "Executing query: %s, fields: %v", query, fields) rows, err := r.db.Query(query, fields...) if err != nil { return nil, err @@ -435,7 +436,7 @@ func (r *RDBMS) GetFrameworkEvent(ctx xcontext.Context, eventQuery *frameworkeve defer func() { if err := rows.Close(); err != nil { - ctx.Warnf("could not close rows for framework events: %v", err) + logging.Warnf(ctx, "could not close rows for framework events: %v", err) } }() diff --git a/plugins/storage/rdbms/init.go b/plugins/storage/rdbms/init.go index caf4d8fb..6e7cb591 100644 --- a/plugins/storage/rdbms/init.go +++ b/plugins/storage/rdbms/init.go @@ -16,8 +16,8 @@ import ( "github.com/linuxboot/contest/pkg/storage" log "github.com/sirupsen/logrus" - "github.com/linuxboot/contest/tools/migration/rdbms/migrationlib" "github.com/google/go-safeweb/safesql" + "github.com/linuxboot/contest/tools/migration/rdbms/migrationlib" // this blank import registers the mysql driver _ "github.com/go-sql-driver/mysql" ) @@ -34,7 +34,6 @@ type db interface { Query(query safesql.TrustedSQLString, args ...interface{}) (*sql.Rows, error) } - // tx defines an interface for a backend that supports transaction like operations type tx interface { Commit() error diff --git a/plugins/storage/rdbms/list_jobs.go b/plugins/storage/rdbms/list_jobs.go index 7419e303..81f7f22a 100644 --- a/plugins/storage/rdbms/list_jobs.go +++ b/plugins/storage/rdbms/list_jobs.go @@ -6,15 +6,16 @@ package rdbms import ( + "context" "fmt" + "github.com/google/go-safeweb/safesql" "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) -func (r *RDBMS) ListJobs(_ xcontext.Context, query *storage.JobQuery) ([]types.JobID, error) { +func (r *RDBMS) ListJobs(_ context.Context, query *storage.JobQuery) ([]types.JobID, error) { res := []types.JobID{} // Quoting SQL strings is hard. https://github.com/golang/go/issues/18478 @@ -42,7 +43,7 @@ func (r *RDBMS) ListJobs(_ xcontext.Context, query *storage.JobQuery) ([]types.J safesql.New(" ON jobs.job_id = jt"), safesql.NewFromUint64(uint64(i)), safesql.New(".job_id"), - ), + ), ) } var conds []safesql.TrustedSQLString @@ -62,7 +63,7 @@ func (r *RDBMS) ListJobs(_ xcontext.Context, query *storage.JobQuery) ([]types.J safesql.New("jobs.state IN ("), safesql.TrustedSQLStringJoin(stst, safesql.New(", ")), safesql.New(")")), - ) + ) } // Now the corresponding conditions. for i, tag := range query.Tags { diff --git a/plugins/storage/rdbms/report.go b/plugins/storage/rdbms/report.go index c14d9907..abcca773 100644 --- a/plugins/storage/rdbms/report.go +++ b/plugins/storage/rdbms/report.go @@ -6,18 +6,20 @@ package rdbms import ( + "context" "encoding/json" "errors" "fmt" + "github.com/google/go-safeweb/safesql" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // StoreReport persists a run or final report in the internal storage. -func (r *RDBMS) StoreReport(_ xcontext.Context, report *job.Report) error { +func (r *RDBMS) StoreReport(_ context.Context, report *job.Report) error { reportJSON, err := report.ToJSON() if err != nil { @@ -44,7 +46,7 @@ func (r *RDBMS) StoreReport(_ xcontext.Context, report *job.Report) error { } // GetJobReport retrieves a JobReport from the database -func (r *RDBMS) GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.JobReport, error) { +func (r *RDBMS) GetJobReport(ctx context.Context, jobID types.JobID) (*job.JobReport, error) { var ( runReports [][]*job.Report @@ -58,14 +60,14 @@ func (r *RDBMS) GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.JobR // get run reports. Don't change the order by asc, because // the code below assumes sorted results by ascending run number. selectStatement := safesql.New("select success, report_time, reporter_name, run_id, data from run_reports where job_id = ? order by run_id asc, reporter_name asc") - ctx.Debugf("Executing query: %s", selectStatement) + logging.Debugf(ctx, "Executing query: %s", selectStatement) rows, err := r.db.Query(selectStatement, jobID) if err != nil { return nil, fmt.Errorf("could not get run report for job %v: %v", jobID, err) } defer func() { if err := rows.Close(); err != nil { - ctx.Warnf("failed to close rows from query statement: %v", err) + logging.Warnf(ctx, "failed to close rows from query statement: %v", err) } }() var lastRunID, currentRunID uint @@ -122,14 +124,14 @@ func (r *RDBMS) GetJobReport(ctx xcontext.Context, jobID types.JobID) (*job.JobR // get final reports selectStatement = safesql.New("select success, report_time, reporter_name, data from final_reports where job_id = ? order by reporter_name asc") - ctx.Debugf("Executing query: %s", selectStatement) + logging.Debugf(ctx, "Executing query: %s", selectStatement) rows2, err := r.db.Query(selectStatement, jobID) if err != nil { return nil, fmt.Errorf("could not get final report for job %v: %v", jobID, err) } defer func() { if err := rows2.Close(); err != nil { - ctx.Warnf("failed to close rows2 from query statement: %v", err) + logging.Warnf(ctx, "failed to close rows2 from query statement: %v", err) } }() for rows2.Next() { diff --git a/plugins/storage/rdbms/request.go b/plugins/storage/rdbms/request.go index def96e14..03116d29 100644 --- a/plugins/storage/rdbms/request.go +++ b/plugins/storage/rdbms/request.go @@ -6,13 +6,15 @@ package rdbms import ( + "context" "encoding/json" "fmt" + "github.com/google/go-safeweb/safesql" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) const ( @@ -21,7 +23,7 @@ const ( ) // StoreJobRequest stores a new job request in the database -func (r *RDBMS) StoreJobRequest(_ xcontext.Context, request *job.Request) (types.JobID, error) { +func (r *RDBMS) StoreJobRequest(_ context.Context, request *job.Request) (types.JobID, error) { var jobID types.JobID @@ -64,20 +66,20 @@ func (r *RDBMS) StoreJobRequest(_ xcontext.Context, request *job.Request) (types } // GetJobRequest retrieves a JobRequest from the database -func (r *RDBMS) GetJobRequest(ctx xcontext.Context, jobID types.JobID) (*job.Request, error) { +func (r *RDBMS) GetJobRequest(ctx context.Context, jobID types.JobID) (*job.Request, error) { r.lockTx() defer r.unlockTx() selectStatement := safesql.New("select job_id, name, requestor, server_id, request_time, descriptor, extended_descriptor from jobs where job_id = ?") - ctx.Debugf("Executing query: %s", selectStatement) + logging.Debugf(ctx, "Executing query: %s", selectStatement) rows, err := r.db.Query(selectStatement, jobID) if err != nil { return nil, fmt.Errorf("could not get job request with id %v: %v", jobID, err) } defer func() { if err := rows.Close(); err != nil { - ctx.Warnf("could not close rows for job request: %v", err) + logging.Warnf(ctx, "could not close rows for job request: %v", err) } }() diff --git a/plugins/targetlocker/dblocker/dblocker.go b/plugins/targetlocker/dblocker/dblocker.go index 426ad67a..8c2138e9 100644 --- a/plugins/targetlocker/dblocker/dblocker.go +++ b/plugins/targetlocker/dblocker/dblocker.go @@ -6,6 +6,7 @@ package dblocker import ( + "context" "database/sql" "fmt" "strings" @@ -15,9 +16,9 @@ import ( // this blank import registers the mysql driver _ "github.com/go-sql-driver/mysql" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the plugin name. @@ -114,7 +115,7 @@ func (d *DBLocker) queryLocks(tx db, targets []string) (map[string]dblock, error } // handleLock does the real locking, it assumes the jobID is valid -func (d *DBLocker) handleLock(ctx xcontext.Context, jobID int64, targets []string, limit uint, timeout time.Duration, requireLocked bool, allowConflicts bool) ([]string, error) { +func (d *DBLocker) handleLock(ctx context.Context, jobID int64, targets []string, limit uint, timeout time.Duration, requireLocked bool, allowConflicts bool) ([]string, error) { if len(targets) == 0 { return nil, nil } @@ -255,7 +256,7 @@ func (d *DBLocker) handleLock(ctx xcontext.Context, jobID int64, targets []strin } // handleUnlock does the real unlocking, it assumes the jobID is valid -func (d *DBLocker) handleUnlock(ctx xcontext.Context, jobID int64, targets []string) error { +func (d *DBLocker) handleUnlock(ctx context.Context, jobID int64, targets []string) error { if len(targets) == 0 { return nil } @@ -308,7 +309,7 @@ func validateTargets(targets []*target.Target) error { // Lock locks the given targets. // See target.Locker for API details -func (d *DBLocker) Lock(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*target.Target) error { +func (d *DBLocker) Lock(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*target.Target) error { if jobID == 0 { return fmt.Errorf("invalid lock request, jobID cannot be zero (targets: %v)", targets) } @@ -316,13 +317,13 @@ func (d *DBLocker) Lock(ctx xcontext.Context, jobID types.JobID, duration time.D return fmt.Errorf("invalid lock request: %w", err) } _, err := d.handleLock(ctx, int64(jobID), targetIDList(targets), uint(len(targets)), duration, false /* requireLocked */, false /* allowConflicts */) - ctx.Debugf("Lock %d targets for %s: %v", len(targets), duration, err) + logging.Debugf(ctx, "Lock %d targets for %s: %v", len(targets), duration, err) return err } // TryLock attempts to locks the given targets. // See target.Locker for API details -func (d *DBLocker) TryLock(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*target.Target, limit uint) ([]string, error) { +func (d *DBLocker) TryLock(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*target.Target, limit uint) ([]string, error) { if jobID == 0 { return nil, fmt.Errorf("invalid tryLock request, jobID cannot be zero (targets: %v)", targets) } @@ -333,13 +334,13 @@ func (d *DBLocker) TryLock(ctx xcontext.Context, jobID types.JobID, duration tim return nil, nil } res, err := d.handleLock(ctx, int64(jobID), targetIDList(targets), limit, duration, false /* requireLocked */, true /* allowConflicts */) - ctx.Debugf("TryLock %d targets for %s: %d %v", len(targets), duration, len(res), err) + logging.Debugf(ctx, "TryLock %d targets for %s: %d %v", len(targets), duration, len(res), err) return res, err } // Unlock unlocks the given targets. // See target.Locker for API details -func (d *DBLocker) Unlock(ctx xcontext.Context, jobID types.JobID, targets []*target.Target) error { +func (d *DBLocker) Unlock(ctx context.Context, jobID types.JobID, targets []*target.Target) error { if jobID == 0 { return fmt.Errorf("invalid unlock request, jobID cannot be zero (targets: %v)", targets) } @@ -347,13 +348,13 @@ func (d *DBLocker) Unlock(ctx xcontext.Context, jobID types.JobID, targets []*ta return fmt.Errorf("invalid unlock request: %w", err) } err := d.handleUnlock(ctx, int64(jobID), targetIDList(targets)) - ctx.Debugf("Unlock %d targets: %v", len(targets), err) + logging.Debugf(ctx, "Unlock %d targets: %v", len(targets), err) return err } // RefreshLocks refreshes the locks on the given targets. // See target.Locker for API details -func (d *DBLocker) RefreshLocks(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*target.Target) error { +func (d *DBLocker) RefreshLocks(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*target.Target) error { if jobID == 0 { return fmt.Errorf("invalid refresh request, jobID cannot be zero (targets: %v)", targets) } @@ -361,7 +362,7 @@ func (d *DBLocker) RefreshLocks(ctx xcontext.Context, jobID types.JobID, duratio return fmt.Errorf("invalid refresh request: %w", err) } _, err := d.handleLock(ctx, int64(jobID), targetIDList(targets), uint(len(targets)), duration, true /* requireLocked */, false /* allowConflicts */) - ctx.Debugf("RefreshLocks on %d targets for %s: %v", len(targets), duration, err) + logging.Debugf(ctx, "RefreshLocks on %d targets for %s: %v", len(targets), duration, err) return err } @@ -373,8 +374,8 @@ func (d *DBLocker) Close() error { // ResetAllLocks resets the database and clears all locks, regardless of who owns them. // This is primarily for testing, and should not be used by used in prod, this // is why it is not exposed by target.Locker -func (d *DBLocker) ResetAllLocks(ctx xcontext.Context) error { - ctx.Warnf("DELETING ALL LOCKS") +func (d *DBLocker) ResetAllLocks(ctx context.Context) error { + logging.Warnf(ctx, "DELETING ALL LOCKS") _, err := d.db.Exec("TRUNCATE TABLE locks") return err } diff --git a/plugins/targetlocker/inmemory/inmemory.go b/plugins/targetlocker/inmemory/inmemory.go index a323f912..a451c67d 100644 --- a/plugins/targetlocker/inmemory/inmemory.go +++ b/plugins/targetlocker/inmemory/inmemory.go @@ -9,21 +9,22 @@ package inmemory import ( + "context" "fmt" "time" "github.com/benbjohnson/clock" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. var Name = "InMemory" type request struct { - ctx xcontext.Context + ctx context.Context targets []*target.Target // requireLocked specifies whether targets must be already locked, used by refresh. requireLocked bool @@ -151,7 +152,7 @@ func broker(clk clock.Clock, lockRequests, unlockRequests <-chan *request, done req.err <- fmt.Errorf("unlock request: %w", err) continue } - req.ctx.Debugf("Requested to transactionally unlock %d targets: %v", len(req.targets), req.targets) + logging.Debugf(req.ctx, "Requested to transactionally unlock %d targets: %v", len(req.targets), req.targets) // validate var unlockErr error for _, t := range req.targets { @@ -182,7 +183,7 @@ type InMemory struct { done chan struct{} } -func newReq(ctx xcontext.Context, jobID types.JobID, targets []*target.Target) request { +func newReq(ctx context.Context, jobID types.JobID, targets []*target.Target) request { return request{ ctx: ctx, targets: targets, @@ -192,7 +193,7 @@ func newReq(ctx xcontext.Context, jobID types.JobID, targets []*target.Target) r } // Lock locks the specified targets. -func (tl *InMemory) Lock(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*target.Target) error { +func (tl *InMemory) Lock(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*target.Target) error { req := newReq(ctx, jobID, targets) req.timeout = duration req.requireLocked = false @@ -200,12 +201,12 @@ func (tl *InMemory) Lock(ctx xcontext.Context, jobID types.JobID, duration time. req.limit = uint(len(targets)) tl.lockRequests <- &req err := <-req.err - ctx.Debugf("Lock %d targets for %s: %v", len(targets), duration, err) + logging.Debugf(ctx, "Lock %d targets for %s: %v", len(targets), duration, err) return err } // Lock locks the specified targets. -func (tl *InMemory) TryLock(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*target.Target, limit uint) ([]string, error) { +func (tl *InMemory) TryLock(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*target.Target, limit uint) ([]string, error) { req := newReq(ctx, jobID, targets) req.timeout = duration req.requireLocked = false @@ -214,22 +215,22 @@ func (tl *InMemory) TryLock(ctx xcontext.Context, jobID types.JobID, duration ti tl.lockRequests <- &req // wait for result err := <-req.err - ctx.Debugf("TryLock %d targets for %s: %d %v", len(targets), duration, len(req.locked), err) + logging.Debugf(ctx, "TryLock %d targets for %s: %d %v", len(targets), duration, len(req.locked), err) return req.locked, err } // Unlock unlocks the specified targets. -func (tl *InMemory) Unlock(ctx xcontext.Context, jobID types.JobID, targets []*target.Target) error { +func (tl *InMemory) Unlock(ctx context.Context, jobID types.JobID, targets []*target.Target) error { req := newReq(ctx, jobID, targets) tl.unlockRequests <- &req err := <-req.err - ctx.Debugf("Unlock %d targets: %v", len(targets), err) + logging.Debugf(ctx, "Unlock %d targets: %v", len(targets), err) return err } // RefreshLocks extends the lock duration by the internally configured timeout. If // the owner is different, the request is rejected. -func (tl *InMemory) RefreshLocks(ctx xcontext.Context, jobID types.JobID, duration time.Duration, targets []*target.Target) error { +func (tl *InMemory) RefreshLocks(ctx context.Context, jobID types.JobID, duration time.Duration, targets []*target.Target) error { req := newReq(ctx, jobID, targets) req.timeout = duration req.requireLocked = true @@ -239,7 +240,7 @@ func (tl *InMemory) RefreshLocks(ctx xcontext.Context, jobID types.JobID, durati // duration. tl.lockRequests <- &req err := <-req.err - ctx.Debugf("RefreshLocks on %d targets for %s: %v", len(targets), duration, err) + logging.Debugf(ctx, "RefreshLocks on %d targets for %s: %v", len(targets), duration, err) return err } diff --git a/plugins/targetlocker/noop/noop.go b/plugins/targetlocker/noop/noop.go index f91a238f..0792b369 100644 --- a/plugins/targetlocker/noop/noop.go +++ b/plugins/targetlocker/noop/noop.go @@ -7,11 +7,12 @@ package noop import ( + "context" "time" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -22,14 +23,14 @@ type Noop struct { } // Lock locks the specified targets by doing nothing. -func (tl Noop) Lock(ctx xcontext.Context, _ types.JobID, _ time.Duration, targets []*target.Target) error { - ctx.Infof("Locked %d targets by doing nothing", len(targets)) +func (tl Noop) Lock(ctx context.Context, _ types.JobID, _ time.Duration, targets []*target.Target) error { + logging.Infof(ctx, "Locked %d targets by doing nothing", len(targets)) return nil } // TryLock locks the specified targets by doing nothing. -func (tl Noop) TryLock(ctx xcontext.Context, _ types.JobID, _ time.Duration, targets []*target.Target, limit uint) ([]string, error) { - ctx.Infof("Trylocked %d targets by doing nothing", len(targets)) +func (tl Noop) TryLock(ctx context.Context, _ types.JobID, _ time.Duration, targets []*target.Target, limit uint) ([]string, error) { + logging.Infof(ctx, "Trylocked %d targets by doing nothing", len(targets)) res := make([]string, 0, len(targets)) for _, t := range targets { res = append(res, t.ID) @@ -38,15 +39,15 @@ func (tl Noop) TryLock(ctx xcontext.Context, _ types.JobID, _ time.Duration, tar } // Unlock unlocks the specified targets by doing nothing. -func (tl Noop) Unlock(ctx xcontext.Context, _ types.JobID, targets []*target.Target) error { - ctx.Infof("Unlocked %d targets by doing nothing", len(targets)) +func (tl Noop) Unlock(ctx context.Context, _ types.JobID, targets []*target.Target) error { + logging.Infof(ctx, "Unlocked %d targets by doing nothing", len(targets)) return nil } // RefreshLocks refreshes all the locks by the internal (non-existing) timeout, // by flawlessly doing nothing. -func (tl Noop) RefreshLocks(ctx xcontext.Context, jobID types.JobID, _ time.Duration, targets []*target.Target) error { - ctx.Infof("All %d target locks are refreshed, since I had to do nothing", len(targets)) +func (tl Noop) RefreshLocks(ctx context.Context, jobID types.JobID, _ time.Duration, targets []*target.Target) error { + logging.Infof(ctx, "All %d target locks are refreshed, since I had to do nothing", len(targets)) return nil } diff --git a/plugins/targetlocker/noop/noop_test.go b/plugins/targetlocker/noop/noop_test.go index 538e50f1..7e5ab64f 100644 --- a/plugins/targetlocker/noop/noop_test.go +++ b/plugins/targetlocker/noop/noop_test.go @@ -6,18 +6,19 @@ package noop import ( + "context" "testing" "time" + "github.com/facebookincubator/go-belt/tool/logger" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" "github.com/stretchr/testify/require" ) var ( - ctx, _ = logrusctx.NewContext(logger.LevelDebug) + ctx = logging.WithBelt(context.Background(), logger.LevelDebug) ) func TestNoopNew(t *testing.T) { diff --git a/plugins/targetmanagers/csvtargetmanager/csvfile.go b/plugins/targetmanagers/csvtargetmanager/csvfile.go index e4e92dab..ff1eef25 100644 --- a/plugins/targetmanagers/csvtargetmanager/csvfile.go +++ b/plugins/targetmanagers/csvtargetmanager/csvfile.go @@ -17,6 +17,7 @@ package csvtargetmanager import ( + "context" "encoding/csv" "encoding/json" "errors" @@ -28,9 +29,9 @@ import ( "strings" "time" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" "github.com/insomniacslk/xjson" ) @@ -98,7 +99,7 @@ func (tf CSVFileTargetManager) ValidateReleaseParameters(params []byte) (interfa // Acquire implements contest.TargetManager.Acquire, reading one entry per line // from a text file. Each input record looks like this: ID,FQDN,IPv4,IPv6. Only ID is required -func (tf *CSVFileTargetManager) Acquire(ctx xcontext.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) { +func (tf *CSVFileTargetManager) Acquire(ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) { acquireParameters, ok := parameters.(AcquireParameters) if !ok { return nil, fmt.Errorf("Acquire expects %T object, got %T", acquireParameters, parameters) @@ -169,9 +170,9 @@ func (tf *CSVFileTargetManager) Acquire(ctx xcontext.Context, jobID types.JobID, len(hosts), ) } - ctx.Debugf("Found %d targets in %s", len(hosts), acquireParameters.FileURI.Path) + logging.Debugf(ctx, "Found %d targets in %s", len(hosts), acquireParameters.FileURI.Path) if acquireParameters.Shuffle { - ctx.Infof("Shuffling targets") + logging.Infof(ctx, "Shuffling targets") rand.Shuffle(len(hosts), func(i, j int) { hosts[i], hosts[j] = hosts[j], hosts[i] }) @@ -206,7 +207,7 @@ func (tf *CSVFileTargetManager) Acquire(ctx xcontext.Context, jobID types.JobID, } // Release releases the acquired resources. -func (tf *CSVFileTargetManager) Release(ctx xcontext.Context, jobID types.JobID, targets []*target.Target, params interface{}) error { +func (tf *CSVFileTargetManager) Release(ctx context.Context, jobID types.JobID, targets []*target.Target, params interface{}) error { return nil } diff --git a/plugins/targetmanagers/targetlist/targetlist.go b/plugins/targetmanagers/targetlist/targetlist.go index d6e4ad20..641b4199 100644 --- a/plugins/targetmanagers/targetlist/targetlist.go +++ b/plugins/targetmanagers/targetlist/targetlist.go @@ -6,16 +6,18 @@ // Package targetlist implements a simple target manager that contains a static // list of targets. Use it as follows in a job descriptor: // "TargetManager": "targetlist", -// "TargetManagerAcquireParameters": { -// "Targets": [ -// { -// "Name": "hostname1.example.com", -// "ID": "id1" -// }, -// { -// "Name": "hostname2.example.com", -// "ID": "id2" -// } +// +// "TargetManagerAcquireParameters": { +// "Targets": [ +// { +// "Name": "hostname1.example.com", +// "ID": "id1" +// }, +// { +// "Name": "hostname2.example.com", +// "ID": "id2" +// } +// // ] // } // @@ -28,15 +30,16 @@ package targetlist import ( + "context" "encoding/json" "errors" "fmt" "strings" "time" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name defined the name of the plugin @@ -81,24 +84,24 @@ func (t TargetList) ValidateReleaseParameters(params []byte) (interface{}, error } // Acquire implements contest.TargetManager.Acquire -func (t *TargetList) Acquire(ctx xcontext.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) { +func (t *TargetList) Acquire(ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) { acquireParameters, ok := parameters.(AcquireParameters) if !ok { return nil, fmt.Errorf("Acquire expects %T object, got %T", acquireParameters, parameters) } if err := tl.Lock(ctx, jobID, jobTargetManagerAcquireTimeout, acquireParameters.Targets); err != nil { - ctx.Warnf("Failed to lock %d targets: %v", len(acquireParameters.Targets), err) + logging.Warnf(ctx, "Failed to lock %d targets: %v", len(acquireParameters.Targets), err) return nil, err } - ctx.Infof("Acquired %d targets", len(acquireParameters.Targets)) + logging.Infof(ctx, "Acquired %d targets", len(acquireParameters.Targets)) return acquireParameters.Targets, nil } // Release releases the acquired resources. -func (t *TargetList) Release(ctx xcontext.Context, jobID types.JobID, targets []*target.Target, params interface{}) error { - ctx.Infof("Released %d targets", len(targets)) +func (t *TargetList) Release(ctx context.Context, jobID types.JobID, targets []*target.Target, params interface{}) error { + logging.Infof(ctx, "Released %d targets", len(targets)) return nil } diff --git a/plugins/testfetchers/literal/literal.go b/plugins/testfetchers/literal/literal.go index 9d5a72b4..edc022ee 100644 --- a/plugins/testfetchers/literal/literal.go +++ b/plugins/testfetchers/literal/literal.go @@ -8,11 +8,11 @@ package literal import ( + "context" "encoding/json" "fmt" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name defined the name of the plugin @@ -33,7 +33,7 @@ type Literal struct { // ValidateFetchParameters performs sanity checks on the fields of the // parameters that will be passed to Fetch. -func (tf Literal) ValidateFetchParameters(_ xcontext.Context, params []byte, requireName bool) (interface{}, error) { +func (tf Literal) ValidateFetchParameters(_ context.Context, params []byte, requireName bool) (interface{}, error) { var fp FetchParameters if err := json.Unmarshal(params, &fp); err != nil { return nil, err @@ -49,7 +49,7 @@ func (tf Literal) ValidateFetchParameters(_ xcontext.Context, params []byte, req // * Name of the test // * list of step definitions // * an error if any -func (tf *Literal) Fetch(_ xcontext.Context, params interface{}) (string, []*test.TestStepDescriptor, error) { +func (tf *Literal) Fetch(_ context.Context, params interface{}) (string, []*test.TestStepDescriptor, error) { fetchParams, ok := params.(FetchParameters) if !ok { return "", nil, fmt.Errorf("Fetch expects uri.FetchParameters object") diff --git a/plugins/testfetchers/uri/uri.go b/plugins/testfetchers/uri/uri.go index ff0f8682..25ed75e8 100644 --- a/plugins/testfetchers/uri/uri.go +++ b/plugins/testfetchers/uri/uri.go @@ -6,6 +6,7 @@ package uri import ( + "context" "encoding/json" "fmt" "io" @@ -13,8 +14,8 @@ import ( "os" "strings" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" "github.com/insomniacslk/xjson" ) @@ -45,7 +46,7 @@ type URI struct { // ValidateFetchParameters performs sanity checks on the fields of the // parameters that will be passed to Fetch. -func (tf URI) ValidateFetchParameters(_ xcontext.Context, params []byte, requireName bool) (interface{}, error) { +func (tf URI) ValidateFetchParameters(_ context.Context, params []byte, requireName bool) (interface{}, error) { var fp FetchParameters if err := json.Unmarshal(params, &fp); err != nil { return nil, err @@ -84,12 +85,12 @@ func (tf URI) ValidateFetchParameters(_ xcontext.Context, params []byte, require // * Name of the test // * list of step definitions // * an error if any -func (tf *URI) Fetch(ctx xcontext.Context, params interface{}) (string, []*test.TestStepDescriptor, error) { +func (tf *URI) Fetch(ctx context.Context, params interface{}) (string, []*test.TestStepDescriptor, error) { fetchParams, ok := params.(FetchParameters) if !ok { return "", nil, fmt.Errorf("Fetch expects uri.FetchParameters object") } - ctx.Debugf("Fetching tests with params %+v", fetchParams) + logging.Debugf(ctx, "Fetching tests with params %+v", fetchParams) scheme := strings.ToLower(strings.ToLower(fetchParams.URI.Scheme)) var ( buf []byte diff --git a/plugins/teststeps/cmd/cmd.go b/plugins/teststeps/cmd/cmd.go index 43dc4041..72255758 100644 --- a/plugins/teststeps/cmd/cmd.go +++ b/plugins/teststeps/cmd/cmd.go @@ -7,6 +7,7 @@ package cmd import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -15,11 +16,12 @@ import ( "strconv" "syscall" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -75,7 +77,7 @@ func (ts Cmd) Name() string { return Name } -func emitEvent(ctx xcontext.Context, name event.Name, payload interface{}, tgt *target.Target, ev testevent.Emitter) error { +func emitEvent(ctx context.Context, name event.Name, payload interface{}, tgt *target.Target, ev testevent.Emitter) error { payloadStr, err := json.Marshal(payload) if err != nil { return fmt.Errorf("cannot encode payload for event '%s': %v", name, err) @@ -94,19 +96,19 @@ func emitEvent(ctx xcontext.Context, name event.Name, payload interface{}, tgt * // Run executes the cmd step. func (ts *Cmd) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - log := ctx.Logger() + log := logger.FromCtx(ctx) if err := ts.validateAndPopulate(params); err != nil { return nil, err } - f := func(ctx xcontext.Context, target *target.Target) error { + f := func(ctx context.Context, target *target.Target) error { // expand args var args []string for _, arg := range ts.args { @@ -205,7 +207,7 @@ func (ts *Cmd) validateAndPopulate(params test.TestStepParameters) error { } // ValidateParameters validates the parameters associated to the TestStep -func (ts *Cmd) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *Cmd) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return ts.validateAndPopulate(params) } diff --git a/plugins/teststeps/cpucmd/cpucmd.go b/plugins/teststeps/cpucmd/cpucmd.go index 096ef95b..9ad72e47 100644 --- a/plugins/teststeps/cpucmd/cpucmd.go +++ b/plugins/teststeps/cpucmd/cpucmd.go @@ -20,6 +20,7 @@ package cpucmd import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -29,14 +30,16 @@ import ( "strconv" "time" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/u-root/cpu/cpu" "golang.org/x/crypto/ssh" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -71,14 +74,14 @@ func (ts CPUCmd) Name() string { // Run executes the cmd step. func (ts *CPUCmd) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - log := ctx.Logger() + log := logger.FromCtx(ctx) // XXX: Dragons ahead! The target (%t) substitution, and function // expression evaluations are done at run-time, so they may still fail // despite passing at early validation time. @@ -91,7 +94,7 @@ func (ts *CPUCmd) Run( return nil, err } - f := func(ctx xcontext.Context, target *target.Target) error { + f := func(ctx context.Context, target *target.Target) error { // apply filters and substitutions to user, host, private key, and command args // cpu does not do user setting yet. // user, err := ts.User.Expand(target) @@ -180,7 +183,7 @@ func (ts *CPUCmd) Run( if err := c.Close(); err != nil { for _, e := range err { if e != io.EOF { - ctx.Warnf("Failed to close CPU session to %s: %v", host, err) + logging.Warnf(ctx, "Failed to close CPU session to %s: %v", host, err) } } } @@ -223,7 +226,7 @@ func (ts *CPUCmd) Run( if err == nil { // Execute expectations if expect == "" { - ctx.Warnf("no expectations specified") + logging.Warnf(ctx, "no expectations specified") } else { matches := re.FindAll(stdout.Bytes(), -1) if len(matches) > 0 { @@ -233,7 +236,7 @@ func (ts *CPUCmd) Run( } } } else { - ctx.Warnf("Stderr of command '%v' is '%s'", c, stderr.Bytes()) + logging.Warnf(ctx, "Stderr of command '%v' is '%s'", c, stderr.Bytes()) } return err case <-ctx.Done(): @@ -307,8 +310,8 @@ func (ts *CPUCmd) validateAndPopulate(params test.TestStepParameters) error { } // ValidateParameters validates the parameters associated to the TestStep -func (ts *CPUCmd) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error { - ctx.Debugf("Params %+v", params) +func (ts *CPUCmd) ValidateParameters(ctx context.Context, params test.TestStepParameters) error { + logging.Debugf(ctx, "Params %+v", params) return ts.validateAndPopulate(params) } diff --git a/plugins/teststeps/echo/echo.go b/plugins/teststeps/echo/echo.go index cd5975c4..65edc197 100644 --- a/plugins/teststeps/echo/echo.go +++ b/plugins/teststeps/echo/echo.go @@ -6,14 +6,15 @@ package echo import ( + "context" "encoding/json" "errors" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -38,7 +39,7 @@ func Load() (string, test.TestStepFactory, []event.Name) { // ValidateParameters validates the parameters that will be passed to the Run // and Resume methods of the test step. -func (e Step) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (e Step) ValidateParameters(_ context.Context, params test.TestStepParameters) error { if t := params.GetOne("text"); t.IsEmpty() { return errors.New("Missing 'text' field in echo parameters") } @@ -52,7 +53,7 @@ func (e Step) Name() string { // Run executes the step func (e Step) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -72,7 +73,7 @@ func (e Step) Run( // guaranteed to work here jobID, _ := types.JobIDFromContext(ctx) runID, _ := types.RunIDFromContext(ctx) - ctx.Infof("This is job %d, run %d on target %s with text '%s'", jobID, runID, target.ID, output) + logging.Infof(ctx, "This is job %d, run %d on target %s with text '%s'", jobID, runID, target.ID, output) ch.Out <- test.TestStepResult{Target: target} case <-ctx.Done(): return nil, nil diff --git a/plugins/teststeps/example/example.go b/plugins/teststeps/example/example.go index 8d262473..b4f5b880 100644 --- a/plugins/teststeps/example/example.go +++ b/plugins/teststeps/example/example.go @@ -6,15 +6,17 @@ package example import ( + "context" "encoding/json" "fmt" "math/rand" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -62,15 +64,15 @@ func (ts *Step) shouldFail(t *target.Target) bool { // Run executes the example step. func (ts *Step) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - f := func(ctx xcontext.Context, target *target.Target) error { - ctx.Infof("Executing on target %s", target) + f := func(ctx context.Context, target *target.Target) error { + logging.Infof(ctx, "Executing on target %s", target) // NOTE: you may want more robust error handling here, possibly just // logging the error, or a retry mechanism. Returning an error // here means failing the entire job. @@ -93,7 +95,7 @@ func (ts *Step) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *Step) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *Step) ValidateParameters(_ context.Context, params test.TestStepParameters) error { if params.GetOne(FailPctParam).String() != "" { if pct, err := params.GetInt(FailPctParam); err == nil { ts.failPct = pct diff --git a/plugins/teststeps/exec/events.go b/plugins/teststeps/exec/events.go index 688fc886..75cff47a 100644 --- a/plugins/teststeps/exec/events.go +++ b/plugins/teststeps/exec/events.go @@ -6,13 +6,13 @@ package exec import ( + "context" "encoding/json" "fmt" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" - "github.com/linuxboot/contest/pkg/xcontext" ) // events that we may emit during the plugin's lifecycle @@ -80,7 +80,7 @@ type stepLogEventPayload struct { Message string `json:"text,omitempty"` } -func emitEvent(ctx xcontext.Context, name event.Name, payload interface{}, tgt *target.Target, ev testevent.Emitter) error { +func emitEvent(ctx context.Context, name event.Name, payload interface{}, tgt *target.Target, ev testevent.Emitter) error { payloadData, err := json.Marshal(payload) if err != nil { return fmt.Errorf("cannot marshal payload for event '%s': %w", name, err) diff --git a/plugins/teststeps/exec/exec.go b/plugins/teststeps/exec/exec.go index 73f7f16d..56210c41 100644 --- a/plugins/teststeps/exec/exec.go +++ b/plugins/teststeps/exec/exec.go @@ -6,6 +6,7 @@ package exec import ( + "context" "encoding/json" "fmt" @@ -13,7 +14,7 @@ import ( "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -53,7 +54,7 @@ func (ts TestStep) Name() string { // Run executes the step. func (ts *TestStep) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -79,7 +80,7 @@ func (ts *TestStep) populateParams(stepParams test.TestStepParameters) error { } // ValidateParameters validates the parameters associated to the step -func (ts *TestStep) ValidateParameters(_ xcontext.Context, stepParams test.TestStepParameters) error { +func (ts *TestStep) ValidateParameters(_ context.Context, stepParams test.TestStepParameters) error { return ts.populateParams(stepParams) } diff --git a/plugins/teststeps/exec/ocp_parser.go b/plugins/teststeps/exec/ocp_parser.go index 455fee59..82252e56 100644 --- a/plugins/teststeps/exec/ocp_parser.go +++ b/plugins/teststeps/exec/ocp_parser.go @@ -6,11 +6,11 @@ package exec import ( + "context" "fmt" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" - "github.com/linuxboot/contest/pkg/xcontext" ) type Severity string @@ -120,7 +120,7 @@ func NewOCPEventParser(target *target.Target, ev testevent.Emitter) *OCPEventPar } } -func (p *OCPEventParser) parseRun(ctx xcontext.Context, node *RunArtifact, root *OCPRoot) error { +func (p *OCPEventParser) parseRun(ctx context.Context, node *RunArtifact, root *OCPRoot) error { if node.RunStart != nil { payload := testStartEventPayload{ SequenceNumber: root.SequenceNumber, @@ -159,7 +159,7 @@ func (p *OCPEventParser) parseRun(ctx xcontext.Context, node *RunArtifact, root return nil } -func (p *OCPEventParser) parseStep(ctx xcontext.Context, node *StepArtifact, root *OCPRoot) error { +func (p *OCPEventParser) parseStep(ctx context.Context, node *StepArtifact, root *OCPRoot) error { if node.StepStart != nil { payload := stepStartEventPayload{ SequenceNumber: root.SequenceNumber, @@ -195,7 +195,7 @@ func (p *OCPEventParser) parseStep(ctx xcontext.Context, node *StepArtifact, roo return nil } -func (ep *OCPEventParser) Parse(ctx xcontext.Context, root *OCPRoot) error { +func (ep *OCPEventParser) Parse(ctx context.Context, root *OCPRoot) error { if root == nil { return fmt.Errorf("invalid nil root object") } diff --git a/plugins/teststeps/exec/ocp_parser_test.go b/plugins/teststeps/exec/ocp_parser_test.go index f5bdd311..e1fc55b3 100644 --- a/plugins/teststeps/exec/ocp_parser_test.go +++ b/plugins/teststeps/exec/ocp_parser_test.go @@ -6,12 +6,13 @@ package exec import ( + "context" "encoding/json" "strings" "testing" "github.com/linuxboot/contest/pkg/event/testevent" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) @@ -22,7 +23,7 @@ type mockEmitter struct { Calls []testevent.Data } -func (e *mockEmitter) Emit(ctx xcontext.Context, data testevent.Data) error { +func (e *mockEmitter) Emit(ctx context.Context, data testevent.Data) error { e.Calls = append(e.Calls, data) args := e.Called(ctx, data) @@ -30,7 +31,7 @@ func (e *mockEmitter) Emit(ctx xcontext.Context, data testevent.Data) error { } func TestOCPEventParser(t *testing.T) { - ctx := xcontext.Background() + ctx := context.Background() ev := &mockEmitter{} ev.On("Emit", ctx, mock.Anything).Return(nil) diff --git a/plugins/teststeps/exec/runner.go b/plugins/teststeps/exec/runner.go index 173261cf..4d51ab55 100644 --- a/plugins/teststeps/exec/runner.go +++ b/plugins/teststeps/exec/runner.go @@ -6,15 +6,17 @@ package exec import ( + "context" "encoding/json" "errors" "fmt" "time" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + exec_transport "github.com/linuxboot/contest/plugins/teststeps/exec/transport" ) @@ -34,7 +36,7 @@ func NewTargetRunner(ts *TestStep, ev testevent.Emitter, stepsVars test.StepsVar } func (r *TargetRunner) runWithOCP( - ctx xcontext.Context, target *target.Target, + ctx context.Context, target *target.Target, transport exec_transport.Transport, params stepParams, ) (outcome, error) { proc, err := transport.NewProcess(ctx, params.Bin.Path, params.Bin.Args) @@ -56,12 +58,12 @@ func (r *TargetRunner) runWithOCP( for dec.More() { var root *OCPRoot if err := dec.Decode(&root); err != nil { - ctx.Warnf("failed to decode ocp json: %w", err) + logging.Warnf(ctx, "failed to decode ocp json: %w", err) break } if err := p.Parse(ctx, root); err != nil { - ctx.Warnf("failed to parse ocp root: %w", err) + logging.Warnf(ctx, "failed to parse ocp root: %w", err) break } } @@ -74,7 +76,7 @@ func (r *TargetRunner) runWithOCP( } func (r *TargetRunner) runAny( - ctx xcontext.Context, target *target.Target, + ctx context.Context, target *target.Target, transport exec_transport.Transport, params stepParams, ) (outcome, error) { proc, err := transport.NewProcess(ctx, params.Bin.Path, params.Bin.Args) @@ -107,7 +109,7 @@ func (r *TargetRunner) runAny( } func (r *TargetRunner) run( - ctx xcontext.Context, target *target.Target, + ctx context.Context, target *target.Target, transport exec_transport.Transport, params stepParams, ) (outcome, error) { if params.OCPOutput { @@ -117,14 +119,14 @@ func (r *TargetRunner) run( return r.runAny(ctx, target, transport, params) } -func (r *TargetRunner) Run(ctx xcontext.Context, target *target.Target) error { - ctx.Infof("Executing on target %s", target) +func (r *TargetRunner) Run(ctx context.Context, target *target.Target) error { + logging.Infof(ctx, "Executing on target %s", target) // limit the execution time if specified timeQuota := r.ts.Constraints.TimeQuota if timeQuota != 0 { - var cancel xcontext.CancelFunc - ctx, cancel = xcontext.WithTimeout(ctx, time.Duration(timeQuota)) + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, time.Duration(timeQuota)) defer cancel() } diff --git a/plugins/teststeps/exec/transport/local_transport.go b/plugins/teststeps/exec/transport/local_transport.go index 468e28bd..cddf2bd2 100644 --- a/plugins/teststeps/exec/transport/local_transport.go +++ b/plugins/teststeps/exec/transport/local_transport.go @@ -3,17 +3,19 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. +//go:build unsafe // +build unsafe package transport import ( + "context" "errors" "fmt" "io" "os/exec" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/pkg/logging" ) type LocalTransport struct{} @@ -22,7 +24,7 @@ func NewLocalTransport() Transport { return &LocalTransport{} } -func (lt *LocalTransport) NewProcess(ctx xcontext.Context, bin string, args []string) (Process, error) { +func (lt *LocalTransport) NewProcess(ctx context.Context, bin string, args []string) (Process, error) { return newLocalProcess(ctx, bin, args) } @@ -31,7 +33,7 @@ type localProcess struct { cmd *exec.Cmd } -func newLocalProcess(ctx xcontext.Context, bin string, args []string) (Process, error) { +func newLocalProcess(ctx context.Context, bin string, args []string) (Process, error) { if err := checkBinary(bin); err != nil { return nil, err } @@ -40,8 +42,8 @@ func newLocalProcess(ctx xcontext.Context, bin string, args []string) (Process, return &localProcess{cmd}, nil } -func (lp *localProcess) Start(ctx xcontext.Context) error { - ctx.Debugf("starting local binary: %v", lp) +func (lp *localProcess) Start(ctx context.Context) error { + logging.Debugf(ctx, "starting local binary: %v", lp) if err := lp.cmd.Start(); err != nil { return fmt.Errorf("failed to start process: %w", err) } @@ -49,7 +51,7 @@ func (lp *localProcess) Start(ctx xcontext.Context) error { return nil } -func (lp *localProcess) Wait(_ xcontext.Context) error { +func (lp *localProcess) Wait(_ context.Context) error { if err := lp.cmd.Wait(); err != nil { var e *exec.ExitError if errors.As(err, &e) { diff --git a/plugins/teststeps/exec/transport/local_transport_safe.go b/plugins/teststeps/exec/transport/local_transport_safe.go index 74622d8b..ed3eb70b 100644 --- a/plugins/teststeps/exec/transport/local_transport_safe.go +++ b/plugins/teststeps/exec/transport/local_transport_safe.go @@ -3,14 +3,14 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. +//go:build !unsafe // +build !unsafe package transport import ( + "context" "fmt" - - "github.com/linuxboot/contest/pkg/xcontext" ) type LocalTransport struct{} @@ -19,6 +19,6 @@ func NewLocalTransport() Transport { return &LocalTransport{} } -func (lt *LocalTransport) NewProcess(ctx xcontext.Context, bin string, args []string) (Process, error) { +func (lt *LocalTransport) NewProcess(ctx context.Context, bin string, args []string) (Process, error) { return nil, fmt.Errorf("unavailable without unsafe build tag") } diff --git a/plugins/teststeps/exec/transport/ssh_process.go b/plugins/teststeps/exec/transport/ssh_process.go index 5f0e8ee8..53122b24 100644 --- a/plugins/teststeps/exec/transport/ssh_process.go +++ b/plugins/teststeps/exec/transport/ssh_process.go @@ -7,13 +7,15 @@ package transport import ( "bytes" + "context" "errors" "fmt" "io" "time" "github.com/kballard/go-shellquote" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/pkg/logging" + "golang.org/x/crypto/ssh" ) @@ -25,13 +27,13 @@ type sshProcess struct { stack *deferedStack } -func newSSHProcess(ctx xcontext.Context, client *ssh.Client, bin string, args []string, stack *deferedStack) (Process, error) { +func newSSHProcess(ctx context.Context, client *ssh.Client, bin string, args []string, stack *deferedStack) (Process, error) { var stdin bytes.Buffer return newSSHProcessWithStdin(ctx, client, bin, args, &stdin, stack) } func newSSHProcessWithStdin( - ctx xcontext.Context, client *ssh.Client, + ctx context.Context, client *ssh.Client, bin string, args []string, stdin io.Reader, stack *deferedStack, @@ -50,8 +52,8 @@ func newSSHProcessWithStdin( return &sshProcess{session, cmd, keepAliveDone, stack}, nil } -func (sp *sshProcess) Start(ctx xcontext.Context) error { - ctx.Debugf("starting remote binary: %s", sp.cmd) +func (sp *sshProcess) Start(ctx context.Context) error { + logging.Debugf(ctx, "starting remote binary: %s", sp.cmd) if err := sp.session.Start(sp.cmd); err != nil { return fmt.Errorf("failed to start process: %w", err) } @@ -63,19 +65,19 @@ func (sp *sshProcess) Start(ctx xcontext.Context) error { return case <-time.After(5 * time.Second): - ctx.Debugf("sending sigcont to ssh server...") + logging.Debugf(ctx, "sending sigcont to ssh server...") if err := sp.session.Signal(ssh.Signal("CONT")); err != nil { - ctx.Warnf("failed to send CONT to ssh server: %w", err) + logging.Warnf(ctx, "failed to send CONT to ssh server: %w", err) } case <-ctx.Done(): - ctx.Debugf("killing ssh session because of cancellation...") + logging.Debugf(ctx, "killing ssh session because of cancellation...") // TODO: figure out if there's a way to fix this (can be used for resource exhaustion) // note: not all servers implement the signal message so this might // not do anything; see comment about cancellation in Wait() if err := sp.session.Signal(ssh.SIGKILL); err != nil { - ctx.Warnf("failed to send KILL on context cancel: %w", err) + logging.Warnf(ctx, "failed to send KILL on context cancel: %w", err) } sp.session.Close() @@ -87,7 +89,7 @@ func (sp *sshProcess) Start(ctx xcontext.Context) error { return nil } -func (sp *sshProcess) Wait(ctx xcontext.Context) error { +func (sp *sshProcess) Wait(ctx context.Context) error { // close these no matter what error we get from the wait defer func() { sp.stack.Done() diff --git a/plugins/teststeps/exec/transport/ssh_process_async.go b/plugins/teststeps/exec/transport/ssh_process_async.go index 68c8b671..35c15003 100644 --- a/plugins/teststeps/exec/transport/ssh_process_async.go +++ b/plugins/teststeps/exec/transport/ssh_process_async.go @@ -7,6 +7,7 @@ package transport import ( "bytes" + "context" "errors" "fmt" "io" @@ -15,8 +16,9 @@ import ( "github.com/insomniacslk/xjson" "github.com/kballard/go-shellquote" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/remote" - "github.com/linuxboot/contest/pkg/xcontext" + "golang.org/x/crypto/ssh" ) @@ -36,7 +38,7 @@ type sshProcessAsync struct { } func newSSHProcessAsync( - ctx xcontext.Context, + ctx context.Context, addr string, clientConfig *ssh.ClientConfig, agent string, timeQuota xjson.Duration, bin string, args []string, @@ -64,7 +66,7 @@ func newSSHProcessAsync( }, nil } -func (spa *sshProcessAsync) Start(ctx xcontext.Context) error { +func (spa *sshProcessAsync) Start(ctx context.Context) error { errChan := make(chan error, 1) resChan := make(chan string, 1) @@ -91,7 +93,7 @@ func (spa *sshProcessAsync) Start(ctx xcontext.Context) error { return } - ctx.Debugf("starting remote agent: %s", spa.cmd) + logging.Debugf(ctx, "starting remote agent: %s", spa.cmd) if err := session.Start(spa.cmd); err != nil { errChan <- fmt.Errorf("failed to start process: %w", err) return @@ -110,7 +112,7 @@ func (spa *sshProcessAsync) Start(ctx xcontext.Context) error { return err case sid := <-resChan: - ctx.Debugf("remote sid: %s", sid) + logging.Debugf(ctx, "remote sid: %s", sid) outWriter := spa.outWriter if outWriter == nil { @@ -142,7 +144,7 @@ func (spa *sshProcessAsync) Start(ctx xcontext.Context) error { } } -func (spa *sshProcessAsync) Wait(_ xcontext.Context) error { +func (spa *sshProcessAsync) Wait(_ context.Context) error { defer spa.stack.Done() // wait for process @@ -188,7 +190,7 @@ type asyncMonitor struct { } func (m *asyncMonitor) Start( - ctx xcontext.Context, + ctx context.Context, outWriter io.WriteCloser, errWriter io.WriteCloser, exitChan chan<- error, ) { @@ -198,18 +200,18 @@ func (m *asyncMonitor) Start( for { select { case <-time.After(time.Second): - ctx.Debugf("polling remote process: %s", m.sid) + logging.Debugf(ctx, "polling remote process: %s", m.sid) stdout, err, runerr := m.runAgent(ctx, "poll") if err != nil { - ctx.Warnf("failed to run agent: %w", err) + logging.Warnf(ctx, "failed to run agent: %w", err) continue } if runerr != nil { // agent started but failed wait or exited with non-zero status if err := m.reap(ctx); err != nil { - ctx.Warnf("monitor error: %w", err) + logging.Warnf(ctx, "monitor error: %w", err) } exitChan <- runerr @@ -218,17 +220,17 @@ func (m *asyncMonitor) Start( var msg remote.PollMessage if err := remote.RecvResponse(bytes.NewReader(stdout), &msg); err != nil { - ctx.Warnf("failed to deserialize agent output: %w", err) + logging.Warnf(ctx, "failed to deserialize agent output: %w", err) } // append stdout, stderr; blocking until read if _, err := outWriter.Write([]byte(msg.Stdout)); err != nil { - ctx.Warnf("failed to write to stdout pipe: %w", err) + logging.Warnf(ctx, "failed to write to stdout pipe: %w", err) continue } if _, err := errWriter.Write([]byte(msg.Stderr)); err != nil { - ctx.Warnf("failed to write to stderr pipe: %w", err) + logging.Warnf(ctx, "failed to write to stderr pipe: %w", err) continue } @@ -241,7 +243,7 @@ func (m *asyncMonitor) Start( if msg.ExitCode != nil { // agent controlled process exited by itself, error was empty if err := m.reap(ctx); err != nil { - ctx.Warnf("monitor error: %w", err) + logging.Warnf(ctx, "monitor error: %w", err) } code := *msg.ExitCode @@ -254,11 +256,11 @@ func (m *asyncMonitor) Start( } case <-ctx.Done(): - ctx.Debugf("killing remote process, reason: cancellation") + logging.Debugf(ctx, "killing remote process, reason: cancellation") err := m.kill(ctx) if err := m.reap(ctx); err != nil { - ctx.Warnf("monitor error: %w", err) + logging.Warnf(ctx, "monitor error: %w", err) } exitChan <- err @@ -267,8 +269,8 @@ func (m *asyncMonitor) Start( } } -func (m *asyncMonitor) kill(ctx xcontext.Context) error { - ctx.Debugf("killing remote process: %s", m.sid) +func (m *asyncMonitor) kill(ctx context.Context) error { + logging.Debugf(ctx, "killing remote process: %s", m.sid) _, err, runerr := m.runAgent(ctx, "kill") if err != nil { @@ -282,8 +284,8 @@ func (m *asyncMonitor) kill(ctx xcontext.Context) error { return nil } -func (m *asyncMonitor) reap(ctx xcontext.Context) error { - ctx.Debugf("reaping remote process: %s", m.sid) +func (m *asyncMonitor) reap(ctx context.Context) error { + logging.Debugf(ctx, "reaping remote process: %s", m.sid) _, err, runerr := m.runAgent(ctx, "reap") if err != nil { @@ -296,7 +298,7 @@ func (m *asyncMonitor) reap(ctx xcontext.Context) error { return nil } -func (m *asyncMonitor) runAgent(ctx xcontext.Context, verb string) ([]byte, error, error) { +func (m *asyncMonitor) runAgent(ctx context.Context, verb string) ([]byte, error, error) { client, err := ssh.Dial("tcp", m.addr, m.clientConfig) if err != nil { return nil, fmt.Errorf("cannot connect to SSH server %s: %v", m.addr, err), nil @@ -314,7 +316,7 @@ func (m *asyncMonitor) runAgent(ctx xcontext.Context, verb string) ([]byte, erro session.Stderr = &stderr cmd := shellquote.Join(m.agent, verb, m.sid) - ctx.Debugf("starting agent command: %s", cmd) + logging.Debugf(ctx, "starting agent command: %s", cmd) if err := session.Start(cmd); err != nil { return nil, fmt.Errorf("failed to start remote agent: %w", err), nil } @@ -323,7 +325,7 @@ func (m *asyncMonitor) runAgent(ctx xcontext.Context, verb string) ([]byte, erro runerr := session.Wait() if stderr.Len() > 0 { - ctx.Debugf("agent produces unexpected stderr: %v", stderr.String()) + logging.Debugf(ctx, "agent produces unexpected stderr: %v", stderr.String()) } return stdout.Bytes(), nil, runerr } diff --git a/plugins/teststeps/exec/transport/ssh_transport.go b/plugins/teststeps/exec/transport/ssh_transport.go index 4b65422d..d2f63604 100644 --- a/plugins/teststeps/exec/transport/ssh_transport.go +++ b/plugins/teststeps/exec/transport/ssh_transport.go @@ -6,6 +6,7 @@ package transport import ( + "context" "fmt" "net" "os" @@ -14,10 +15,9 @@ import ( "github.com/google/uuid" "github.com/insomniacslk/xjson" + "github.com/linuxboot/contest/pkg/logging" "github.com/pkg/sftp" "golang.org/x/crypto/ssh" - - "github.com/linuxboot/contest/pkg/xcontext" ) type SSHTransportConfig struct { @@ -52,7 +52,7 @@ func NewSSHTransport(config SSHTransportConfig) Transport { return &SSHTransport{config} } -func (st *SSHTransport) NewProcess(ctx xcontext.Context, bin string, args []string) (Process, error) { +func (st *SSHTransport) NewProcess(ctx context.Context, bin string, args []string) (Process, error) { var signer ssh.Signer if st.IdentityFile != "" { key, err := os.ReadFile(st.IdentityFile) @@ -94,7 +94,7 @@ func (st *SSHTransport) NewProcess(ctx xcontext.Context, bin string, args []stri // cleanup the ssh client after the operations have ended stack.Add(func() { if err := client.Close(); err != nil { - ctx.Warnf("failed to close SSH client: %w", err) + logging.Warnf(ctx, "failed to close SSH client: %w", err) } }) @@ -110,9 +110,9 @@ func (st *SSHTransport) NewProcess(ctx xcontext.Context, bin string, args []stri // cleanup the sent file so we don't leave hanging files around stack.Add(func() { - ctx.Debugf("cleaning remote file: %s", bin) + logging.Debugf(ctx, "cleaning remote file: %s", bin) if err := st.unlinkFile(ctx, client, bin); err != nil { - ctx.Warnf("failed to cleanup remote file: %w", err) + logging.Warnf(ctx, "failed to cleanup remote file: %w", err) } }) } @@ -123,12 +123,12 @@ func (st *SSHTransport) NewProcess(ctx xcontext.Context, bin string, args []stri return st.new(ctx, client, bin, args, stack) } -func (st *SSHTransport) new(ctx xcontext.Context, client *ssh.Client, bin string, args []string, stack *deferedStack) (Process, error) { +func (st *SSHTransport) new(ctx context.Context, client *ssh.Client, bin string, args []string, stack *deferedStack) (Process, error) { return newSSHProcess(ctx, client, bin, args, stack) } func (st *SSHTransport) newAsync( - ctx xcontext.Context, + ctx context.Context, client *ssh.Client, addr string, clientConfig *ssh.ClientConfig, bin string, args []string, stack *deferedStack, @@ -140,16 +140,16 @@ func (st *SSHTransport) newAsync( } stack.Add(func() { - ctx.Debugf("cleaning async agent: %s", agent) + logging.Debugf(ctx, "cleaning async agent: %s", agent) if err := st.unlinkFile(ctx, client, agent); err != nil { - ctx.Warnf("failed to cleanup asyng agent: %w", err) + logging.Warnf(ctx, "failed to cleanup asyng agent: %w", err) } }) return newSSHProcessAsync(ctx, addr, clientConfig, agent, st.Async.TimeQuota, bin, args, stack) } -func (st *SSHTransport) sendFile(ctx xcontext.Context, client *ssh.Client, bin string, mode os.FileMode) (string, error) { +func (st *SSHTransport) sendFile(ctx context.Context, client *ssh.Client, bin string, mode os.FileMode) (string, error) { sftp, err := sftp.NewClient(client) if err != nil { return "", fmt.Errorf("failed to create sftp client: %w", err) @@ -169,7 +169,7 @@ func (st *SSHTransport) sendFile(ctx xcontext.Context, client *ssh.Client, bin s } defer fin.Close() - ctx.Debugf("sending file to remote: %s", remoteBin) + logging.Debugf(ctx, "sending file to remote: %s", remoteBin) _, err = fout.ReadFrom(fin) if err != nil { return "", fmt.Errorf("failed to send file: %w", err) @@ -178,7 +178,7 @@ func (st *SSHTransport) sendFile(ctx xcontext.Context, client *ssh.Client, bin s return remoteBin, fout.Chmod(mode) } -func (st *SSHTransport) unlinkFile(ctx xcontext.Context, client *ssh.Client, bin string) error { +func (st *SSHTransport) unlinkFile(ctx context.Context, client *ssh.Client, bin string) error { sftp, err := sftp.NewClient(client) if err != nil { return fmt.Errorf("failed to create sftp client: %w", err) diff --git a/plugins/teststeps/exec/transport/transport.go b/plugins/teststeps/exec/transport/transport.go index 7a550d8b..ac794f58 100644 --- a/plugins/teststeps/exec/transport/transport.go +++ b/plugins/teststeps/exec/transport/transport.go @@ -6,16 +6,16 @@ package transport import ( + "context" "encoding/json" "fmt" "io" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) type Transport interface { - NewProcess(ctx xcontext.Context, bin string, args []string) (Process, error) + NewProcess(ctx context.Context, bin string, args []string) (Process, error) } // ExitError is returned by Process.Wait when the controlled process exited with @@ -29,8 +29,8 @@ func (e *ExitError) Error() string { } type Process interface { - Start(ctx xcontext.Context) error - Wait(ctx xcontext.Context) error + Start(ctx context.Context) error + Wait(ctx context.Context) error StdoutPipe() (io.Reader, error) StderrPipe() (io.Reader, error) diff --git a/plugins/teststeps/gathercmd/gathercmd.go b/plugins/teststeps/gathercmd/gathercmd.go index 98f27062..32d80ad0 100644 --- a/plugins/teststeps/gathercmd/gathercmd.go +++ b/plugins/teststeps/gathercmd/gathercmd.go @@ -7,6 +7,7 @@ package gathercmd import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -14,11 +15,14 @@ import ( "path/filepath" "syscall" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -64,7 +68,7 @@ func (ts GatherCmd) Name() string { } func emitEvent( - ctx xcontext.Context, + ctx context.Context, emitter testevent.Emitter, target *target.Target, name event.Name, @@ -96,30 +100,30 @@ func truncate(in string, maxsize uint) string { return in[:size] } -func (ts *GatherCmd) acquireTargets(ctx xcontext.Context, ch test.TestStepChannels) ([]*target.Target, error) { +func (ts *GatherCmd) acquireTargets(ctx context.Context, ch test.TestStepChannels) ([]*target.Target, error) { var targets []*target.Target for { select { case target, ok := <-ch.In: if !ok { - ctx.Debugf("acquired %d targets", len(targets)) + logging.Debugf(ctx, "acquired %d targets", len(targets)) return targets, nil } targets = append(targets, target) - case <-ctx.Until(xcontext.ErrPaused): - ctx.Debugf("paused during target acquisition, acquired %d", len(targets)) - return nil, xcontext.ErrPaused + case <-signaling.Until(ctx, signals.Paused): + logging.Debugf(ctx, "paused during target acquisition, acquired %d", len(targets)) + return nil, signals.Paused case <-ctx.Done(): - ctx.Debugf("canceled during target acquisition, acquired %d", len(targets)) + logging.Debugf(ctx, "canceled during target acquisition, acquired %d", len(targets)) return nil, ctx.Err() } } } -func (ts *GatherCmd) returnTargets(ctx xcontext.Context, ch test.TestStepChannels, targets []*target.Target) { +func (ts *GatherCmd) returnTargets(ctx context.Context, ch test.TestStepChannels, targets []*target.Target) { for _, target := range targets { ch.Out <- test.TestStepResult{Target: target} } @@ -127,14 +131,14 @@ func (ts *GatherCmd) returnTargets(ctx xcontext.Context, ch test.TestStepChannel // Run executes the step func (ts *GatherCmd) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, emitter testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - log := ctx.Logger() + log := logger.FromCtx(ctx) if err := ts.setParams(params); err != nil { return nil, err @@ -157,12 +161,12 @@ func (ts *GatherCmd) Run( eventTarget := targets[0] // used to manually cancel the exec if step becomes paused - ctx, cancel := xcontext.WithCancel(ctx) + ctx, cancel := context.WithCancel(ctx) defer cancel() go func() { select { - case <-ctx.Until(xcontext.ErrPaused): + case <-signaling.Until(ctx, signals.Paused): log.Debugf("step was paused, killing the executing command") cancel() @@ -194,9 +198,13 @@ func (ts *GatherCmd) Run( if cmdErr := cmd.Run(); cmdErr != nil { // the command may have been canceled as a result of the step pausing - if ctx.IsSignaledWith(xcontext.ErrPaused) { + isPaused, err := signaling.IsSignaledWith(ctx, signals.Paused) + if err != nil { + return nil, fmt.Errorf("pause signaling internal error: %w", err) + } + if isPaused { // nothing to save, just continue pausing - return nil, xcontext.ErrPaused + return nil, signals.Paused } // output the failure event @@ -263,7 +271,7 @@ func (ts *GatherCmd) setParams(params test.TestStepParameters) error { } // ValidateParameters validates the parameters associated to the TestStep -func (ts *GatherCmd) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *GatherCmd) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return ts.setParams(params) } diff --git a/plugins/teststeps/qemu/qemu.go b/plugins/teststeps/qemu/qemu.go index 65dfa776..9f73b3fa 100644 --- a/plugins/teststeps/qemu/qemu.go +++ b/plugins/teststeps/qemu/qemu.go @@ -1,6 +1,7 @@ package qemu import ( + "context" "encoding/json" "errors" "fmt" @@ -11,12 +12,13 @@ import ( "regexp" "time" + "github.com/facebookincubator/go-belt/tool/logger" expect "github.com/google/goexpect" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -42,7 +44,7 @@ type Qemu struct { steps []test.Param } -// Needed for the Teststep interface. Returns a Teststep instance. +// Needed for the Teststep interface. Returns a Teststep instance. func New() test.TestStep { return &Qemu{} } @@ -60,7 +62,7 @@ func (q Qemu) Name() string { // ValidateParameters validates the parameters that will be passed to the Run // and Resume methods of the test step. -func (q *Qemu) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (q *Qemu) ValidateParameters(_ context.Context, params test.TestStepParameters) error { if q.executable = params.GetOne("executable"); q.executable.IsEmpty() { return fmt.Errorf("No Qemu executable given") } @@ -88,25 +90,25 @@ func (q *Qemu) ValidateParameters(_ xcontext.Context, params test.TestStepParame return nil } -func (q *Qemu) validateAndPopulate(ctx xcontext.Context, params test.TestStepParameters) error { +func (q *Qemu) validateAndPopulate(ctx context.Context, params test.TestStepParameters) error { return q.ValidateParameters(ctx, params) } // Run starts the Qemu instance for each target and interacts with the qemu instance // through the expect and send steps. -func (q *Qemu) Run(ctx xcontext.Context, +func (q *Qemu) Run(ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - log := ctx.Logger() + log := logger.FromCtx(ctx) if err := q.validateAndPopulate(ctx, params); err != nil { return nil, err } - f := func(ctx xcontext.Context, target *target.Target) error { + f := func(ctx context.Context, target *target.Target) error { targetTimeout, err := q.timeout.Expand(target, stepsVars) if err != nil { return err diff --git a/plugins/teststeps/randecho/randecho.go b/plugins/teststeps/randecho/randecho.go index a3b39820..e9ef08cb 100644 --- a/plugins/teststeps/randecho/randecho.go +++ b/plugins/teststeps/randecho/randecho.go @@ -6,6 +6,7 @@ package randecho import ( + "context" "encoding/json" "errors" "fmt" @@ -13,9 +14,10 @@ import ( "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -41,7 +43,7 @@ func Load() (string, test.TestStepFactory, []event.Name) { // ValidateParameters validates the parameters that will be passed to the Run // and Resume methods of the test step. -func (e Step) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (e Step) ValidateParameters(_ context.Context, params test.TestStepParameters) error { if t := params.GetOne("text"); t.IsEmpty() { return errors.New("Missing 'text' field in echo parameters") } @@ -55,7 +57,7 @@ func (e Step) Name() string { // Run executes the step func (e Step) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -63,7 +65,7 @@ func (e Step) Run( resumeState json.RawMessage, ) (json.RawMessage, error) { return teststeps.ForEachTarget(Name, ctx, ch, - func(ctx xcontext.Context, target *target.Target) error { + func(ctx context.Context, target *target.Target) error { r := rand.Intn(2) if r == 0 { evData := testevent.Data{ @@ -72,7 +74,7 @@ func (e Step) Run( Payload: nil, } _ = ev.Emit(ctx, evData) - ctx.Infof("Run: target %s succeeded: %s", target, params.GetOne("text")) + logging.Infof(ctx, "Run: target %s succeeded: %s", target, params.GetOne("text")) return nil } else { evData := testevent.Data{ @@ -81,7 +83,7 @@ func (e Step) Run( Payload: nil, } _ = ev.Emit(ctx, evData) - ctx.Infof("Run: target %s failed: %s", target, params.GetOne("text")) + logging.Infof(ctx, "Run: target %s failed: %s", target, params.GetOne("text")) return fmt.Errorf("target randomly failed") } }, diff --git a/plugins/teststeps/s3fileupload/s3fileupload.go b/plugins/teststeps/s3fileupload/s3fileupload.go index 12d8e985..3605e0e3 100644 --- a/plugins/teststeps/s3fileupload/s3fileupload.go +++ b/plugins/teststeps/s3fileupload/s3fileupload.go @@ -9,6 +9,7 @@ import ( "archive/tar" "bytes" "compress/gzip" + "context" "encoding/json" "fmt" "io" @@ -24,9 +25,10 @@ import ( "github.com/aws/aws-sdk-go/service/s3" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -65,7 +67,7 @@ func (ts FileUpload) Name() string { return Name } -func emitEvent(ctx xcontext.Context, name event.Name, payload interface{}, tgt *target.Target, ev testevent.Emitter) error { +func emitEvent(ctx context.Context, name event.Name, payload interface{}, tgt *target.Target, ev testevent.Emitter) error { payloadStr, err := json.Marshal(payload) if err != nil { return fmt.Errorf("cannot encode payload for event '%s': %w", name, err) @@ -84,7 +86,7 @@ func emitEvent(ctx xcontext.Context, name event.Name, payload interface{}, tgt * // Run executes the awsFileUpload. func (ts *FileUpload) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -95,7 +97,7 @@ func (ts *FileUpload) Run( if err := ts.validateAndPopulate(params); err != nil { return nil, err } - f := func(ctx xcontext.Context, target *target.Target) error { + f := func(ctx context.Context, target *target.Target) error { // expand args path, err := ts.localPath.Expand(target, stepsVars) if err != nil { @@ -188,7 +190,7 @@ func (ts *FileUpload) validateAndPopulate(params test.TestStepParameters) error } // ValidateParameters validates the parameters associated to the TestStep -func (ts *FileUpload) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *FileUpload) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return ts.validateAndPopulate(params) } @@ -203,7 +205,7 @@ func Load() (string, test.TestStepFactory, []event.Name) { } // createTarArchive creates compressed data writer and invokes addFileToArchive -func createTarArchive(file string, ctx xcontext.Context) (*bytes.Buffer, error) { +func createTarArchive(file string, ctx context.Context) (*bytes.Buffer, error) { // Create buffer for the compressed data var buf bytes.Buffer // Create gzip and tar writers @@ -220,7 +222,7 @@ func createTarArchive(file string, ctx xcontext.Context) (*bytes.Buffer, error) } // addFileToArchive takes the data and writes it into the tar archive -func addFileToArchive(tarwriter *tar.Writer, filename string, ctx xcontext.Context) error { +func addFileToArchive(tarwriter *tar.Writer, filename string, ctx context.Context) error { // Open the file which shall be written into the tar archive file, err := os.Open(filename) if err != nil { @@ -228,7 +230,7 @@ func addFileToArchive(tarwriter *tar.Writer, filename string, ctx xcontext.Conte } defer func() { if err := file.Close(); err != nil { - ctx.Warnf("failed to close file '%s': %w", filename, err) + logging.Warnf(ctx, "failed to close file '%s': %w", filename, err) } }() @@ -257,7 +259,7 @@ func addFileToArchive(tarwriter *tar.Writer, filename string, ctx xcontext.Conte } // Upload the file that is specified in the JobDescritor -func (ts *FileUpload) upload(filename string, data []byte, ctx xcontext.Context) (string, error) { +func (ts *FileUpload) upload(filename string, data []byte, ctx context.Context) (string, error) { // Create an AWS session s, err := session.NewSession(&aws.Config{Region: aws.String(ts.s3Region), @@ -288,7 +290,7 @@ func (ts *FileUpload) upload(filename string, data []byte, ctx xcontext.Context) if err != nil { return "", fmt.Errorf("could not upload the file: %w", err) } else { - ctx.Infof("Pushed the file to S3 Bucket!") + logging.Infof(ctx, "Pushed the file to S3 Bucket!") } // Create download link for public ACL url := strings.Join([]string{"https://", ts.s3Bucket, ".s3.amazonaws.com/", uploadPath}, "") diff --git a/plugins/teststeps/sleep/sleep.go b/plugins/teststeps/sleep/sleep.go index 9040d061..3ed288d5 100644 --- a/plugins/teststeps/sleep/sleep.go +++ b/plugins/teststeps/sleep/sleep.go @@ -6,6 +6,7 @@ package sleep import ( + "context" "encoding/json" "errors" "fmt" @@ -13,8 +14,11 @@ import ( "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -53,7 +57,7 @@ func getDuration(params test.TestStepParameters) (time.Duration, error) { // ValidateParameters validates the parameters that will be passed to the Run // and Resume methods of the test step. -func (ss *sleepStep) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ss *sleepStep) ValidateParameters(_ context.Context, params test.TestStepParameters) error { _, err := getDuration(params) return err } @@ -69,7 +73,7 @@ type sleepStepData struct { // Run executes the step func (ss *sleepStep) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -80,7 +84,7 @@ func (ss *sleepStep) Run( if err != nil { return nil, err } - fn := func(ctx xcontext.Context, target *teststeps.TargetWithData) error { + fn := func(ctx context.Context, target *teststeps.TargetWithData) error { var deadline time.Time // copy, can be different per target var sleepTime = dur @@ -93,7 +97,7 @@ func (ss *sleepStep) Run( } deadline = time.Unix(ssd.DeadlineMS/1000, (ssd.DeadlineMS%1000)*1000000) sleepTime = time.Until(deadline) - ctx.Debugf("restored with %v unix, in %s", ssd.DeadlineMS, time.Until(deadline)) + logging.Debugf(ctx, "restored with %v unix, in %s", ssd.DeadlineMS, time.Until(deadline)) } else { deadline = time.Now().Add(dur) } @@ -102,8 +106,8 @@ func (ss *sleepStep) Run( select { case <-time.After(sleepTime): return nil - case <-ctx.Until(xcontext.ErrPaused): - ctx.Debugf("%s: Paused with %s left", target.Target, time.Until(deadline)) + case <-signaling.Until(ctx, signals.Paused): + logging.Debugf(ctx, "%s: Paused with %s left", target.Target, time.Until(deadline)) ssd := &sleepStepData{ DeadlineMS: deadline.UnixNano() / 1000000, } @@ -112,9 +116,9 @@ func (ss *sleepStep) Run( if err != nil { return err } - return xcontext.ErrPaused + return signals.Paused case <-ctx.Done(): - ctx.Debugf("%s: Cancelled with %s left", target.Target, time.Until(deadline)) + logging.Debugf(ctx, "%s: Cancelled with %s left", target.Target, time.Until(deadline)) } return nil } diff --git a/plugins/teststeps/sshcmd/sshcmd.go b/plugins/teststeps/sshcmd/sshcmd.go index 70a7b2a7..4760607c 100644 --- a/plugins/teststeps/sshcmd/sshcmd.go +++ b/plugins/teststeps/sshcmd/sshcmd.go @@ -17,6 +17,7 @@ package sshcmd import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -27,14 +28,16 @@ import ( "strconv" "time" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/kballard/go-shellquote" "golang.org/x/crypto/ssh" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -70,14 +73,14 @@ func (ts SSHCmd) Name() string { // Run executes the cmd step. func (ts *SSHCmd) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - log := ctx.Logger() + log := logger.FromCtx(ctx) // XXX: Dragons ahead! The target (%t) substitution, and function // expression evaluations are done at run-time, so they may still fail @@ -91,7 +94,7 @@ func (ts *SSHCmd) Run( return nil, err } - f := func(ctx xcontext.Context, target *target.Target) error { + f := func(ctx context.Context, target *target.Target) error { // apply filters and substitutions to user, host, private key, and command args user, err := ts.User.Expand(target, stepsVars) if err != nil { @@ -203,7 +206,7 @@ func (ts *SSHCmd) Run( } defer func() { if err := client.Close(); err != nil { - ctx.Warnf("Failed to close SSH connection to %s: %v", addr, err) + logging.Warnf(ctx, "Failed to close SSH connection to %s: %v", addr, err) } }() session, err := client.NewSession() @@ -212,7 +215,7 @@ func (ts *SSHCmd) Run( } defer func() { if err := session.Close(); err != nil && err != io.EOF { - ctx.Warnf("Failed to close SSH session to %s: %v", addr, err) + logging.Warnf(ctx, "Failed to close SSH session to %s: %v", addr, err) } }() // run the remote command and catch stdout/stderr @@ -241,7 +244,7 @@ func (ts *SSHCmd) Run( if err == nil { // Execute expectations if expect == "" { - ctx.Warnf("no expectations specified") + logging.Warnf(ctx, "no expectations specified") } else { matches := re.FindAll(stdout.Bytes(), -1) if len(matches) > 0 { @@ -251,7 +254,7 @@ func (ts *SSHCmd) Run( } } } else { - ctx.Warnf("Stderr of command '%s' is '%s'", cmd, stderr.Bytes()) + logging.Warnf(ctx, "Stderr of command '%s' is '%s'", cmd, stderr.Bytes()) } return err case <-ctx.Done(): @@ -330,8 +333,8 @@ func (ts *SSHCmd) validateAndPopulate(params test.TestStepParameters) error { } // ValidateParameters validates the parameters associated to the TestStep -func (ts *SSHCmd) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error { - ctx.Debugf("Params %+v", params) +func (ts *SSHCmd) ValidateParameters(ctx context.Context, params test.TestStepParameters) error { + logging.Debugf(ctx, "Params %+v", params) return ts.validateAndPopulate(params) } diff --git a/plugins/teststeps/terminalexpect/terminalexpect.go b/plugins/teststeps/terminalexpect/terminalexpect.go index 3f44a857..1d025353 100644 --- a/plugins/teststeps/terminalexpect/terminalexpect.go +++ b/plugins/teststeps/terminalexpect/terminalexpect.go @@ -6,6 +6,7 @@ package terminalexpect import ( + "context" "encoding/json" "errors" "fmt" @@ -13,12 +14,13 @@ import ( "strings" "time" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/insomniacslk/termhook" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -43,7 +45,7 @@ func (ts TerminalExpect) Name() string { } // match implements termhook.LineHandler -func match(match string, log xcontext.Logger) termhook.LineHandler { +func match(match string, log logger.Logger) termhook.LineHandler { return func(w io.Writer, line []byte) (bool, error) { if strings.Contains(string(line), match) { log.Infof("%s: found pattern '%s'", Name, match) @@ -55,14 +57,14 @@ func match(match string, log xcontext.Logger) termhook.LineHandler { // Run executes the terminal step. func (ts *TerminalExpect) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - log := ctx.Logger() + log := logger.FromCtx(ctx) if err := ts.validateAndPopulate(params); err != nil { return nil, err @@ -72,7 +74,7 @@ func (ts *TerminalExpect) Run( return nil, err } // f implements plugins.PerTargetFunc - f := func(ctx xcontext.Context, target *target.Target) error { + f := func(ctx context.Context, target *target.Target) error { errCh := make(chan error, 1) go func() { errCh <- hook.Run() @@ -123,7 +125,7 @@ func (ts *TerminalExpect) validateAndPopulate(params test.TestStepParameters) er } // ValidateParameters validates the parameters associated to the TestStep -func (ts *TerminalExpect) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *TerminalExpect) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return ts.validateAndPopulate(params) } diff --git a/plugins/teststeps/teststeps.go b/plugins/teststeps/teststeps.go index f5bef9a5..19014578 100644 --- a/plugins/teststeps/teststeps.go +++ b/plugins/teststeps/teststeps.go @@ -6,19 +6,22 @@ package teststeps import ( + "context" "encoding/json" "fmt" "reflect" "sync" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // PerTargetFunc is a function type that is called on each target by the // ForEachTarget function below. -type PerTargetFunc func(ctx xcontext.Context, target *target.Target) error +type PerTargetFunc func(ctx context.Context, target *target.Target) error // ForEachTarget is a simple helper to write plugins that apply a given PerTargetFunc // independenly to each target. This helper handles routing through the in/out channels, @@ -29,17 +32,17 @@ type PerTargetFunc func(ctx xcontext.Context, target *target.Target) error // This function wraps the logic that handles target routing through the in/out // The implementation of the per-target function is responsible for // reacting to cancel/pause signals and return quickly. -func ForEachTarget(pluginName string, ctx xcontext.Context, ch test.TestStepChannels, f PerTargetFunc) (json.RawMessage, error) { +func ForEachTarget(pluginName string, ctx context.Context, ch test.TestStepChannels, f PerTargetFunc) (json.RawMessage, error) { reportTarget := func(t *target.Target, err error) { if err != nil { - ctx.Errorf("%s: ForEachTarget: failed to apply test step function on target %s: %v", pluginName, t, err) + logging.Errorf(ctx, "%s: ForEachTarget: failed to apply test step function on target %s: %v", pluginName, t, err) } else { - ctx.Debugf("%s: ForEachTarget: target %s completed successfully", pluginName, t) + logging.Debugf(ctx, "%s: ForEachTarget: target %s completed successfully", pluginName, t) } select { case ch.Out <- test.TestStepResult{Target: t, Err: err}: case <-ctx.Done(): - ctx.Debugf("%s: ForEachTarget: received cancellation signal while reporting result", pluginName) + logging.Debugf(ctx, "%s: ForEachTarget: received cancellation signal while reporting result", pluginName) } } @@ -49,10 +52,10 @@ func ForEachTarget(pluginName string, ctx xcontext.Context, ch test.TestStepChan select { case tgt, ok := <-ch.In: if !ok { - ctx.Debugf("%s: ForEachTarget: all targets have been received", pluginName) + logging.Debugf(ctx, "%s: ForEachTarget: all targets have been received", pluginName) return } - ctx.Debugf("%s: ForEachTarget: received target %s", pluginName, tgt) + logging.Debugf(ctx, "%s: ForEachTarget: received target %s", pluginName, tgt) wg.Add(1) go func() { defer wg.Done() @@ -61,7 +64,7 @@ func ForEachTarget(pluginName string, ctx xcontext.Context, ch test.TestStepChan reportTarget(tgt, err) }() case <-ctx.Done(): - ctx.Debugf("%s: ForEachTarget: incoming loop canceled", pluginName) + logging.Debugf(ctx, "%s: ForEachTarget: incoming loop canceled", pluginName) return } } @@ -88,7 +91,7 @@ func MarshalState(state interface{}, version int) (json.RawMessage, error) { if err != nil { return nil, err } - return data, xcontext.ErrPaused + return data, signals.Paused } // TargetWithData holds a step target and the pause/resumption data for it @@ -102,7 +105,7 @@ type TargetWithData struct { // PerTargetWithResumeFunc is the function that is called per target by ForEachTargetWithResume // It must obey the context and quickly return on cancellation and pause signals. // Functions can modify target and store any data required for resumption in target.data. -type PerTargetWithResumeFunc func(ctx xcontext.Context, target *TargetWithData) error +type PerTargetWithResumeFunc func(ctx context.Context, target *TargetWithData) error // parallelTargetsState is the internal state of ForEachTargetWithResume. type parallelTargetsState struct { @@ -121,7 +124,7 @@ type parallelTargetsState struct { // with the same data on job resumption. The helper will not call functions again that succeeded or failed // before the pause signal was received. // The supplied PerTargetWithResumeFunc must react to pause and cancellation signals as normal. -func ForEachTargetWithResume(ctx xcontext.Context, ch test.TestStepChannels, resumeState json.RawMessage, currentStepStateVersion int, f PerTargetWithResumeFunc) (json.RawMessage, error) { +func ForEachTargetWithResume(ctx context.Context, ch test.TestStepChannels, resumeState json.RawMessage, currentStepStateVersion int, f PerTargetWithResumeFunc) (json.RawMessage, error) { var ss parallelTargetsState // Parse resume state, if any. @@ -142,32 +145,32 @@ func ForEachTargetWithResume(ctx xcontext.Context, ch test.TestStepChannels, res err := f(ctx, tgt2) switch err { - case xcontext.ErrCanceled: + case context.Canceled: // nothing to do for failed - case xcontext.ErrPaused: + case signals.Paused: select { case pauseStates <- tgt2: case <-ctx.Done(): - ctx.Debugf("ForEachTargetWithResume: received cancellation signal while pausing") + logging.Debugf(ctx, "ForEachTargetWithResume: received cancellation signal while pausing") } default: // nil or error if err != nil { - ctx.Errorf("ForEachTargetWithResume: failed to apply test step function on target %s: %v", tgt2.Target.ID, err) + logging.Errorf(ctx, "ForEachTargetWithResume: failed to apply test step function on target %s: %v", tgt2.Target.ID, err) } else { - ctx.Debugf("ForEachTargetWithResume: target %s completed successfully", tgt2.Target.ID) + logging.Debugf(ctx, "ForEachTargetWithResume: target %s completed successfully", tgt2.Target.ID) } select { case ch.Out <- test.TestStepResult{Target: tgt2.Target, Err: err}: case <-ctx.Done(): - ctx.Debugf("ForEachTargetWithResume: received cancellation signal while reporting result") + logging.Debugf(ctx, "ForEachTargetWithResume: received cancellation signal while reporting result") } } } // restart paused targets for _, state := range ss.Targets { - ctx.Debugf("ForEachTargetWithResume: resuming target %s", state.Target.ID) + logging.Debugf(ctx, "ForEachTargetWithResume: resuming target %s", state.Target.ID) wg.Add(1) go handleTarget(state) } @@ -183,12 +186,12 @@ mainloop: if !ok { break mainloop } - ctx.Debugf("ForEachTargetWithResume: received target %s", tgt) + logging.Debugf(ctx, "ForEachTargetWithResume: received target %s", tgt) wg.Add(1) go handleTarget(&TargetWithData{Target: tgt}) case <-ctx.Done(): - ctx.Debugf("ForEachTargetWithResume: canceled, terminating") - err = xcontext.ErrCanceled + logging.Debugf(ctx, "ForEachTargetWithResume: canceled, terminating") + err = context.Canceled break mainloop } } @@ -204,10 +207,14 @@ mainloop: } // wrap up - if !ctx.IsSignaledWith(xcontext.ErrPaused) && len(ss.Targets) > 0 { + isPaused, _err := signaling.IsSignaledWith(ctx, signals.Paused) + if _err != nil { + return nil, fmt.Errorf("pause signaling internal error: %w", _err) + } + if !isPaused && len(ss.Targets) > 0 { return nil, fmt.Errorf("ForEachTargetWithResume: some target functions paused, but no pause signal received: %v ", ss.Targets) } - if ctx.IsSignaledWith(xcontext.ErrPaused) { + if isPaused { return MarshalState(&ss, currentStepStateVersion) } return nil, err diff --git a/plugins/teststeps/teststeps_test.go b/plugins/teststeps/teststeps_test.go index e00ba3ce..fd771f64 100644 --- a/plugins/teststeps/teststeps_test.go +++ b/plugins/teststeps/teststeps_test.go @@ -14,11 +14,13 @@ import ( "testing" "time" + "github.com/linuxboot/contest/pkg/logging" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/tests/common/goroutine_leak_check" @@ -27,7 +29,7 @@ import ( ) type data struct { - ctx xcontext.Context + ctx context.Context cancel, pause func() inCh chan *target.Target outCh chan test.TestStepResult @@ -35,8 +37,8 @@ type data struct { } func newData() data { - ctx, pause := xcontext.WithNotify(nil, xcontext.ErrPaused) - ctx, cancel := xcontext.WithCancel(ctx) + ctx, pause := signaling.WithSignal(context.Background(), signals.Paused) + ctx, cancel := context.WithCancel(ctx) inCh := make(chan *target.Target) outCh := make(chan test.TestStepResult) return data{ @@ -53,10 +55,10 @@ func newData() data { } func TestForEachTargetOneTarget(t *testing.T) { - ctx, _ := logrusctx.NewContext(logger.LevelDebug) - log := ctx.Logger() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + log := logger.FromCtx(ctx) d := newData() - fn := func(ctx xcontext.Context, tgt *target.Target) error { + fn := func(ctx context.Context, tgt *target.Target) error { log.Debugf("Handling target %s", tgt) return nil } @@ -64,7 +66,7 @@ func TestForEachTargetOneTarget(t *testing.T) { d.inCh <- &target.Target{ID: "target001"} close(d.inCh) }() - ctx, cancel := xcontext.WithCancel(ctx) + ctx, cancel := context.WithCancel(ctx) defer cancel() go func() { for { @@ -85,10 +87,10 @@ func TestForEachTargetOneTarget(t *testing.T) { } func TestForEachTargetOneTargetAllFail(t *testing.T) { - ctx, _ := logrusctx.NewContext(logger.LevelDebug) - log := ctx.Logger() + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + log := logger.FromCtx(ctx) d := newData() - fn := func(ctx xcontext.Context, t *target.Target) error { + fn := func(ctx context.Context, t *target.Target) error { log.Debugf("Handling target %s", t) return fmt.Errorf("error with target %s", t) } @@ -96,7 +98,7 @@ func TestForEachTargetOneTargetAllFail(t *testing.T) { d.inCh <- &target.Target{ID: "target001"} close(d.inCh) }() - ctx, cancel := xcontext.WithCancel(ctx) + ctx, cancel := context.WithCancel(ctx) defer cancel() go func() { for { @@ -118,8 +120,8 @@ func TestForEachTargetOneTargetAllFail(t *testing.T) { func TestForEachTargetTenTargets(t *testing.T) { d := newData() - fn := func(ctx xcontext.Context, tgt *target.Target) error { - ctx.Debugf("Handling target %s", tgt) + fn := func(ctx context.Context, tgt *target.Target) error { + logging.Debugf(ctx, "Handling target %s", tgt) return nil } go func() { @@ -137,7 +139,7 @@ func TestForEachTargetTenTargets(t *testing.T) { return case res := <-d.outCh: if res.Err == nil { - d.ctx.Debugf("Step for target %s completed as expected", res.Target) + logging.Debugf(d.ctx, "Step for target %s completed as expected", res.Target) } else { t.Errorf("Expected no error but got one: %v", res.Err) } @@ -150,8 +152,8 @@ func TestForEachTargetTenTargets(t *testing.T) { func TestForEachTargetTenTargetsAllFail(t *testing.T) { d := newData() - fn := func(ctx xcontext.Context, tgt *target.Target) error { - d.ctx.Debugf("Handling target %s", tgt) + fn := func(ctx context.Context, tgt *target.Target) error { + logging.Debugf(d.ctx, "Handling target %s", tgt) return fmt.Errorf("error with target %s", tgt) } go func() { @@ -171,7 +173,7 @@ func TestForEachTargetTenTargetsAllFail(t *testing.T) { if res.Err == nil { t.Errorf("Step for target %s expected to fail but completed successfully instead", res.Target) } else { - d.ctx.Debugf("Step for target failed as expected: %v", res.Err) + logging.Debugf(d.ctx, "Step for target failed as expected: %v", res.Err) } } } @@ -185,8 +187,8 @@ func TestForEachTargetTenTargetsOneFails(t *testing.T) { // chosen by fair dice roll. // guaranteed to be random. failingTarget := "target004" - fn := func(ctx xcontext.Context, tgt *target.Target) error { - d.ctx.Debugf("Handling target %s", tgt) + fn := func(ctx context.Context, tgt *target.Target) error { + logging.Debugf(d.ctx, "Handling target %s", tgt) if tgt.ID == failingTarget { return fmt.Errorf("error with target %s", tgt) } @@ -210,11 +212,11 @@ func TestForEachTargetTenTargetsOneFails(t *testing.T) { if res.Target.ID == failingTarget { t.Errorf("Step for target %s expected to fail but completed successfully instead", res.Target) } else { - d.ctx.Debugf("Step for target %s completed as expected", res.Target) + logging.Debugf(d.ctx, "Step for target %s completed as expected", res.Target) } } else { if res.Target.ID == failingTarget { - d.ctx.Debugf("Step for target %s failed as expected: %v", res.Target, res.Err) + logging.Debugf(d.ctx, "Step for target %s failed as expected: %v", res.Target, res.Err) } else { t.Errorf("Expected no error for %s but got one: %v", res.Target, res.Err) } @@ -234,15 +236,15 @@ func TestForEachTargetTenTargetsOneFails(t *testing.T) { func TestForEachTargetTenTargetsParallelism(t *testing.T) { sleepTime := 300 * time.Millisecond d := newData() - fn := func(ctx xcontext.Context, tgt *target.Target) error { - d.ctx.Debugf("Handling target %s", tgt) + fn := func(ctx context.Context, tgt *target.Target) error { + logging.Debugf(d.ctx, "Handling target %s", tgt) select { case <-ctx.Done(): - d.ctx.Debugf("target %s cancelled", tgt) - case <-ctx.Until(xcontext.ErrPaused): - d.ctx.Debugf("target %s paused", tgt) + logging.Debugf(d.ctx, "target %s cancelled", tgt) + case <-signaling.Until(ctx, signals.Paused): + logging.Debugf(d.ctx, "target %s paused", tgt) case <-time.After(sleepTime): - d.ctx.Debugf("target %s processed", tgt) + logging.Debugf(d.ctx, "target %s processed", tgt) } return nil } @@ -268,25 +270,25 @@ func TestForEachTargetTenTargetsParallelism(t *testing.T) { maxWaitTime := sleepTime * 3 deadline := time.Now().Add(maxWaitTime) - d.ctx.Debugf("Setting deadline to now+%s", maxWaitTime) + logging.Debugf(d.ctx, "Setting deadline to now+%s", maxWaitTime) for { select { case res := <-d.outCh: targetsRemain-- if res.Err == nil { - d.ctx.Debugf("Step for target %s completed successfully as expected", res.Target) + logging.Debugf(d.ctx, "Step for target %s completed successfully as expected", res.Target) } else { - d.ctx.Debugf("Step for target %s expected to completed successfully but failed instead", res.Target, res.Err) + logging.Debugf(d.ctx, "Step for target %s expected to completed successfully but failed instead", res.Target, res.Err) targetError = res.Err } if targetsRemain == 0 { - d.ctx.Debugf("All targets processed") + logging.Debugf(d.ctx, "All targets processed") return } case <-time.After(time.Until(deadline)): deadlineExceeded = true - d.ctx.Debugf("Deadline exceeded") + logging.Debugf(d.ctx, "Deadline exceeded") return } } @@ -310,16 +312,16 @@ func TestForEachTargetCancelSignalPropagation(t *testing.T) { var canceledTargets int32 d := newData() - fn := func(ctx xcontext.Context, tgt *target.Target) error { - d.ctx.Debugf("Handling target %s", tgt) + fn := func(ctx context.Context, tgt *target.Target) error { + logging.Debugf(d.ctx, "Handling target %s", tgt) select { case <-ctx.Done(): - d.ctx.Debugf("target %s caneled", tgt) + logging.Debugf(d.ctx, "target %s caneled", tgt) atomic.AddInt32(&canceledTargets, 1) - case <-ctx.Until(xcontext.ErrPaused): - d.ctx.Debugf("target %s paused", tgt) + case <-signaling.Until(ctx, signals.Paused): + logging.Debugf(d.ctx, "target %s paused", tgt) case <-time.After(sleepTime): - d.ctx.Debugf("target %s processed", tgt) + logging.Debugf(d.ctx, "target %s processed", tgt) } return nil } @@ -348,16 +350,16 @@ func TestForEachTargetCancelBeforeInputChannelClosed(t *testing.T) { var canceledTargets int32 d := newData() - fn := func(ctx xcontext.Context, tgt *target.Target) error { - d.ctx.Debugf("Handling target %s", tgt) + fn := func(ctx context.Context, tgt *target.Target) error { + logging.Debugf(d.ctx, "Handling target %s", tgt) select { case <-ctx.Done(): - d.ctx.Debugf("target %s cancelled", tgt) + logging.Debugf(d.ctx, "target %s cancelled", tgt) atomic.AddInt32(&canceledTargets, 1) - case <-ctx.Until(xcontext.ErrPaused): - d.ctx.Debugf("target %s paused", tgt) + case <-signaling.Until(ctx, signals.Paused): + logging.Debugf(d.ctx, "target %s paused", tgt) case <-time.After(sleepTime): - d.ctx.Debugf("target %s processed", tgt) + logging.Debugf(d.ctx, "target %s processed", tgt) } return nil } @@ -387,7 +389,7 @@ func TestForEachTargetWithResumeAllReturn(t *testing.T) { numTargets := 10 d := newData() - fn := func(ctx xcontext.Context, target *TargetWithData) error { + fn := func(ctx context.Context, target *TargetWithData) error { return nil // success } @@ -431,14 +433,14 @@ func TestForEachTargetWithResumeAllPause(t *testing.T) { } d := newData() - fn := func(ctx xcontext.Context, target *TargetWithData) error { + fn := func(ctx context.Context, target *TargetWithData) error { stepData := simpleStepData{target.Target.ID} json, err := json.Marshal(&stepData) require.NoError(t, err) // block and pause - <-ctx.Until(xcontext.ErrPaused) + <-signaling.Until(ctx, signals.Paused) target.Data = json - return xcontext.ErrPaused + return signals.Paused } var testingWg sync.WaitGroup @@ -469,7 +471,7 @@ func TestForEachTargetWithResumeAllPause(t *testing.T) { testingWg.Add(1) go func() { res, err := ForEachTargetWithResume(d.ctx, d.stepChans, nil, 1, fn) - assert.Equal(t, xcontext.ErrPaused, err) + assert.Equal(t, signals.Paused, err) // inspect result state := parallelTargetsState{} assert.NoError(t, json.Unmarshal(res, &state)) diff --git a/plugins/teststeps/variables/variables.go b/plugins/teststeps/variables/variables.go index f0c00d05..e46d3d4a 100644 --- a/plugins/teststeps/variables/variables.go +++ b/plugins/teststeps/variables/variables.go @@ -1,13 +1,16 @@ package variables import ( + "context" "encoding/json" "fmt" + "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -28,7 +31,7 @@ func (ts *Variables) Name() string { // Run executes the cmd step. func (ts *Variables) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -38,9 +41,9 @@ func (ts *Variables) Run( if err := ts.ValidateParameters(ctx, inputParams); err != nil { return nil, err } - return teststeps.ForEachTarget(Name, ctx, ch, func(ctx xcontext.Context, target *target.Target) error { + return teststeps.ForEachTarget(Name, ctx, ch, func(ctx context.Context, target *target.Target) error { for name, ps := range inputParams { - ctx.Debugf("add variable %s, value: %s", name, ps[0]) + logging.Debugf(ctx, "add variable %s, value: %s", name, ps[0]) if err := stepsVars.Add(target.ID, name, ps[0].RawMessage); err != nil { return err } @@ -50,7 +53,7 @@ func (ts *Variables) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *Variables) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error { +func (ts *Variables) ValidateParameters(ctx context.Context, params test.TestStepParameters) error { for name, ps := range params { if err := test.CheckIdentifier(name); err != nil { return fmt.Errorf("invalid variable name: '%s': %w", name, err) diff --git a/plugins/teststeps/variables/variables_test.go b/plugins/teststeps/variables/variables_test.go index ce7a7698..b69010ba 100644 --- a/plugins/teststeps/variables/variables_test.go +++ b/plugins/teststeps/variables/variables_test.go @@ -1,6 +1,7 @@ package variables import ( + "context" "encoding/json" "fmt" "sync" @@ -10,7 +11,7 @@ import ( "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/storage/memory" "github.com/stretchr/testify/require" ) @@ -25,8 +26,8 @@ func TestValidateParameters(t *testing.T) { obj := New() require.NotNil(t, obj) - require.NoError(t, obj.ValidateParameters(xcontext.Background(), nil)) - require.NoError(t, obj.ValidateParameters(xcontext.Background(), test.TestStepParameters{ + require.NoError(t, obj.ValidateParameters(context.Background(), nil)) + require.NoError(t, obj.ValidateParameters(context.Background(), test.TestStepParameters{ "var1": []test.Param{ { RawMessage: json.RawMessage("123"), @@ -34,7 +35,7 @@ func TestValidateParameters(t *testing.T) { }, })) // invalid variable name - require.Error(t, obj.ValidateParameters(xcontext.Background(), test.TestStepParameters{ + require.Error(t, obj.ValidateParameters(context.Background(), test.TestStepParameters{ "var var": []test.Param{ { RawMessage: json.RawMessage("123"), @@ -42,7 +43,7 @@ func TestValidateParameters(t *testing.T) { }, })) // invalid value - require.Error(t, obj.ValidateParameters(xcontext.Background(), test.TestStepParameters{ + require.Error(t, obj.ValidateParameters(context.Background(), test.TestStepParameters{ "var1": []test.Param{ { RawMessage: json.RawMessage("ALALALALA[}"), @@ -52,7 +53,7 @@ func TestValidateParameters(t *testing.T) { } func TestVariablesEmission(t *testing.T) { - ctx, cancel := xcontext.WithCancel(xcontext.Background()) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() obj := New() diff --git a/plugins/teststeps/waitport/waitport.go b/plugins/teststeps/waitport/waitport.go index 514452f3..b687a9c7 100644 --- a/plugins/teststeps/waitport/waitport.go +++ b/plugins/teststeps/waitport/waitport.go @@ -13,9 +13,10 @@ import ( "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -45,7 +46,7 @@ func (ts *WaitPort) Name() string { // Run executes the cmd step. func (ts *WaitPort) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -57,7 +58,7 @@ func (ts *WaitPort) Run( return nil, err } - f := func(ctx xcontext.Context, targetWithData *teststeps.TargetWithData) error { + f := func(ctx context.Context, targetWithData *teststeps.TargetWithData) error { target := targetWithData.Target targetParams, err := expandParameters(target, params, stepsVars) if err != nil { @@ -68,7 +69,7 @@ func (ts *WaitPort) Run( // Can emit duplicate events on server restart / job resumption payload, err := json.Marshal(targetParams) if err != nil { - ctx.Warnf("Cannot encode payload for %T: %v", params, err) + logging.Warnf(ctx, "Cannot encode payload for %T: %v", params, err) } else { rm := json.RawMessage(payload) evData := testevent.Data{ @@ -77,7 +78,7 @@ func (ts *WaitPort) Run( Payload: &rm, } if err := ev.Emit(ctx, evData); err != nil { - ctx.Warnf("Cannot emit event EventCmdStart: %v", err) + logging.Warnf(ctx, "Cannot emit event EventCmdStart: %v", err) } } @@ -107,19 +108,19 @@ func (ts *WaitPort) Run( var d net.Dialer conn, err := d.DialContext(finishedContext, targetParams.Protocol, addr) if err == nil { - ctx.Warnf("successfully connected via %s", addr) + logging.Warnf(ctx, "successfully connected via %s", addr) if err := conn.Close(); err != nil { - ctx.Warnf("failed to close opened connection: %v", err) + logging.Warnf(ctx, "failed to close opened connection: %v", err) } return nil } - ctx.Warnf("failed to connect to '%s', err: '%v'", addr, err) + logging.Warnf(ctx, "failed to connect to '%s', err: '%v'", addr, err) if finishedContext.Err() != nil { return finishedContext.Err() } } - ctx.Infof("wait for the next iteration") + logging.Infof(ctx, "wait for the next iteration") select { case <-finishedContext.Done(): return finishedContext.Err() @@ -135,17 +136,17 @@ func (ts *WaitPort) Run( Payload: nil, } if err := ev.Emit(ctx, evData); err != nil { - ctx.Warnf("Cannot emit event EventCmdEnd: %v", err) + logging.Warnf(ctx, "Cannot emit event EventCmdEnd: %v", err) } - ctx.Infof("wait port plugin finished, err: '%v'", resultErr) + logging.Infof(ctx, "wait port plugin finished, err: '%v'", resultErr) return resultErr } return teststeps.ForEachTargetWithResume(ctx, ch, resumeState, 0, f) } // ValidateParameters validates the parameters associated to the TestStep -func (ts *WaitPort) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error { +func (ts *WaitPort) ValidateParameters(ctx context.Context, params test.TestStepParameters) error { _, err := parseParameters(params) return err } diff --git a/plugins/teststeps/waitport/waitport_test.go b/plugins/teststeps/waitport/waitport_test.go index e04875fb..5696e8e3 100644 --- a/plugins/teststeps/waitport/waitport_test.go +++ b/plugins/teststeps/waitport/waitport_test.go @@ -1,6 +1,7 @@ package waitport import ( + "context" "fmt" "net" "sync" @@ -10,7 +11,7 @@ import ( "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/storage/memory" ) @@ -25,7 +26,7 @@ func TestWaitForTCPPort(t *testing.T) { } }() - ctx, cancel := xcontext.WithCancel(xcontext.Background()) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() m, err := memory.New() diff --git a/tests/common/get_events.go b/tests/common/get_events.go index 6e1d3e12..04ee9ea1 100644 --- a/tests/common/get_events.go +++ b/tests/common/get_events.go @@ -6,6 +6,7 @@ package common import ( + "context" "fmt" "strings" @@ -13,7 +14,6 @@ import ( "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) func eventToStringNoTime(ev testevent.Event) string { @@ -21,7 +21,7 @@ func eventToStringNoTime(ev testevent.Event) string { return fmt.Sprintf("{%s%s}", ev.Header, ev.Data) } -func getEventsAsString(ctx xcontext.Context, st storage.EventStorage, jobID types.JobID, testNames []string, eventNames []event.Name, targetID, stepLabel *string) string { +func getEventsAsString(ctx context.Context, st storage.EventStorage, jobID types.JobID, testNames []string, eventNames []event.Name, targetID, stepLabel *string) string { var qp []testevent.QueryField if jobID != 0 { qp = append(qp, testevent.QueryJobID(jobID)) @@ -59,12 +59,12 @@ func getEventsAsString(ctx xcontext.Context, st storage.EventStorage, jobID type // GetJobEventsAsString queries storage for particular test's events, // further filtering by target ID and/or step label. -func GetJobEventsAsString(ctx xcontext.Context, st storage.EventStorage, jobID types.JobID, eventNames []event.Name) string { +func GetJobEventsAsString(ctx context.Context, st storage.EventStorage, jobID types.JobID, eventNames []event.Name) string { return getEventsAsString(ctx, st, jobID, nil, eventNames, nil, nil) } // GetTestEventsAsString queries storage for particular test's events, // further filtering by target ID and/or step label. -func GetTestEventsAsString(ctx xcontext.Context, st storage.EventStorage, testNames []string, targetID, stepLabel *string) string { +func GetTestEventsAsString(ctx context.Context, st storage.EventStorage, testNames []string, targetID, stepLabel *string) string { return getEventsAsString(ctx, st, 0, testNames, nil, targetID, stepLabel) } diff --git a/tests/common/goroutine_leak_check/goroutine_leak_check.go b/tests/common/goroutine_leak_check/goroutine_leak_check.go index 926924e7..23039e22 100644 --- a/tests/common/goroutine_leak_check/goroutine_leak_check.go +++ b/tests/common/goroutine_leak_check/goroutine_leak_check.go @@ -30,7 +30,7 @@ func CheckLeakedGoRoutines(funcWhitelist ...string) error { for tryIdx := 0; tryIdx < 8; tryIdx++ { // We need to explicitly call GC to call full GC procedures for real. // Otherwise, for example there is high probability of not calling - // Finalizers (which are used in xcontext, for example). + // Finalizers (which are used in context, for example). runtime.GC() runtime.Gosched() diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index a63db76a..cf6690c6 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -10,6 +10,7 @@ package e2e import ( "bytes" + "context" "encoding/json" "fmt" "net" @@ -34,9 +35,8 @@ import ( "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/plugins/reporters/noop" "github.com/linuxboot/contest/plugins/reporters/targetsuccess" "github.com/linuxboot/contest/plugins/targetlocker/dblocker" @@ -58,7 +58,7 @@ import ( // NB: When adding a test here you need to invoke it explicitly from docker/contest/tests.sh var ( - ctx, _ = logrusctx.NewContext(logger.LevelDebug, logging.DefaultOptions()...) + ctx = logging.WithBelt(context.Background(), logger.LevelDebug) ) type E2ETestSuite struct { @@ -82,7 +82,7 @@ func (ts *E2ETestSuite) SetupSuite() { } func (ts *E2ETestSuite) TearDownSuite() { - ctx.Infof("Teardown") + logging.Infof(ctx, "Teardown") if !ts.T().Failed() { // Only check for goroutine leaks if otherwise ok. require.NoError(ts.T(), goroutine_leak_check.CheckLeakedGoRoutines()) } @@ -90,19 +90,21 @@ func (ts *E2ETestSuite) TearDownSuite() { func (ts *E2ETestSuite) SetupTest() { ts.dbURI = common.GetDatabaseURI() - ctx.Infof("DB URI: %s", ts.dbURI) + logging.Infof(ctx, "DB URI: %s", ts.dbURI) st, err := common.NewStorage() require.NoError(ts.T(), err) + ts.st = st require.NoError(ts.T(), st.(storage.ResettableStorage).Reset()) tl, err := dblocker.New(common.GetDatabaseURI()) require.NoError(ts.T(), err) _ = tl.ResetAllLocks(ctx) tl.Close() - ts.st = st } func (ts *E2ETestSuite) TearDownTest() { - ts.st.Close() + if ts.st != nil { + ts.st.Close() + } } func (ts *E2ETestSuite) startServer(extraArgs ...string) { @@ -138,7 +140,7 @@ func (ts *E2ETestSuite) startServer(extraArgs ...string) { continue } conn.Close() - ctx.Infof("Server is up") + logging.Infof(ctx, "Server is up") return } err := <-serverErr @@ -160,7 +162,7 @@ func (ts *E2ETestSuite) startJob(descriptorFile string) types.JobID { var resp api.StartResponse _, err = ts.runClient(&resp, "start", "-Y", descriptorFile) require.NoError(ts.T(), err) - ctx.Infof("%+v", resp) + logging.Infof(ctx, "%+v", resp) require.NotEqual(ts.T(), 0, resp.Data.JobID) return resp.Data.JobID } @@ -169,7 +171,7 @@ func (ts *E2ETestSuite) stopServer(timeout time.Duration) error { if ts.serverSigs == nil { return nil } - ctx.Infof("Stopping server...") + logging.Infof(ctx, "Stopping server...") var err error select { case ts.serverSigs <- syscall.SIGTERM: @@ -184,7 +186,7 @@ func (ts *E2ETestSuite) stopServer(timeout time.Duration) error { } ts.serverSigs = nil ts.serverDone = nil - ctx.Infof("Server stopped, err %v", err) + logging.Infof(ctx, "Server stopped, err %v", err) return err } @@ -242,9 +244,9 @@ func (ts *E2ETestSuite) TestSimple() { stdout, err := ts.runClient(&resp, "status", fmt.Sprintf("%d", jobID)) require.NoError(ts.T(), err) require.Nil(ts.T(), resp.Err, "error: %s", resp.Err) - ctx.Infof("Job %d state %s", jobID, resp.Data.Status.State) + logging.Infof(ctx, "Job %d state %s", jobID, resp.Data.Status.State) if resp.Data.Status.State == string(job.EventJobCompleted) { - ctx.Debugf("Job %d status: %s", jobID, stdout) + logging.Debugf(ctx, "Job %d status: %s", jobID, stdout) break } } @@ -254,7 +256,7 @@ func (ts *E2ETestSuite) TestSimple() { es := testsCommon.GetJobEventsAsString(ctx, ts.st, jobID, []event.Name{ cmd.EventCmdStdout, target.EventTargetAcquired, target.EventTargetReleased, }) - ctx.Debugf("%s", es) + logging.Debugf(ctx, "%s", es) require.Equal(ts.T(), fmt.Sprintf(` {[%d 1 Test 1 0 ][Target{ID: "T1"} TargetAcquired]} @@ -291,9 +293,9 @@ func (ts *E2ETestSuite) TestVariables() { stdout, err := ts.runClient(&resp, "status", fmt.Sprintf("%d", jobID)) require.NoError(ts.T(), err) require.Nil(ts.T(), resp.Err, "error: %s", resp.Err) - ctx.Infof("Job %d state %s", jobID, resp.Data.Status.State) + logging.Infof(ctx, "Job %d state %s", jobID, resp.Data.Status.State) if resp.Data.Status.State == string(job.EventJobCompleted) { - ctx.Debugf("Job %d status: %s", jobID, stdout) + logging.Debugf(ctx, "Job %d status: %s", jobID, stdout) break } } @@ -303,7 +305,7 @@ func (ts *E2ETestSuite) TestVariables() { es := testsCommon.GetJobEventsAsString(ctx, ts.st, jobID, []event.Name{ cmd.EventCmdStdout, target.EventTargetAcquired, target.EventTargetReleased, }) - ctx.Debugf("%s", es) + logging.Debugf(ctx, "%s", es) require.Equal(ts.T(), fmt.Sprintf(` {[%d 1 Test 1 0 ][Target{ID: "T1"} TargetAcquired]} @@ -329,10 +331,10 @@ func (ts *E2ETestSuite) TestPauseResume() { _, err := ts.runClient(&resp, "status", fmt.Sprintf("%d", jobID)) require.NoError(ts.T(), err) require.Nil(ts.T(), resp.Err, "error: %s", resp.Err) - ctx.Infof("Job %d state %s", jobID, resp.Data.Status.State) + logging.Infof(ctx, "Job %d state %s", jobID, resp.Data.Status.State) switch resp.Data.Status.State { case string(job.EventJobCompleted): - ctx.Debugf("Job %d completed after %d restarts", jobID, i) + logging.Debugf(ctx, "Job %d completed after %d restarts", jobID, i) break wait_loop case string(job.EventJobFailed): require.Failf(ts.T(), "job failed", "Job %d failed after %d restarts", jobID, i) @@ -348,7 +350,7 @@ func (ts *E2ETestSuite) TestPauseResume() { es := testsCommon.GetJobEventsAsString(ctx, ts.st, jobID, []event.Name{ cmd.EventCmdStdout, target.EventTargetAcquired, target.EventTargetReleased, }) - ctx.Debugf("%s", es) + logging.Debugf(ctx, "%s", es) require.Equal(ts.T(), fmt.Sprintf(` {[%d 1 Test 1 0 ][Target{ID: "T1"} TargetAcquired]} @@ -413,7 +415,7 @@ func (ts *E2ETestSuite) TestRetries() { } }() - ctx, cancel := xcontext.WithCancel(xcontext.Background()) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() var wg sync.WaitGroup @@ -436,9 +438,9 @@ func (ts *E2ETestSuite) TestRetries() { stdout, err := ts.runClient(&resp, "status", fmt.Sprintf("%d", jobID)) require.NoError(ts.T(), err) require.Nil(ts.T(), resp.Err, "error: %s", resp.Err) - ctx.Infof("Job %d state %s", jobID, resp.Data.Status.State) + logging.Infof(ctx, "Job %d state %s", jobID, resp.Data.Status.State) if resp.Data.Status.State == string(job.EventJobCompleted) { - ctx.Debugf("Job %d status: %s", jobID, stdout) + logging.Debugf(ctx, "Job %d status: %s", jobID, stdout) break } } @@ -449,7 +451,7 @@ func (ts *E2ETestSuite) TestRetries() { es := testsCommon.GetJobEventsAsString(ctx, ts.st, jobID, []event.Name{ cmd.EventCmdStdout, target.EventTargetAcquired, target.EventTargetReleased, target.EventTargetOut, target.EventTargetErr}) - ctx.Debugf("%s", es) + logging.Debugf(ctx, "%s", es) require.Equal(ts.T(), fmt.Sprintf(` {[%d 1 Test 1 0 ][Target{ID: "T1"} TargetAcquired]} diff --git a/tests/integ/events/frameworkevents/common.go b/tests/integ/events/frameworkevents/common.go index b2bf5ad1..7b08be45 100644 --- a/tests/integ/events/frameworkevents/common.go +++ b/tests/integ/events/frameworkevents/common.go @@ -9,16 +9,17 @@ package test import ( + "context" "encoding/json" "testing" "time" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/frameworkevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" "github.com/linuxboot/contest/tests/integ/common" "github.com/stretchr/testify/assert" @@ -27,7 +28,7 @@ import ( ) var ( - ctx, _ = logrusctx.NewContext(logger.LevelDebug) + ctx = logging.WithBelt(context.Background(), logger.LevelDebug) ) func mustBuildQuery(t require.TestingT, queryFields ...frameworkevent.QueryField) *frameworkevent.Query { diff --git a/tests/integ/events/testevents/common.go b/tests/integ/events/testevents/common.go index bccda310..a469e092 100644 --- a/tests/integ/events/testevents/common.go +++ b/tests/integ/events/testevents/common.go @@ -9,17 +9,18 @@ package test import ( + "context" "encoding/json" "testing" "time" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" "github.com/linuxboot/contest/tests/integ/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -27,7 +28,7 @@ import ( ) var ( - ctx, _ = logrusctx.NewContext(logger.LevelDebug) + ctx = logging.WithBelt(context.Background(), logger.LevelDebug) ) func mustBuildQuery(t require.TestingT, queryFields ...testevent.QueryField) *testevent.Query { diff --git a/tests/integ/job/common.go b/tests/integ/job/common.go index f679f6bf..ee9f29a8 100644 --- a/tests/integ/job/common.go +++ b/tests/integ/job/common.go @@ -9,15 +9,16 @@ package test import ( + "context" "time" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/linuxboot/contest/pkg/event/frameworkevent" "github.com/linuxboot/contest/pkg/job" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/types" "github.com/linuxboot/contest/tests/integ/common" @@ -53,7 +54,7 @@ var testDescs = ` ` var ( - ctx, _ = logrusctx.NewContext(logger.LevelDebug) + ctx = logging.WithBelt(context.Background(), logger.LevelDebug) ) type JobSuite struct { diff --git a/tests/integ/jobmanager/common.go b/tests/integ/jobmanager/common.go index e1306dc8..4fdab543 100644 --- a/tests/integ/jobmanager/common.go +++ b/tests/integ/jobmanager/common.go @@ -9,6 +9,7 @@ package test import ( + "context" "encoding/json" "errors" "fmt" @@ -28,12 +29,14 @@ import ( "github.com/linuxboot/contest/pkg/jobmanager" "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/pluginregistry" + "github.com/linuxboot/contest/pkg/signaling" + "github.com/linuxboot/contest/pkg/signals" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/plugins/reporters/targetsuccess" "github.com/linuxboot/contest/plugins/targetlocker/inmemory" "github.com/linuxboot/contest/plugins/targetmanagers/targetlist" @@ -92,13 +95,13 @@ type TestListener struct { // Serve implements the main logic of a dummy listener which talks to the API // layer to trigger actions in the JobManager -func (tl *TestListener) Serve(ctx xcontext.Context, contestApi *api.API) error { - ctx.Debugf("Serving mock listener") +func (tl *TestListener) Serve(ctx context.Context, contestApi *api.API) error { + logging.Debugf(ctx, "Serving mock listener") tl.api = contestApi for { select { case command := <-tl.commandCh: - ctx.Debugf("received command: %#+v", command) + logging.Debugf(ctx, "received command: %#+v", command) switch command.commandType { case StartJob: resp, err := contestApi.Start(ctx, "IntegrationTest", command.jobDescriptor) @@ -142,7 +145,7 @@ func pollForEvent(eventManager frameworkevent.EmitterFetcher, ev event.Name, job frameworkevent.QueryJobID(jobID), frameworkevent.QueryEventName(ev), } - ev, err := eventManager.Fetch(xcontext.Background(), queryFields...) + ev, err := eventManager.Fetch(context.Background(), queryFields...) if err != nil { return nil, err } @@ -165,7 +168,7 @@ func pollForTestEvent(eventManager testevent.Fetcher, ev event.Name, jobID types testevent.QueryJobID(jobID), testevent.QueryEventName(ev), } - ev, err := eventManager.Fetch(xcontext.Background(), queryFields...) + ev, err := eventManager.Fetch(context.Background(), queryFields...) if err != nil { return nil, err } @@ -214,7 +217,7 @@ type TestJobManagerSuite struct { // jobManagerCh is a control channel used to signal the termination of JobManager jobManagerCh chan struct{} // ctx is an input context to the JobManager which can be used to pause or cancel JobManager - jmCtx xcontext.Context + jmCtx context.Context jmPause, jmCancel func() } @@ -317,7 +320,7 @@ func (suite *TestJobManagerSuite) SetupTest() { suite.eventManager = eventManager suite.testEventManager = testEventManager - pr := pluginregistry.NewPluginRegistry(xcontext.Background()) + pr := pluginregistry.NewPluginRegistry(context.Background()) pr.RegisterTargetManager(targetlist.Name, targetlist.New) pr.RegisterTargetManager(readmeta.Name, readmeta.New) pr.RegisterTestFetcher(literal.Name, literal.New) @@ -352,12 +355,14 @@ func (suite *TestJobManagerSuite) initJobManager(instanceTag string) { require.NoError(suite.T(), err) suite.jm = jm - suite.jmCtx, suite.jmCancel = logrusctx.NewContext(logger.LevelDebug, logging.DefaultOptions()...) - suite.jmCtx, suite.jmPause = xcontext.WithNotify(suite.jmCtx, xcontext.ErrPaused) + ctx := logging.WithBelt(context.Background(), logger.LevelTrace) + ctx = beltctx.WithField(ctx, "integ-test", suite.T().Name()) + suite.jmCtx, suite.jmCancel = context.WithCancel(ctx) + suite.jmCtx, suite.jmPause = signaling.WithSignal(suite.jmCtx, signals.Paused) } func (suite *TestJobManagerSuite) BeforeTest(suiteName, testName string) { - suite.jmCtx.Infof("=== Running %s/%s", suiteName, testName) + logging.Infof(suite.jmCtx, "=== Running %s/%s", suiteName, testName) } func (suite *TestJobManagerSuite) stopJobManager() { @@ -451,7 +456,7 @@ func (suite *TestJobManagerSuite) testExit( select { case <-suite.jobManagerCh: - suite.jmCtx.Infof("jm finished") + logging.Infof(suite.jmCtx, "jm finished") case <-time.After(exitTimeout): suite.T().Errorf("JobManager should return within the timeout") } @@ -503,7 +508,7 @@ func (suite *TestJobManagerSuite) testPauseAndResume( time.Sleep(pauseAfter) // Signal pause to the manager. - suite.jmCtx.Infof("-> pausing") + logging.Infof(suite.jmCtx, "-> pausing") suite.jmPause() select { diff --git a/tests/integ/migration/0002_migrate_descriptor_to_extended_descriptor_test.go b/tests/integ/migration/0002_migrate_descriptor_to_extended_descriptor_test.go index 8958d142..3e24f51c 100644 --- a/tests/integ/migration/0002_migrate_descriptor_to_extended_descriptor_test.go +++ b/tests/integ/migration/0002_migrate_descriptor_to_extended_descriptor_test.go @@ -18,10 +18,12 @@ import ( _ "github.com/go-sql-driver/mysql" + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/experimental/metrics" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/db/rdbms/migration" "github.com/linuxboot/contest/pkg/job" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/tests/integ/common" "github.com/stretchr/testify/require" @@ -81,8 +83,8 @@ func (suite *TestDescriptorMigrationSuite) TearDownTest() { // TestFetchJobs tests that jobs are fetched correctly from the db func (suite *TestDescriptorMigrationSuite) TestUpMigratesToExtendedDescriptor() { - ctx, _ := logrusctx.NewContext(logger.LevelDebug) - ctx = ctx.WithTag("test", "TestDescriptorMigrationSuite") + ctx := logging.WithBelt(context.Background(), logger.LevelDebug) + ctx = beltctx.WithField(ctx, "test", "TestDescriptorMigrationSuite", metrics.FieldPropInclude) extendedDescriptorMigration := migration.NewDescriptorMigration(ctx) err := extendedDescriptorMigration.Up(suite.tx) diff --git a/tests/integ/plugins/cmd_plugin_test.go b/tests/integ/plugins/cmd_plugin_test.go index a6807e8b..9f83fac5 100644 --- a/tests/integ/plugins/cmd_plugin_test.go +++ b/tests/integ/plugins/cmd_plugin_test.go @@ -9,13 +9,14 @@ package tests import ( + "context" "testing" "time" "github.com/linuxboot/contest/pkg/runner" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/stretchr/testify/require" ) @@ -39,7 +40,7 @@ func TestCmdPlugin(t *testing.T) { {TestStep: ts1, Parameters: params}, } - stateCtx, cancel := xcontext.WithCancel(ctx) + stateCtx, cancel := context.WithCancel(ctx) errCh := make(chan error, 1) go func() { diff --git a/tests/integ/plugins/exec_plugin_test.go b/tests/integ/plugins/exec_plugin_test.go index 412f5893..a3a1b670 100644 --- a/tests/integ/plugins/exec_plugin_test.go +++ b/tests/integ/plugins/exec_plugin_test.go @@ -23,7 +23,7 @@ import ( "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -41,7 +41,7 @@ func nextID() int { return currentID } -func runExecPlugin(t *testing.T, ctx xcontext.Context, jsonParams string) error { +func runExecPlugin(t *testing.T, ctx context.Context, jsonParams string) error { jobID := types.JobID(nextID()) runID := types.RunID(1) @@ -301,7 +301,7 @@ func TestExecPluginLocalCancel(t *testing.T) { } }` - ctx, cancel := xcontext.WithTimeout(ctx, time.Second) + ctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() err := runExecPlugin(t, ctx, jsonParams) @@ -327,7 +327,7 @@ func TestExecPluginSSHCancel(t *testing.T) { } }` - ctx, cancel := xcontext.WithTimeout(ctx, time.Second) + ctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() err := runExecPlugin(t, ctx, jsonParams) @@ -358,7 +358,7 @@ func TestExecPluginSSHAsyncCancel(t *testing.T) { } }` - ctx, cancel := xcontext.WithTimeout(ctx, time.Second) + ctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() err := runExecPlugin(t, ctx, jsonParams) diff --git a/tests/integ/plugins/testrunner_test.go b/tests/integ/plugins/testrunner_test.go index 353f0b98..2f904baf 100644 --- a/tests/integ/plugins/testrunner_test.go +++ b/tests/integ/plugins/testrunner_test.go @@ -9,6 +9,7 @@ package tests import ( + "context" "fmt" "os" "testing" @@ -16,15 +17,15 @@ import ( "github.com/stretchr/testify/require" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/linuxboot/contest/pkg/event" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/pluginregistry" "github.com/linuxboot/contest/pkg/runner" "github.com/linuxboot/contest/pkg/storage" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" "github.com/linuxboot/contest/plugins/storage/memory" "github.com/linuxboot/contest/plugins/teststeps/cmd" "github.com/linuxboot/contest/plugins/teststeps/echo" @@ -39,7 +40,7 @@ import ( ) var ( - ctx, _ = logrusctx.NewContext(logger.LevelDebug) + ctx = logging.WithBelt(context.Background(), logger.LevelDebug) storageEngineVault = storage.NewSimpleEngineVault() ) diff --git a/tests/plugins/reporters/readmeta/readmeta.go b/tests/plugins/reporters/readmeta/readmeta.go index 49c6075c..b521ae7c 100644 --- a/tests/plugins/reporters/readmeta/readmeta.go +++ b/tests/plugins/reporters/readmeta/readmeta.go @@ -6,10 +6,11 @@ package readmeta_test import ( + "context" + "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/job" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name defines the name of the reporter used within the plugin registry @@ -36,7 +37,7 @@ func (n *Readmeta) Name() string { } // RunReport calculates the report to be associated with a job run. -func (n *Readmeta) RunReport(ctx xcontext.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { +func (n *Readmeta) RunReport(ctx context.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { // test metadata exists jobID, ok1 := types.JobIDFromContext(ctx) // note this must use panic to abort the test run, as this is a test for the job runner which ignore the actual outcome @@ -51,7 +52,7 @@ func (n *Readmeta) RunReport(ctx xcontext.Context, parameters interface{}, runSt } // FinalReport calculates the final report to be associated to a job. -func (n *Readmeta) FinalReport(ctx xcontext.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { +func (n *Readmeta) FinalReport(ctx context.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { // this one only has jobID, there is no specific runID in the final reporter jobID, ok1 := types.JobIDFromContext(ctx) // note this must use panic to abort the test run, as this is a test for the job runner which ignore the actual outcome diff --git a/tests/plugins/targetlist_with_state/targetlist_with_state.go b/tests/plugins/targetlist_with_state/targetlist_with_state.go index e30b2d1b..22888968 100644 --- a/tests/plugins/targetlist_with_state/targetlist_with_state.go +++ b/tests/plugins/targetlist_with_state/targetlist_with_state.go @@ -8,14 +8,15 @@ package targetlist_with_state import ( + "context" "encoding/json" "fmt" "math/rand" "time" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name defined the name of the plugin @@ -49,14 +50,14 @@ func (tlws TargetListWithState) ValidateReleaseParameters(params []byte) (interf } // Acquire implements contest.TargetManager.Acquire -func (tlws *TargetListWithState) Acquire(ctx xcontext.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) { +func (tlws *TargetListWithState) Acquire(ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) { acquireParameters, ok := parameters.(AcquireParameters) if !ok { return nil, fmt.Errorf("Acquire expects %T object, got %T", acquireParameters, parameters) } if err := tl.Lock(ctx, jobID, jobTargetManagerAcquireTimeout, acquireParameters.Targets); err != nil { - ctx.Warnf("Failed to lock %d targets: %v", len(acquireParameters.Targets), err) + logging.Warnf(ctx, "Failed to lock %d targets: %v", len(acquireParameters.Targets), err) return nil, err } var tt []*target.Target @@ -66,12 +67,12 @@ func (tlws *TargetListWithState) Acquire(ctx xcontext.Context, jobID types.JobID tt = append(tt, &tc) } time.Sleep(time.Duration(rand.Int31n(200)) * time.Millisecond) - ctx.Infof("Acquired %d targets", tt) + logging.Infof(ctx, "Acquired %d targets", tt) return tt, nil } // Release releases the acquired resources. -func (tlws *TargetListWithState) Release(ctx xcontext.Context, jobID types.JobID, targets []*target.Target, params interface{}) error { +func (tlws *TargetListWithState) Release(ctx context.Context, jobID types.JobID, targets []*target.Target, params interface{}) error { // Validate tokens to make sure state was passed correctly. for _, t := range targets { actualState := string(t.TargetManagerState) @@ -80,7 +81,7 @@ func (tlws *TargetListWithState) Release(ctx xcontext.Context, jobID types.JobID panic(fmt.Sprintf("state mismatch: expected %q, got %q", expectedState, actualState)) } } - ctx.Infof("Released %d targets", len(targets)) + logging.Infof(ctx, "Released %d targets", len(targets)) return nil } diff --git a/tests/plugins/targetlocker/targetlocker_common_test.go b/tests/plugins/targetlocker/targetlocker_common_test.go index 9edecceb..79e1b18b 100644 --- a/tests/plugins/targetlocker/targetlocker_common_test.go +++ b/tests/plugins/targetlocker/targetlocker_common_test.go @@ -6,9 +6,11 @@ package targetlocker import ( + "context" "time" "github.com/benbjohnson/clock" + "github.com/facebookincubator/go-belt/tool/logger" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -16,8 +18,6 @@ import ( "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" "github.com/linuxboot/contest/tests/common/goroutine_leak_check" ) @@ -33,7 +33,7 @@ var ( twoTargets = []*target.Target{target1[0], target2[0]} allTargets = []*target.Target{target1[0], target2[0], &target.Target{ID: "003"}, &target.Target{ID: "004"}} - ctx, _ = logrusctx.NewContext(logger.LevelDebug, logging.DefaultOptions()...) + ctx = logging.WithBelt(context.Background(), logger.LevelDebug) ) type TargetLockerTestSuite struct { diff --git a/tests/plugins/targetlocker/targetlocker_dblocker_test.go b/tests/plugins/targetlocker/targetlocker_dblocker_test.go index 3ed44777..22b1068f 100644 --- a/tests/plugins/targetlocker/targetlocker_dblocker_test.go +++ b/tests/plugins/targetlocker/targetlocker_dblocker_test.go @@ -3,6 +3,7 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. +//go:build integration_storage // +build integration_storage package targetlocker diff --git a/tests/plugins/targetmanagers/readmeta/readmeta.go b/tests/plugins/targetmanagers/readmeta/readmeta.go index 4acef8a7..f1de3bbc 100644 --- a/tests/plugins/targetmanagers/readmeta/readmeta.go +++ b/tests/plugins/targetmanagers/readmeta/readmeta.go @@ -6,11 +6,11 @@ package readmeta import ( + "context" "time" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name defined the name of the plugin @@ -33,7 +33,7 @@ func (r Readmeta) ValidateReleaseParameters(params []byte) (interface{}, error) } // Acquire implements contest.TargetManager.Acquire -func (t *Readmeta) Acquire(ctx xcontext.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) { +func (t *Readmeta) Acquire(ctx context.Context, jobID types.JobID, jobTargetManagerAcquireTimeout time.Duration, parameters interface{}, tl target.Locker) ([]*target.Target, error) { // test metadata exists jobID2, ok1 := types.JobIDFromContext(ctx) // note this must use panic to abort the test run, as this is a test for the job runner which ignore the actual outcome @@ -49,7 +49,7 @@ func (t *Readmeta) Acquire(ctx xcontext.Context, jobID types.JobID, jobTargetMan } // Release releases the acquired resources. -func (t *Readmeta) Release(ctx xcontext.Context, jobID types.JobID, targets []*target.Target, params interface{}) error { +func (t *Readmeta) Release(ctx context.Context, jobID types.JobID, targets []*target.Target, params interface{}) error { // test metadata exists jobID2, ok1 := types.JobIDFromContext(ctx) // note this must use panic to abort the test run, as this is a test for the job runner which ignore the actual outcome diff --git a/tests/plugins/teststeps/badtargets/badtargets.go b/tests/plugins/teststeps/badtargets/badtargets.go index 2ea7e4ae..90edce04 100644 --- a/tests/plugins/teststeps/badtargets/badtargets.go +++ b/tests/plugins/teststeps/badtargets/badtargets.go @@ -6,6 +6,7 @@ package badtargets import ( + "context" "encoding/json" "fmt" @@ -13,7 +14,6 @@ import ( "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -32,7 +32,7 @@ func (ts *badTargets) Name() string { // Run executes a step that messes up the flow of targets. func (ts *badTargets) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -54,30 +54,30 @@ func (ts *badTargets) Run( select { case ch.Out <- test.TestStepResult{Target: &tgt2}: case <-ctx.Done(): - return nil, xcontext.ErrCanceled + return nil, context.Canceled } case "TDup": select { case ch.Out <- test.TestStepResult{Target: tgt}: case <-ctx.Done(): - return nil, xcontext.ErrCanceled + return nil, context.Canceled } select { case ch.Out <- test.TestStepResult{Target: tgt}: case <-ctx.Done(): - return nil, xcontext.ErrCanceled + return nil, context.Canceled } case "TExtra": tgt2 := &target.Target{ID: "TExtra2"} select { case ch.Out <- test.TestStepResult{Target: tgt}: case <-ctx.Done(): - return nil, xcontext.ErrCanceled + return nil, context.Canceled } select { case ch.Out <- test.TestStepResult{Target: tgt2}: case <-ctx.Done(): - return nil, xcontext.ErrCanceled + return nil, context.Canceled } case "T1": // Mangle the returned target name. @@ -85,19 +85,19 @@ func (ts *badTargets) Run( select { case ch.Out <- test.TestStepResult{Target: tgt2}: case <-ctx.Done(): - return nil, xcontext.ErrCanceled + return nil, context.Canceled } default: return nil, fmt.Errorf("Unexpected target name: %q", tgt.ID) } case <-ctx.Done(): - return nil, xcontext.ErrCanceled + return nil, context.Canceled } } } // ValidateParameters validates the parameters associated to the TestStep -func (ts *badTargets) ValidateParameters(ctx xcontext.Context, params test.TestStepParameters) error { +func (ts *badTargets) ValidateParameters(ctx context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/channels/channels.go b/tests/plugins/teststeps/channels/channels.go index 971cd387..0dcef9ec 100644 --- a/tests/plugins/teststeps/channels/channels.go +++ b/tests/plugins/teststeps/channels/channels.go @@ -6,12 +6,12 @@ package channels import ( + "context" "encoding/json" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -30,7 +30,7 @@ func (ts *channels) Name() string { // Run executes a step that runs fine but closes its output channels on exit. func (ts *channels) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -46,7 +46,7 @@ func (ts *channels) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *channels) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *channels) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/crash/crash.go b/tests/plugins/teststeps/crash/crash.go index d3de211e..063a72db 100644 --- a/tests/plugins/teststeps/crash/crash.go +++ b/tests/plugins/teststeps/crash/crash.go @@ -6,13 +6,13 @@ package crash import ( + "context" "encoding/json" "fmt" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -31,7 +31,7 @@ func (ts *crash) Name() string { // Run executes a step which returns an error func (ts *crash) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -42,7 +42,7 @@ func (ts *crash) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *crash) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *crash) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/fail/fail.go b/tests/plugins/teststeps/fail/fail.go index 2042b08b..7de6b642 100644 --- a/tests/plugins/teststeps/fail/fail.go +++ b/tests/plugins/teststeps/fail/fail.go @@ -6,6 +6,7 @@ package fail import ( + "context" "encoding/json" "fmt" @@ -13,7 +14,7 @@ import ( "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -33,20 +34,20 @@ func (ts *fail) Name() string { // Run executes a step that fails all the targets it receives. func (ts *fail) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - return teststeps.ForEachTarget(Name, ctx, ch, func(ctx xcontext.Context, t *target.Target) error { + return teststeps.ForEachTarget(Name, ctx, ch, func(ctx context.Context, t *target.Target) error { return fmt.Errorf("Integration test failure for %v", t) }) } // ValidateParameters validates the parameters associated to the TestStep -func (ts *fail) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *fail) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/hanging/hanging.go b/tests/plugins/teststeps/hanging/hanging.go index 434af72a..904f0541 100644 --- a/tests/plugins/teststeps/hanging/hanging.go +++ b/tests/plugins/teststeps/hanging/hanging.go @@ -6,12 +6,12 @@ package hanging import ( + "context" "encoding/json" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -30,7 +30,7 @@ func (ts *hanging) Name() string { // Run executes a step that does not process any targets and never returns. func (ts *hanging) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -43,7 +43,7 @@ func (ts *hanging) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *hanging) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *hanging) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/noop/noop.go b/tests/plugins/teststeps/noop/noop.go index c380f431..546f66f6 100644 --- a/tests/plugins/teststeps/noop/noop.go +++ b/tests/plugins/teststeps/noop/noop.go @@ -6,13 +6,14 @@ package noop import ( + "context" "encoding/json" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -32,20 +33,20 @@ func (ts *noop) Name() string { // Run executes a step that does nothing and returns targets with success. func (ts *noop) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, inputParams test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - return teststeps.ForEachTarget(Name, ctx, ch, func(ctx xcontext.Context, t *target.Target) error { + return teststeps.ForEachTarget(Name, ctx, ch, func(ctx context.Context, t *target.Target) error { return nil }) } // ValidateParameters validates the parameters associated to the TestStep -func (ts *noop) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *noop) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/noreturn/noreturn.go b/tests/plugins/teststeps/noreturn/noreturn.go index e145bbb9..22c7dedd 100644 --- a/tests/plugins/teststeps/noreturn/noreturn.go +++ b/tests/plugins/teststeps/noreturn/noreturn.go @@ -6,12 +6,12 @@ package noreturn import ( + "context" "encoding/json" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -30,7 +30,7 @@ func (ts *noreturnStep) Name() string { // Run executes a step that never returns. func (ts *noreturnStep) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -46,7 +46,7 @@ func (ts *noreturnStep) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *noreturnStep) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *noreturnStep) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/panicstep/panicstep.go b/tests/plugins/teststeps/panicstep/panicstep.go index 5b565902..4f3d5745 100644 --- a/tests/plugins/teststeps/panicstep/panicstep.go +++ b/tests/plugins/teststeps/panicstep/panicstep.go @@ -6,12 +6,12 @@ package panicstep import ( + "context" "encoding/json" "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" ) // Name is the name used to look this plugin up. @@ -30,7 +30,7 @@ func (ts *panicStep) Name() string { // Run executes the example step. func (ts *panicStep) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -41,7 +41,7 @@ func (ts *panicStep) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *panicStep) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *panicStep) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/readmeta/readmeta.go b/tests/plugins/teststeps/readmeta/readmeta.go index 7ad58a56..55897a8a 100644 --- a/tests/plugins/teststeps/readmeta/readmeta.go +++ b/tests/plugins/teststeps/readmeta/readmeta.go @@ -6,6 +6,7 @@ package readmeta import ( + "context" "encoding/json" "fmt" @@ -14,7 +15,7 @@ import ( "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" "github.com/linuxboot/contest/pkg/types" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -38,14 +39,14 @@ func (ts *readmeta) Name() string { // Run executes a step that reads the job metadata that must be in the context and panics if it is missing. func (ts *readmeta) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, inputParams test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - return teststeps.ForEachTarget(Name, ctx, ch, func(ctx xcontext.Context, t *target.Target) error { + return teststeps.ForEachTarget(Name, ctx, ch, func(ctx context.Context, t *target.Target) error { jobID, ok1 := types.JobIDFromContext(ctx) if jobID == 0 || !ok1 { return fmt.Errorf("unable to extract jobID from context") @@ -70,7 +71,7 @@ func (ts *readmeta) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *readmeta) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *readmeta) ValidateParameters(_ context.Context, params test.TestStepParameters) error { return nil } diff --git a/tests/plugins/teststeps/slowecho/slowecho.go b/tests/plugins/teststeps/slowecho/slowecho.go index 280b0d86..2346b73b 100644 --- a/tests/plugins/teststeps/slowecho/slowecho.go +++ b/tests/plugins/teststeps/slowecho/slowecho.go @@ -6,6 +6,7 @@ package slowecho import ( + "context" "encoding/json" "errors" "strconv" @@ -15,9 +16,10 @@ import ( "github.com/linuxboot/contest/pkg/event" "github.com/linuxboot/contest/pkg/event/testevent" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -63,7 +65,7 @@ func sleepTime(secStr string) (time.Duration, error) { // ValidateParameters validates the parameters that will be passed to the Run // and Resume methods of the test step. -func (e *Step) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (e *Step) ValidateParameters(_ context.Context, params test.TestStepParameters) error { if t := params.GetOne("text"); t.IsEmpty() { return errors.New("missing 'text' field in slowecho parameters") } @@ -81,7 +83,7 @@ func (e *Step) ValidateParameters(_ xcontext.Context, params test.TestStepParame // Run executes the step func (e *Step) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, @@ -96,15 +98,15 @@ func (e *Step) Run( if clk == nil { clk = clock.New() } - f := func(ctx xcontext.Context, t *target.Target) error { - ctx.Infof("Waiting %v for target %s", sleep, t.ID) + f := func(ctx context.Context, t *target.Target) error { + logging.Infof(ctx, "Waiting %v for target %s", sleep, t.ID) select { case <-clk.After(sleep): case <-ctx.Done(): - ctx.Infof("Returning because cancellation is requested") - return xcontext.ErrCanceled + logging.Infof(ctx, "Returning because cancellation is requested") + return context.Canceled } - ctx.Infof("target %s: %s", t, params.GetOne("text")) + logging.Infof(ctx, "target %s: %s", t, params.GetOne("text")) return nil } return teststeps.ForEachTarget(Name, ctx, ch, f) diff --git a/tests/plugins/teststeps/teststep/teststep.go b/tests/plugins/teststeps/teststep/teststep.go index 831f75ad..7d961ef9 100644 --- a/tests/plugins/teststeps/teststep/teststep.go +++ b/tests/plugins/teststeps/teststep/teststep.go @@ -6,6 +6,7 @@ package teststep import ( + "context" "encoding/json" "fmt" "math/rand" @@ -17,7 +18,7 @@ import ( "github.com/linuxboot/contest/pkg/event/testevent" "github.com/linuxboot/contest/pkg/target" "github.com/linuxboot/contest/pkg/test" - "github.com/linuxboot/contest/pkg/xcontext" + "github.com/linuxboot/contest/plugins/teststeps" ) @@ -66,14 +67,14 @@ func (ts *Step) shouldFail(t *target.Target, params test.TestStepParameters) boo // Run executes the example step. func (ts *Step) Run( - ctx xcontext.Context, + ctx context.Context, ch test.TestStepChannels, ev testevent.Emitter, stepsVars test.StepsVariables, params test.TestStepParameters, resumeState json.RawMessage, ) (json.RawMessage, error) { - f := func(ctx xcontext.Context, target *target.Target) error { + f := func(ctx context.Context, target *target.Target) error { // Sleep to ensure TargetIn fires first. This simplifies test assertions. time.Sleep(50 * time.Millisecond) if err := ev.Emit(ctx, testevent.Data{EventName: StartedEvent, Target: target, Payload: nil}); err != nil { @@ -86,7 +87,7 @@ func (ts *Step) Run( select { case <-time.After(delay): case <-ctx.Done(): - return xcontext.ErrCanceled + return context.Canceled } if ts.shouldFail(target, params) { if err := ev.Emit(ctx, testevent.Data{EventName: FailedEvent, Target: target, Payload: nil}); err != nil { @@ -111,7 +112,7 @@ func (ts *Step) Run( } // ValidateParameters validates the parameters associated to the TestStep -func (ts *Step) ValidateParameters(_ xcontext.Context, params test.TestStepParameters) error { +func (ts *Step) ValidateParameters(_ context.Context, params test.TestStepParameters) error { targetsToFail := params.GetOne(FailTargetsParam).String() if len(targetsToFail) > 0 { for _, t := range strings.Split(targetsToFail, ",") { diff --git a/tools/migration/rdbms/main.go b/tools/migration/rdbms/main.go index 35b9e4ea..feb0fe7e 100644 --- a/tools/migration/rdbms/main.go +++ b/tools/migration/rdbms/main.go @@ -7,22 +7,24 @@ package main import ( "bytes" + "context" "flag" "fmt" "os" "path/filepath" // Import migration packages so that golang migrations can register themselves + "github.com/facebookincubator/go-belt/beltctx" + "github.com/facebookincubator/go-belt/tool/logger" + "github.com/facebookincubator/go-belt/tool/logger/implementation/logrus" _ "github.com/linuxboot/contest/db/rdbms/migration" - "github.com/linuxboot/contest/pkg/xcontext/bundles/logrusctx" - "github.com/linuxboot/contest/pkg/xcontext/logger" + "github.com/linuxboot/contest/pkg/logging" "github.com/linuxboot/contest/tools/migration/rdbms/migrate" _ "github.com/go-sql-driver/mysql" "github.com/pressly/goose" - "github.com/sirupsen/logrus" ) var ( @@ -77,35 +79,35 @@ func main() { if *flagDebug { logLevel = logger.LevelDebug } - var ctx, _ = logrusctx.NewContext(logLevel) - ctx.Logger().OriginalLogger().(*logrus.Entry).Logger.SetOutput(os.Stdout) + ctx := logging.WithBelt(context.Background(), logLevel) + logger.FromCtx(ctx).Emitter().(*logrus.Emitter).LogrusEntry.Logger.SetOutput(os.Stdout) if *flagDir == "" { flags.Usage() - ctx.Logger().Fatalf("migration directory was not specified") + logging.Fatalf(ctx, "migration directory was not specified") } for _, m := range migrate.Migrations { - migration := m.Factory(ctx.WithField("migration", filepath.Base(m.Name))) + migration := m.Factory(beltctx.WithField(ctx, "migration", filepath.Base(m.Name))) goose.AddNamedMigration(m.Name, migration.Up, migration.Down) } command := os.Args[len(os.Args)-1] db, err := goose.OpenDBWithDriver(*flagDBDriver, *flagDBURI) if err != nil { - ctx.Logger().Fatalf("failed to open DB: %v", err) + logging.Fatalf(ctx, "failed to open DB: %v", err) } if err := db.Ping(); err != nil { - ctx.Logger().Fatalf("db not reachable: %v", err) + logging.Fatalf(ctx, "db not reachable: %v", err) } defer func() { if err := db.Close(); err != nil { - ctx.Logger().Fatalf("failed to close DB: %v", err) + logging.Fatalf(ctx, "failed to close DB: %v", err) } }() if err := goose.Run(command, db, *flagDir, flags.Args()...); err != nil { - ctx.Logger().Fatalf("could not run command %v for migration: %v", command, err) + logging.Fatalf(ctx, "could not run command %v for migration: %v", command, err) } } diff --git a/tools/migration/rdbms/migrate/migrate.go b/tools/migration/rdbms/migrate/migrate.go index 53d0f713..917ee109 100644 --- a/tools/migration/rdbms/migrate/migrate.go +++ b/tools/migration/rdbms/migrate/migrate.go @@ -6,10 +6,9 @@ package migrate import ( + "context" "database/sql" "runtime" - - "github.com/linuxboot/contest/pkg/xcontext" ) // Migrate is the interface that every migration task must implement to support @@ -21,7 +20,7 @@ type Migrate interface { } // Factory defines a factory type of an object implementing Migration interface -type Factory func(ctx xcontext.Context) Migrate +type Factory func(ctx context.Context) Migrate // Migration represents a migration task registered in the migration tool type Migration struct {