Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Heartbeat] Support JSON expressions / validation of JSON arrays #28073

Merged
merged 14 commits into from
Sep 27, 2021

Conversation

andrewvc
Copy link
Contributor

@andrewvc andrewvc commented Sep 22, 2021

This PR greatly improves validation of JSON HTTP response bodies in heartbeat in two different ways:

  1. Introduces a new notion of JSON expressions, using gval as an expression engine. This allows validation of complex data, including the use of JSON Path expressions within. As an example you can write an expression like: $.nodes[?(@name == "foo"][2].message == "hello" to traverse a JSON object containing a nodes key with nested objects, find all elements named "foo", select the third one, then see if its' message attribute equals "hello".
  2. Supports handling APIs that return arrays of JSON objects without a top level object root. Previously, we only parsed JSON response that looked like an object, e.g. {"an": "object"}, we now support: [{"one": 1},{"two": 2}].
  3. Deprecates the condition configuration in favor of this new expression syntax. The new syntax is more consistent and powerful, and should be less effort to maintain.

It also splits out the JSON checking code into separate files to cut down on the extreme length of the originals.

Fixes #27283

Checklist

  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have made corresponding change to the default configuration files
  • I have added tests that prove my fix is effective or that my feature works
  • I have added an entry in CHANGELOG.next.asciidoc or CHANGELOG-developer.next.asciidoc.

How to test this PR locally

Try the docs examples

@andrewvc andrewvc added enhancement v7.16.0 backport-v7.16.0 Automated backport with mergify labels Sep 22, 2021
@andrewvc andrewvc self-assigned this Sep 22, 2021
@botelastic botelastic bot added the needs_team Indicates that the issue/PR needs a Team:* label label Sep 22, 2021
@elasticmachine
Copy link
Collaborator

elasticmachine commented Sep 23, 2021

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview preview

Expand to view the summary

Build stats

  • Start Time: 2021-09-27T13:35:21.838+0000

  • Duration: 223 min 22 sec

  • Commit: 0e6a11b

Test stats 🧪

Test Results
Failed 0
Passed 54135
Skipped 5328
Total 59463

💚 Flaky test report

Tests succeeded.

🤖 GitHub comments

To re-run your PR in the CI, just comment with:

  • /test : Re-trigger the build.

  • /package : Generate the packages and run the E2E tests.

  • /beats-tester : Run the installation tests with beats-tester.

@andrewvc
Copy link
Contributor Author

@lowryxiao I noticed you spotted a bugfix earlier, if you have any feedback here it's appreciated as well!

@@ -258,12 +258,6 @@ This monitor examines match successfully only when 'foo' or 'Foo' in body AND no
name: Demo Service
schedule: '@every 5s'
urls: ["http://localhost:8080/demo/add"]
check.request:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was redundant for this section, we're focusing on JSON here

@@ -219,53 +211,3 @@ func checkBody(positiveMatch, negativeMatch []match.Matcher) bodyValidator {
return nil
}
}

func checkJSON(checks []*jsonResponseCheck) (bodyValidator, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to checkjson.go

@@ -196,142 +194,6 @@ func TestCheckBody(t *testing.T) {
}
}

func TestCheckJson(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to checkjson_test.go

source: check.Expression,
})
} else if check.Condition != nil {
cfgwarn.Deprecate("8.0.0", "JSON conditions are deprecated, use 'expression' instead.")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do a follow-up PR to actually delete this in master if we agree we should just move to expression

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion here, Do you see people using conditions for simpler use case?

@andrewvc andrewvc marked this pull request as ready for review September 23, 2021 02:23
@andrewvc andrewvc requested a review from a team as a code owner September 23, 2021 02:23
@andrewvc andrewvc added the Team:obs-ds-hosted-services Label for the Observability Hosted Services team label Sep 23, 2021
@botelastic botelastic bot removed the needs_team Indicates that the issue/PR needs a Team:* label label Sep 23, 2021
@elasticmachine
Copy link
Collaborator

Pinging @elastic/uptime (Team:Uptime)

@andrewvc andrewvc added Heartbeat needs_team Indicates that the issue/PR needs a Team:* label labels Sep 23, 2021
@botelastic botelastic bot removed the needs_team Indicates that the issue/PR needs a Team:* label label Sep 23, 2021
@botelastic
Copy link

botelastic bot commented Sep 23, 2021

This pull request doesn't have a Team:<team> label.

Copy link
Member

@vigneshshanmugam vigneshshanmugam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good to me, Added small comments.

source: check.Expression,
})
} else if check.Condition != nil {
cfgwarn.Deprecate("8.0.0", "JSON conditions are deprecated, use 'expression' instead.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion here, Do you see people using conditions for simpler use case?

condition common.MapStr
expectedErrMsg string
expectedContentType string
}

testCases := []testCase{
{
"simple match",
"expression simple match",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to add one more case when both condition and expression exists?

@andrewvc
Copy link
Contributor Author

@vigneshshanmugam I've incorporated your PR feedback into 0e6a11b , I think it's a bit cleaner, esp. with the new config validator

Copy link
Member

@vigneshshanmugam vigneshshanmugam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍🏽

@andrewvc andrewvc merged commit 5ae6d63 into elastic:master Sep 27, 2021
@andrewvc andrewvc deleted the array-syntax branch September 27, 2021 20:03
mergify bot pushed a commit that referenced this pull request Sep 27, 2021
)

This PR greatly improves validation of JSON HTTP response bodies in heartbeat in two different ways:

Introduces a new notion of JSON expressions, using gval as an expression engine. This allows validation of complex data, including the use of JSON Path expressions within. As an example you can write an expression like: $.nodes[?(@name == "foo"][2].message == "hello" to traverse a JSON object containing a nodes key with nested objects, find all elements named "foo", select the third one, then see if its' message attribute equals "hello".
Supports handling APIs that return arrays of JSON objects without a top level object root. Previously, we only parsed JSON response that looked like an object, e.g. {"an": "object"}, we now support: [{"one": 1},{"two": 2}].
Deprecates the condition configuration in favor of this new expression syntax. The new syntax is more consistent and powerful, and should be less effort to maintain.
It also splits out the JSON checking code into separate files to cut down on the extreme length of the originals.

Fixes #27283

(cherry picked from commit 5ae6d63)

# Conflicts:
#	go.mod
andrewvc added a commit that referenced this pull request Sep 29, 2021
…ion of JSON arrays (#28137)

* [Heartbeat] Support JSON expressions / validation of JSON arrays (#28073)

This PR greatly improves validation of JSON HTTP response bodies in heartbeat in two different ways:

Introduces a new notion of JSON expressions, using gval as an expression engine. This allows validation of complex data, including the use of JSON Path expressions within. As an example you can write an expression like: $.nodes[?(@name == "foo"][2].message == "hello" to traverse a JSON object containing a nodes key with nested objects, find all elements named "foo", select the third one, then see if its' message attribute equals "hello".
Supports handling APIs that return arrays of JSON objects without a top level object root. Previously, we only parsed JSON response that looked like an object, e.g. {"an": "object"}, we now support: [{"one": 1},{"two": 2}].
Deprecates the condition configuration in favor of this new expression syntax. The new syntax is more consistent and powerful, and should be less effort to maintain.
It also splits out the JSON checking code into separate files to cut down on the extreme length of the originals.

Fixes #27283

(cherry picked from commit 5ae6d63)

# Conflicts:
#	go.mod

* Fix merge conflict

Co-authored-by: Andrew Cholakian <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Icedroid pushed a commit to Icedroid/beats that referenced this pull request Nov 1, 2021
…stic#28073)

This PR greatly improves validation of JSON HTTP response bodies in heartbeat in two different ways:

Introduces a new notion of JSON expressions, using gval as an expression engine. This allows validation of complex data, including the use of JSON Path expressions within. As an example you can write an expression like: $.nodes[?(@name == "foo"][2].message == "hello" to traverse a JSON object containing a nodes key with nested objects, find all elements named "foo", select the third one, then see if its' message attribute equals "hello".
Supports handling APIs that return arrays of JSON objects without a top level object root. Previously, we only parsed JSON response that looked like an object, e.g. {"an": "object"}, we now support: [{"one": 1},{"two": 2}].
Deprecates the condition configuration in favor of this new expression syntax. The new syntax is more consistent and powerful, and should be less effort to maintain.
It also splits out the JSON checking code into separate files to cut down on the extreme length of the originals.

Fixes elastic#27283
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-v7.16.0 Automated backport with mergify enhancement Heartbeat Team:obs-ds-hosted-services Label for the Observability Hosted Services team v7.16.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Heartbeat] Monitor - Add ability for check an array of objects from a JSON payload response
4 participants