Skip to content

Commit

Permalink
Support logging in starlark (influxdata#8408)
Browse files Browse the repository at this point in the history
  • Loading branch information
essobedo authored Nov 16, 2020
1 parent cf3f455 commit 9e2417a
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 2 deletions.
2 changes: 2 additions & 0 deletions plugins/processors/starlark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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.

Expand Down
47 changes: 47 additions & 0 deletions plugins/processors/starlark/logging.go
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 8 additions & 2 deletions plugins/processors/starlark/starlark.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
Expand Down Expand Up @@ -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")
}
Expand Down
25 changes: 25 additions & 0 deletions plugins/processors/starlark/starlark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
19 changes: 19 additions & 0 deletions plugins/processors/starlark/testdata/logging.star
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 9e2417a

Please sign in to comment.