diff --git a/plugins/processors/starlark/README.md b/plugins/processors/starlark/README.md index 96da69e49..f674b7fdc 100644 --- a/plugins/processors/starlark/README.md +++ b/plugins/processors/starlark/README.md @@ -96,6 +96,7 @@ While Starlark is similar to Python, there are important differences to note: The ability to load external scripts other than your own is pretty limited. The following libraries are available for loading: * json: `load("json.star", "json")` provides the following functions: `json.encode()`, `json.decode()`, `json.indent()`. See [json.star](/plugins/processors/starlark/testdata/json.star) for an example. +* log: `load("logging.star", "log")` provides the following functions: `log.debug()`, `log.info()`, `log.warn()`, `log.error()`. See [logging.star](/plugins/processors/starlark/testdata/logging.star) for an example. If you would like to see support for something else here, please open an issue. @@ -185,6 +186,7 @@ def failing(metric): - [rename](/plugins/processors/starlark/testdata/rename.star) - Rename tags or fields using a name mapping. - [scale](/plugins/processors/starlark/testdata/scale.star) - Multiply any field by a number - [value filter](/plugins/processors/starlark/testdata/value_filter.star) - remove a metric based on a field value. +- [logging](/plugins/processors/starlark/testdata/logging.star) - Log messages with the logger of Telegraf [All examples](/plugins/processors/starlark/testdata) are in the testdata folder. diff --git a/plugins/processors/starlark/logging.go b/plugins/processors/starlark/logging.go new file mode 100644 index 000000000..35ba65d1d --- /dev/null +++ b/plugins/processors/starlark/logging.go @@ -0,0 +1,47 @@ +package starlark + +import ( + "errors" + "fmt" + + "github.com/influxdata/telegraf" + "go.starlark.net/starlark" + "go.starlark.net/starlarkstruct" +) + +// Builds a module that defines all the supported logging functions which will log using the provided logger +func LogModule(logger telegraf.Logger) *starlarkstruct.Module { + var logFunc = func(t *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { + return log(t, b, args, kwargs, logger) + } + return &starlarkstruct.Module{ + Name: "log", + Members: starlark.StringDict{ + "debug": starlark.NewBuiltin("log.debug", logFunc), + "info": starlark.NewBuiltin("log.info", logFunc), + "warn": starlark.NewBuiltin("log.warn", logFunc), + "error": starlark.NewBuiltin("log.error", logFunc), + }, + } +} + +// Logs the provided message according to the level chosen +func log(t *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple, logger telegraf.Logger) (starlark.Value, error) { + var msg starlark.String + if err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 1, &msg); err != nil { + return starlark.None, fmt.Errorf("%s: %v", b.Name(), err) + } + switch b.Name() { + case "log.debug": + logger.Debug(string(msg)) + case "log.info": + logger.Info(string(msg)) + case "log.warn": + logger.Warn(string(msg)) + case "log.error": + logger.Error(string(msg)) + default: + return nil, errors.New("method " + b.Name() + " is unknown") + } + return starlark.None, nil +} diff --git a/plugins/processors/starlark/starlark.go b/plugins/processors/starlark/starlark.go index a39b341f2..4835f06de 100644 --- a/plugins/processors/starlark/starlark.go +++ b/plugins/processors/starlark/starlark.go @@ -52,7 +52,9 @@ func (s *Starlark) Init() error { s.thread = &starlark.Thread{ Print: func(_ *starlark.Thread, msg string) { s.Log.Debug(msg) }, - Load: loadFunc, + Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) { + return loadFunc(thread, module, s.Log) + }, } builtins := starlark.StringDict{} @@ -217,12 +219,16 @@ func init() { }) } -func loadFunc(thread *starlark.Thread, module string) (starlark.StringDict, error) { +func loadFunc(thread *starlark.Thread, module string, logger telegraf.Logger) (starlark.StringDict, error) { switch module { case "json.star": return starlark.StringDict{ "json": starlarkjson.Module, }, nil + case "logging.star": + return starlark.StringDict{ + "log": LogModule(logger), + }, nil default: return nil, errors.New("module " + module + " is not available") } diff --git a/plugins/processors/starlark/starlark_test.go b/plugins/processors/starlark/starlark_test.go index f83767210..aad2575ca 100644 --- a/plugins/processors/starlark/starlark_test.go +++ b/plugins/processors/starlark/starlark_test.go @@ -2535,6 +2535,31 @@ func TestScript(t *testing.T) { ), }, }, + { + name: "logging", + plugin: &Starlark{ + Script: "testdata/logging.star", + Log: testutil.Logger{}, + }, + input: []telegraf.Metric{ + testutil.MustMetric("log", + map[string]string{}, + map[string]interface{}{ + "debug": "a debug message", + }, + time.Unix(0, 0), + ), + }, + expected: []telegraf.Metric{ + testutil.MustMetric("log", + map[string]string{}, + map[string]interface{}{ + "debug": "a debug message", + }, + time.Unix(0, 0), + ), + }, + }, } for _, tt := range tests { diff --git a/plugins/processors/starlark/testdata/logging.star b/plugins/processors/starlark/testdata/logging.star new file mode 100644 index 000000000..8be85eb96 --- /dev/null +++ b/plugins/processors/starlark/testdata/logging.star @@ -0,0 +1,19 @@ +# Example of the way to log a message with all the supported levels +# using the logger of Telegraf. +# +# Example Input: +# log debug="a debug message" 1465839830100400201 +# +# Example Output: +# log debug="a debug message" 1465839830100400201 + +load("logging.star", "log") +# loads log.debug(), log.info(), log.warn(), log.error() + +def apply(metric): + log.debug("debug: {}".format(metric.fields["debug"])) + log.info("an info message") + log.warn("a warning message") + log.error("an error message") + return metric + \ No newline at end of file