Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]
- Added input metrics to Azure Blob Storage input. {issue}36641[36641] {pull}43954[43954]
- Added support for websocket keep_alive heartbeat in the streaming input. {issue}42277[42277] {pull}44204[44204]
- Allow empty HTTPJSON cursor template value evaluations to be ignored by Fleet health status updates. {pull}45361[45361]
- Add mechanism to allow HTTP JSON templates to terminate without logging an error. {issue}45664[45664] {pull}45810[45810]

*Auditbeat*

Expand Down
1 change: 1 addition & 0 deletions docs/reference/filebeat/filebeat-input-httpjson.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ Some built-in helper functions are provided to work with the input state inside
* `parseTimestamp`: parses a timestamp in seconds and returns a `time.Time` in UTC. Example: `[[parseTimestamp 1604582732]]` returns `2020-11-05 13:25:32 +0000 UTC`.
* `replaceAll(old, new, s)`: replaces all non-overlapping instances of `old` with `new` in `s`. Example: `[[ replaceAll "some" "my" "some value" ]]` returns `my value`.
* `sprintf`: formats according to a format specifier and returns the resulting string. Refer to [the Go docs](https://pkg.go.dev/fmt#Sprintf) for usage. Example: `[[sprintf "%d:%q" 34 "quote this"]]`
* `terminate`: exits the template without falling back to the default value and without causing an error. It takes a single string argument that is logged in debug logging. {applies_to}`stack: ga 9.1.2, ga 9.0.6, ga 8.19.2, ga 8.18.6`
* `toInt`: converts a value of any type to an integer when possible. Returns 0 if the conversion fails.
* `toJSON`: converts a value to a JSON string. This can be used with `value_type: json` to create an object from a template. Example: `[[ toJSON .last_response.body.pagingIdentifiers ]]`.
* `urlEncode`: URL encodes the supplied string. Example `[[urlEncode "string1"]]`. Example `[[urlEncode "<string1>"]]` will return `%3Cstring1%3E`.
Expand Down
4 changes: 3 additions & 1 deletion x-pack/filebeat/input/httpjson/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,9 +414,11 @@ func evaluateResponse(expression *valueTpl, data []byte, stat status.StatusRepor

val, err := expression.Execute(paramCtx, tr, "response_evaluation", nil, stat, log)
if err != nil {

return false, fmt.Errorf("error while evaluating expression: %w", err)
}
if val == "" {
return false, nil
}
result, err := strconv.ParseBool(val)
if err != nil {
return false, fmt.Errorf("error while parsing boolean value of string: %w", err)
Expand Down
17 changes: 17 additions & 0 deletions x-pack/filebeat/input/httpjson/value_tpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"urlEncode": urlEncode,
"userAgent": userAgentString,
"uuid": uuidString,
"terminate": func(s string) (any, error) { return nil, &errTerminate{s} },
}).
Delims(leftDelim, rightDelim).
Parse(in)
Expand All @@ -95,6 +96,17 @@
return nil
}

type errTerminate struct {
Reason string
}

func (e *errTerminate) Error() string {
if e.Reason != "" {
return "terminated template: " + e.Reason
}
return "terminated template"
}

func (t *valueTpl) Execute(trCtx *transformContext, tr transformable, targetName string, defaultVal *valueTpl, stat status.StatusReporter, log *logp.Logger) (val string, err error) {
fallback := func(err error) (string, error) {
if defaultVal != nil {
Expand Down Expand Up @@ -134,6 +146,11 @@
}

if err := t.Template.Execute(buf, data); err != nil {
var termErr *errTerminate
if errors.As(err, &termErr) {
log.Debugw("template execution terminated", "target", targetName, "reason", termErr.Reason)
return "", nil
}
return fallback(err)
}

Expand Down Expand Up @@ -331,7 +348,7 @@
case reflect.Float32, reflect.Float64:
return int64(vv.Float())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return int64(vv.Uint())

Check failure on line 351 in x-pack/filebeat/input/httpjson/value_tpl.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

G115: integer overflow conversion uint64 -> int64 (gosec)
case reflect.String:
f, _ := strconv.ParseFloat(vv.String(), 64)
return int64(f)
Expand Down
8 changes: 8 additions & 0 deletions x-pack/filebeat/input/httpjson/value_tpl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
)

func TestValueTpl(t *testing.T) {
logp.TestingSetup()

Check failure on line 22 in x-pack/filebeat/input/httpjson/value_tpl_test.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

SA1019: logp.TestingSetup is deprecated: Prefer using localized loggers. Use logptest.NewTestingLogger. (staticcheck)

cases := []struct {
name string
Expand Down Expand Up @@ -74,6 +74,14 @@
paramDefVal: "25",
expectedVal: "25",
},
{
name: "terminate",
value: `[[if false]]ok[[else]][[terminate "because reasons"]][[end]]`,
paramCtx: emptyTransformContext(),
paramTr: transformable{},
paramDefVal: "this should not be seen",
expectedVal: "",
},
{
name: "returns error if result is empty and no default is set",
value: "",
Expand Down
Loading