From bb30f2f2b5e1aaf643fe2472f8ec02a169f176fa Mon Sep 17 00:00:00 2001 From: Cyril Tovena Date: Fri, 19 Mar 2021 09:07:43 +0100 Subject: [PATCH] Add sprig text/template function to template stage. Fixes #3129 Signed-off-by: Cyril Tovena --- .../clients/promtail/stages/template.md | 4 +- pkg/logentry/stages/template.go | 64 ++++++++++--------- pkg/logentry/stages/template_test.go | 12 ++++ .../Masterminds/sprig/v3/functions.go | 26 ++++---- 4 files changed, 63 insertions(+), 43 deletions(-) diff --git a/docs/sources/clients/promtail/stages/template.md b/docs/sources/clients/promtail/stages/template.md index 95b4d2cdec05..c69c91557cdb 100644 --- a/docs/sources/clients/promtail/stages/template.md +++ b/docs/sources/clients/promtail/stages/template.md @@ -113,6 +113,8 @@ The snippet above will for instance prepend the log line with the application na ## Supported Functions +> All [sprig functions](http://masterminds.github.io/sprig/) have been added to the template stage in Loki 2.3 along with function described below. + ### ToLower & ToUpper ToLower and ToUpper convert the entire string respectively to lowercase and uppercase. @@ -201,7 +203,7 @@ and trailing white space removed, as defined by Unicode. template: '{{ Hash .Value "salt" }}' ``` -Alternatively, you can use `Sha2Hash` for calculating the Sha2_256 of the string. Sha2_256 is faster and requires less CPU than Sha3_256, however it is less secure. +Alternatively, you can use `Sha2Hash` for calculating the Sha2_256 of the string. Sha2_256 is faster and requires less CPU than Sha3_256, however it is less secure. We recommend using `Hash` as it has a stronger hashing algorithm which we plan to keep strong over time without requiring client config changes. diff --git a/pkg/logentry/stages/template.go b/pkg/logentry/stages/template.go index 31698f808fae..47119c786173 100644 --- a/pkg/logentry/stages/template.go +++ b/pkg/logentry/stages/template.go @@ -11,6 +11,7 @@ import ( "text/template" "time" + "github.com/Masterminds/sprig/v3" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/mitchellh/mapstructure" @@ -25,35 +26,41 @@ const ( ErrTemplateSourceRequired = "template source value is required" ) -var ( - functionMap = template.FuncMap{ - "ToLower": strings.ToLower, - "ToUpper": strings.ToUpper, - "Replace": strings.Replace, - "Trim": strings.Trim, - "TrimLeft": strings.TrimLeft, - "TrimRight": strings.TrimRight, - "TrimPrefix": strings.TrimPrefix, - "TrimSuffix": strings.TrimSuffix, - "TrimSpace": strings.TrimSpace, - "Hash": func(salt string, input string) string { - hash := sha3.Sum256([]byte(salt + input)) - return hex.EncodeToString(hash[:]) - }, - "Sha2Hash": func(salt string, input string) string { - hash := sha256.Sum256([]byte(salt + input)) - return hex.EncodeToString(hash[:]) - }, - "regexReplaceAll": func(regex string, s string, repl string) string { - r := regexp.MustCompile(regex) - return r.ReplaceAllString(s, repl) - }, - "regexReplaceAllLiteral": func(regex string, s string, repl string) string { - r := regexp.MustCompile(regex) - return r.ReplaceAllLiteralString(s, repl) - }, +var extraFunctionMap = template.FuncMap{ + "ToLower": strings.ToLower, + "ToUpper": strings.ToUpper, + "Replace": strings.Replace, + "Trim": strings.Trim, + "TrimLeft": strings.TrimLeft, + "TrimRight": strings.TrimRight, + "TrimPrefix": strings.TrimPrefix, + "TrimSuffix": strings.TrimSuffix, + "TrimSpace": strings.TrimSpace, + "Hash": func(salt string, input string) string { + hash := sha3.Sum256([]byte(salt + input)) + return hex.EncodeToString(hash[:]) + }, + "Sha2Hash": func(salt string, input string) string { + hash := sha256.Sum256([]byte(salt + input)) + return hex.EncodeToString(hash[:]) + }, + "regexReplaceAll": func(regex string, s string, repl string) string { + r := regexp.MustCompile(regex) + return r.ReplaceAllString(s, repl) + }, + "regexReplaceAllLiteral": func(regex string, s string, repl string) string { + r := regexp.MustCompile(regex) + return r.ReplaceAllLiteralString(s, repl) + }, +} + +var functionMap = sprig.TxtFuncMap() + +func init() { + for k, v := range extraFunctionMap { + functionMap[k] = v } -) +} // TemplateConfig configures template value extraction type TemplateConfig struct { @@ -135,7 +142,6 @@ func (o *templateStage) Process(labels model.LabelSet, extracted map[string]inte } else { extracted[o.cfgs.Source] = st } - } // Name implements Stage diff --git a/pkg/logentry/stages/template_test.go b/pkg/logentry/stages/template_test.go index 9b62d93b3ea7..22fec94e004e 100644 --- a/pkg/logentry/stages/template_test.go +++ b/pkg/logentry/stages/template_test.go @@ -226,6 +226,18 @@ func TestTemplateStage_Process(t *testing.T) { "testval": "value", }, }, + "sprig": { + TemplateConfig{ + Source: "testval", + Template: "{{ add 7 3 }}", + }, + map[string]interface{}{ + "testval": "Value", + }, + map[string]interface{}{ + "testval": "10", + }, + }, "ToLowerParams": { TemplateConfig{ Source: "testval", diff --git a/vendor/github.com/Masterminds/sprig/v3/functions.go b/vendor/github.com/Masterminds/sprig/v3/functions.go index 57fcec1d9ea8..b0c6c8fcd23a 100644 --- a/vendor/github.com/Masterminds/sprig/v3/functions.go +++ b/vendor/github.com/Masterminds/sprig/v3/functions.go @@ -336,20 +336,20 @@ var genericMap = map[string]interface{}{ "mustChunk": mustChunk, // Crypto: - "bcrypt": bcrypt, - "htpasswd": htpasswd, - "genPrivateKey": generatePrivateKey, - "derivePassword": derivePassword, - "buildCustomCert": buildCustomCertificate, - "genCA": generateCertificateAuthority, - "genCAWithKey": generateCertificateAuthorityWithPEMKey, - "genSelfSignedCert": generateSelfSignedCertificate, + "bcrypt": bcrypt, + "htpasswd": htpasswd, + "genPrivateKey": generatePrivateKey, + "derivePassword": derivePassword, + "buildCustomCert": buildCustomCertificate, + "genCA": generateCertificateAuthority, + "genCAWithKey": generateCertificateAuthorityWithPEMKey, + "genSelfSignedCert": generateSelfSignedCertificate, "genSelfSignedCertWithKey": generateSelfSignedCertificateWithPEMKey, - "genSignedCert": generateSignedCertificate, - "genSignedCertWithKey": generateSignedCertificateWithPEMKey, - "encryptAES": encryptAES, - "decryptAES": decryptAES, - "randBytes": randBytes, + "genSignedCert": generateSignedCertificate, + "genSignedCertWithKey": generateSignedCertificateWithPEMKey, + "encryptAES": encryptAES, + "decryptAES": decryptAES, + "randBytes": randBytes, // UUIDs: "uuidv4": uuidv4,