Support logging in starlark (#8408)

This commit is contained in:
Nicolas Filotto 2020-11-16 21:22:40 +01:00 committed by GitHub
parent dc782805da
commit 0c15569174
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 2 deletions

View File

@ -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: 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. * 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. 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. - [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 - [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. - [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. [All examples](/plugins/processors/starlark/testdata) are in the testdata folder.

View File

@ -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
}

View File

@ -52,7 +52,9 @@ func (s *Starlark) Init() error {
s.thread = &starlark.Thread{ s.thread = &starlark.Thread{
Print: func(_ *starlark.Thread, msg string) { s.Log.Debug(msg) }, 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{} 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 { switch module {
case "json.star": case "json.star":
return starlark.StringDict{ return starlark.StringDict{
"json": starlarkjson.Module, "json": starlarkjson.Module,
}, nil }, nil
case "logging.star":
return starlark.StringDict{
"log": LogModule(logger),
}, nil
default: default:
return nil, errors.New("module " + module + " is not available") return nil, errors.New("module " + module + " is not available")
} }

View File

@ -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 { for _, tt := range tests {

View File

@ -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