diff --git a/engines/enginetest/testutils.go b/engines/enginetest/testutils.go index cca1a54a..281b83c3 100644 --- a/engines/enginetest/testutils.go +++ b/engines/enginetest/testutils.go @@ -50,6 +50,7 @@ func (p *engineProvider) ensureEngine(engineName string) { // Create Engine instance engine, err := engineProvider(extpoints.EngineOptions{ Environment: p.environment, + Log: p.environment.Log.WithField("engine", engineName), }) nilOrpanic(err, "Failed to create Engine") p.engine = engine @@ -77,9 +78,17 @@ func newTestEnvironment() *runtime.Environment { rt.SetFinalizer(folder, func(f runtime.TemporaryFolder) { f.Remove() }) + + logger, err := runtime.CreateLogger(os.Getenv("LOGGING_LEVEL")) + if err != nil { + fmt.Fprintf(os.Stderr, "Error creating logger. %s", err) + os.Exit(1) + } + return &runtime.Environment{ GarbageCollector: &gc.GarbageCollector{}, TemporaryStorage: folder, + Log: logger, } } diff --git a/engines/extpoints/extpoints.go b/engines/extpoints/extpoints.go index 56896bbe..5c3a6988 100644 --- a/engines/extpoints/extpoints.go +++ b/engines/extpoints/extpoints.go @@ -55,6 +55,7 @@ func UnregisterExtension(name string) []string { return ifaces } + // Base extension point type extensionPoint struct { @@ -175,3 +176,5 @@ func (ep *engineProviderExt) Names() []string { } return names } + + diff --git a/engines/extpoints/interfaces.go b/engines/extpoints/interfaces.go index d425961c..bbf88ecb 100644 --- a/engines/extpoints/interfaces.go +++ b/engines/extpoints/interfaces.go @@ -3,6 +3,7 @@ package extpoints import ( + "github.com/Sirupsen/logrus" "github.com/taskcluster/taskcluster-worker/engines" "github.com/taskcluster/taskcluster-worker/runtime" ) @@ -20,6 +21,7 @@ type EngineOptions struct { // Note: This is intended to be a simple argument wrapper, do not add methods // to this struct. Environment *runtime.Environment + Log *logrus.Entry } // EngineProvider is the interface engine implementors must implement and diff --git a/engines/mock/mockengine.go b/engines/mock/mockengine.go index 6cb52b76..54f1746e 100644 --- a/engines/mock/mockengine.go +++ b/engines/mock/mockengine.go @@ -3,8 +3,10 @@ package mockengine import ( + "fmt" "net/http" + "github.com/Sirupsen/logrus" "github.com/taskcluster/taskcluster-worker/engines" "github.com/taskcluster/taskcluster-worker/engines/extpoints" "github.com/taskcluster/taskcluster-worker/runtime" @@ -12,6 +14,7 @@ import ( type engine struct { engines.EngineBase + Log *logrus.Entry } func init() { @@ -19,7 +22,8 @@ func init() { extpoints.EngineProviders.Register(func( options extpoints.EngineOptions, ) (engines.Engine, error) { - return engine{}, nil + fmt.Println(options.Log) + return engine{Log: options.Log}, nil }, "mock") } @@ -30,7 +34,7 @@ type payload struct { Delay int64 `json:"delay"` } -func (engine) PayloadSchema() runtime.CompositeSchema { +func (e engine) PayloadSchema() runtime.CompositeSchema { // Declare the schema for the "task.payload.start" property schema, err := runtime.NewCompositeSchema("start", `{ "type": "object", @@ -60,10 +64,11 @@ func (engine) PayloadSchema() runtime.CompositeSchema { return schema } -func (engine) NewSandboxBuilder(options engines.SandboxOptions) (engines.SandboxBuilder, error) { +func (e engine) NewSandboxBuilder(options engines.SandboxOptions) (engines.SandboxBuilder, error) { // We know that payload was created with CompositeSchema.Parse() from the // schema returned by PayloadSchema(), so here we type assert that it is // indeed a pointer to such a thing. + e.Log.Debug("Building Sandbox") p, valid := options.Payload.(*payload) if !valid { // TODO: Write to some sort of log if the type assertion fails diff --git a/main.go b/main.go index 0781a37c..5424d1c3 100644 --- a/main.go +++ b/main.go @@ -6,45 +6,68 @@ package main import ( "fmt" - "log" + "os" "github.com/docopt/docopt-go" "github.com/taskcluster/taskcluster-worker/engines/extpoints" + "github.com/taskcluster/taskcluster-worker/runtime" ) const version = "taskcluster-worker 0.0.1" const usage = ` -Usage: taskcluster-worker [options] -Runs a worker with the given options. -Options: - -V, --version Display the version of go-import-subtree and exit. - -h, --help Print this help information. - -e, --engine Execution engine to run tasks in +TaskCluster worker +This worker is meant to be used with the taskcluster platform for the execution and +resolution of tasks. + + Usage: + taskcluster-worker --help + taskcluster-worker --version + taskcluster-worker --engine + taskcluster-worker --engine --logging + + Options: + --help Show this help screen. + --version Display the version of go-import-subtree and exit. + -e --engine Engine to use for task execution sandboxes. + -l --logging-level Set logging at . ` func main() { args, err := docopt.Parse(usage, nil, true, version, false, true) if err != nil { - log.Fatalf("Error parsing arguments. %v", err) + fmt.Fprintf(os.Stderr, "Error parsing arguments. %v", err) + os.Exit(1) } - e := args["--engine"] - if e == nil { - panic("Must supply engine type") + var level string + if l := args["--logging-level"]; l != nil { + level = l.(string) + } + logger, err := runtime.CreateLogger(level) + if err != nil { + os.Stderr.WriteString(err.Error()) + os.Exit(1) } + e := args["--engine"] engine := e.(string) engineProvider := extpoints.EngineProviders.Lookup(engine) if engineProvider == nil { engineNames := extpoints.EngineProviders.Names() - log.Fatalf("Must supply a valid engine. Supported Engines %v", engineNames) + logger.Fatalf("Must supply a valid engine. Supported Engines %v", engineNames) } - engineInstance, err := engineProvider(extpoints.EngineOptions{}) + runtimeEnvironment := runtime.Environment{Log: logger} + + _, err = engineProvider(extpoints.EngineOptions{ + Environment: &runtimeEnvironment, + Log: logger.WithField("engine", engine), + }) if err != nil { - panic(err) + logger.Fatal(err.Error()) } - fmt.Println(engineInstance) + + runtimeEnvironment.Log.Info("Worker started up") } diff --git a/plugins/extpoints/extpoints.go b/plugins/extpoints/extpoints.go index d476f7a3..9f8f86d5 100644 --- a/plugins/extpoints/extpoints.go +++ b/plugins/extpoints/extpoints.go @@ -55,6 +55,7 @@ func UnregisterExtension(name string) []string { return ifaces } + // Base extension point type extensionPoint struct { @@ -175,3 +176,5 @@ func (ep *pluginProviderExt) Names() []string { } return names } + + diff --git a/plugins/extpoints/interfaces.go b/plugins/extpoints/interfaces.go index c79c4c57..1f25bc9a 100644 --- a/plugins/extpoints/interfaces.go +++ b/plugins/extpoints/interfaces.go @@ -1,6 +1,7 @@ package extpoints import ( + "github.com/Sirupsen/logrus" "github.com/taskcluster/taskcluster-worker/engines" "github.com/taskcluster/taskcluster-worker/plugins" "github.com/taskcluster/taskcluster-worker/runtime" @@ -11,13 +12,14 @@ import ( // // We wrap all arguments so that we can add additional properties without // breaking source compatibility with older plugins. +// Note: This is passed by-value for efficiency (and to prohibit nil), if +// adding any large fields please consider adding them as pointers. +// Note: This is intended to be a simple argument wrapper, do not add methods +// to this struct. type PluginOptions struct { environment *runtime.Environment engine *engines.Engine - // Note: This is passed by-value for efficiency (and to prohibit nil), if - // adding any large fields please consider adding them as pointers. - // Note: This is intended to be a simple argument wrapper, do not add methods - // to this struct. + log *logrus.Entry } // The PluginProvider interface must be implemented and registered by anyone diff --git a/plugins/extpoints/manager.go b/plugins/extpoints/manager.go index b22fdce8..30399757 100644 --- a/plugins/extpoints/manager.go +++ b/plugins/extpoints/manager.go @@ -68,7 +68,11 @@ func NewPluginManager(pluginsToLoad []string, options PluginOptions) (plugins.Pl if pluginProvider == nil { return nil, errors.New("Missing plugin") } - plugin, err := pluginProvider(options) + plugin, err := pluginProvider(PluginOptions{ + environment: options.environment, + engine: options.engine, + log: options.log.WithField("plugin", p), + }) if err != nil { return nil, err } diff --git a/runtime/environment.go b/runtime/environment.go index 874ccb27..e160684e 100644 --- a/runtime/environment.go +++ b/runtime/environment.go @@ -1,6 +1,9 @@ package runtime -import "github.com/taskcluster/taskcluster-worker/runtime/gc" +import ( + "github.com/Sirupsen/logrus" + "github.com/taskcluster/taskcluster-worker/runtime/gc" +) // Environment is a collection of objects that makes up a runtime environment. type Environment struct { @@ -9,4 +12,5 @@ type Environment struct { //TODO: Add some interface to submit statistics for influxdb/signalfx //TODO: Add some interface to attach a http.Handler to public facing server TemporaryStorage TemporaryStorage + Log *logrus.Logger } diff --git a/runtime/log.go b/runtime/log.go new file mode 100644 index 00000000..614bc3fb --- /dev/null +++ b/runtime/log.go @@ -0,0 +1,26 @@ +package runtime + +import ( + "fmt" + + "github.com/Sirupsen/logrus" +) + +// Create a logger that can be passed around through the environment. +// Loggers can be created based on the one returned from this method by calling +// WithField or WithFields and specifying additional fields that the package +// would like. +func CreateLogger(level string) (*logrus.Logger, error) { + if level == "" { + level = "warn" + } + + lvl, err := logrus.ParseLevel(level) + if err != nil { + return nil, fmt.Errorf("Unable to parse logging level: %s\n", level) + } + + logger := logrus.New() + logger.Level = lvl + return logger, nil +} diff --git a/runtime/log_test.go b/runtime/log_test.go new file mode 100644 index 00000000..25e0363e --- /dev/null +++ b/runtime/log_test.go @@ -0,0 +1,29 @@ +package runtime + +import ( + "fmt" + "reflect" + "testing" + + "github.com/Sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +func TestCreateLogger(t *testing.T) { + logger, err := CreateLogger("debug") + assert.Equal(t, err, nil, fmt.Sprintf("Error should not have been returned. %s", err)) + assert.Equal(t, reflect.TypeOf(logger).String(), "*logrus.Logger") + assert.Equal(t, logger.Level, logrus.DebugLevel) +} + +func TestLoggerNotCreatedWithInvalidLevel(t *testing.T) { + _, err := CreateLogger("debug1234") + assert.NotEqual(t, err, nil, fmt.Sprintf("Error should not have been returned. %s", err)) +} + +func TestDefaultWarnLevel(t *testing.T) { + logger, err := CreateLogger("") + assert.Equal(t, err, nil, fmt.Sprintf("Error should not have been returned. %s", err)) + assert.Equal(t, reflect.TypeOf(logger).String(), "*logrus.Logger") + assert.Equal(t, logger.Level, logrus.WarnLevel) +}