prometheus-community / json_exporter

A prometheus exporter which scrapes remote JSON by JSONPath
Apache License 2.0
632 stars 195 forks source link

Jsonpath filter comparing numbers #293

Open iperovic opened 7 months ago

iperovic commented 7 months ago

If I change this in your example config:

$ git diff examples/config.yml
diff --git a/examples/config.yml b/examples/config.yml
index 9d0745c..a04a068 100644
--- a/examples/config.yml
+++ b/examples/config.yml
@@ -22,7 +22,7 @@ modules:
     - name: example_value
       type: object
       help: Example of sub-level value scrapes from a json
-      path: '{.values[?(@.state == "ACTIVE")]}'
+      path: '{.values[?(@.count == 2)]}'
       labels:
         environment: beta # static label
         id: '{.id}'       # dynamic label

I expect only the element with count value of 2 retrieved. I proceed starting the setup as described under "Example Usage" in your README.md. When I run curl, I get:

$ curl "http://localhost:7979/probe?module=default&target=http://localhost:8000/examples/data.json"
# HELP example_global_value Example of a top-level global value scrape in the json
# TYPE example_global_value untyped
example_global_value{environment="beta",location="planet-mars"} 1234
# HELP example_timestamped_value_count Example of a timestamped value scrape in the json
# TYPE example_timestamped_value_count untyped
example_timestamped_value_count{environment="beta"} 2

Meanwhile, these errors are logged on the console running json_exporter:

$ ./json_exporter --config.file examples/config.yml
ts=2024-02-28T16:00:13.569Z caller=main.go:57 level=info msg="Starting json_exporter" version="(version=0.6.0, branch=HEAD, revision=2f9b473b83faf29da4050d12e5d510059b7475bb)"
ts=2024-02-28T16:00:13.569Z caller=main.go:58 level=info msg="Build context" build="(go=go1.20.4, platform=linux/amd64, user=root@51ced0102bcd, date=20230606-02:44:54, tags=netgo static_build)"
ts=2024-02-28T16:00:13.569Z caller=main.go:60 level=info msg="Loading config file" file=examples/config.yml
ts=2024-02-28T16:00:13.570Z caller=main.go:70 level=info msg="Loaded config file" config="{\"Modules\":{\"animals\":{\"Headers\":null,\"Metrics\":[{\"Name\":\"animal\",\"Path\":\"{ [*] }\",\"Labels\":{\"name\":\"{ .noun }\",\"predator\":\"{ .predator }\"},\"Type\":\"object\",\"ValueType\":\"untyped\",\"EpochTimestamp\":\"\",\"Help\":\"Example of top-level lists in a separate module\",\"Values\":{\"population\":\"{ .population }\"}}],\"HTTPClientConfig\":{\"tls_config\":{\"insecure_skip_verify\":false},\"follow_redirects\":false,\"enable_http2\":false,\"proxy_url\":null},\"Body\":{\"Content\":\"\",\"Templatize\":false},\"ValidStatusCodes\":null},\"default\":{\"Headers\":{\"X-Dummy\":\"my-test-header\"},\"Metrics\":[{\"Name\":\"example_global_value\",\"Path\":\"{ .counter }\",\"Labels\":{\"environment\":\"beta\",\"location\":\"planet-{.location}\"},\"Type\":\"value\",\"ValueType\":\"untyped\",\"EpochTimestamp\":\"\",\"Help\":\"Example of a top-level global value scrape in the json\",\"Values\":null},{\"Name\":\"example_timestamped_value\",\"Path\":\"{ .values[?(@.state == \\\"INACTIVE\\\")] }\",\"Labels\":{\"environment\":\"beta\"},\"Type\":\"object\",\"ValueType\":\"untyped\",\"EpochTimestamp\":\"\",\"Help\":\"Example of a timestamped value scrape in the json\",\"Values\":{\"count\":\"{.count}\"}},{\"Name\":\"example_value\",\"Path\":\"{.values[?(@.count == 2)]}\",\"Labels\":{\"environment\":\"beta\",\"id\":\"{.id}\"},\"Type\":\"object\",\"ValueType\":\"untyped\",\"EpochTimestamp\":\"\",\"Help\":\"Example of sub-level value scrapes from a json\",\"Values\":{\"active\":\"1\",\"boolean\":\"{.some_boolean}\",\"count\":\"{.count}\"}}],\"HTTPClientConfig\":{\"tls_config\":{\"insecure_skip_verify\":false},\"follow_redirects\":false,\"enable_http2\":false,\"proxy_url\":null},\"Body\":{\"Content\":\"\",\"Templatize\":false},\"ValidStatusCodes\":null}}}"
ts=2024-02-28T16:00:13.570Z caller=tls_config.go:274 level=info msg="Listening on" address=[::]:7979
ts=2024-02-28T16:00:13.570Z caller=tls_config.go:277 level=info msg="TLS is disabled." http2=false address=[::]:7979
ts=2024-02-28T16:00:17.863Z caller=collector.go:139 level=error msg="Failed to execute jsonpath" err="incompatible types for comparison" path="{.values[?(@.count == 2)]}" data="{\n    \"counter\": 1234,\n    \"timestamp\": 1657568506,\n    \"values\": [\n        {\n            \"id\": \"id-A\",\n            \"count\": 1,\n            \"some_boolean\": true,\n            \"state\": \"ACTIVE\"\n        },\n        {\n            \"id\": \"id-B\",\n            \"count\": 2,\n            \"some_boolean\": true,\n            \"state\": \"INACTIVE\"\n        },\n        {\n            \"id\": \"id-C\",\n            \"count\": 3,\n            \"some_boolean\": false,\n            \"state\": \"ACTIVE\"\n        }\n    ],\n    \"location\": \"mars\"\n}\n"
ts=2024-02-28T16:00:17.863Z caller=collector.go:76 level=error msg="Failed to extract json objects for metric" err="incompatible types for comparison" metric="Desc{fqName: \"example_value_active\", help: \"Example of sub-level value scrapes from a json\", constLabels: {}, variableLabels: [{id <nil>} {environment <nil>}]}"
ts=2024-02-28T16:00:17.863Z caller=collector.go:139 level=error msg="Failed to execute jsonpath" err="incompatible types for comparison" path="{.values[?(@.count == 2)]}" data="{\n    \"counter\": 1234,\n    \"timestamp\": 1657568506,\n    \"values\": [\n        {\n            \"id\": \"id-A\",\n            \"count\": 1,\n            \"some_boolean\": true,\n            \"state\": \"ACTIVE\"\n        },\n        {\n            \"id\": \"id-B\",\n            \"count\": 2,\n            \"some_boolean\": true,\n            \"state\": \"INACTIVE\"\n        },\n        {\n            \"id\": \"id-C\",\n            \"count\": 3,\n            \"some_boolean\": false,\n            \"state\": \"ACTIVE\"\n        }\n    ],\n    \"location\": \"mars\"\n}\n"
ts=2024-02-28T16:00:17.863Z caller=collector.go:76 level=error msg="Failed to extract json objects for metric" err="incompatible types for comparison" metric="Desc{fqName: \"example_value_count\", help: \"Example of sub-level value scrapes from a json\", constLabels: {}, variableLabels: [{environment <nil>} {id <nil>}]}"
ts=2024-02-28T16:00:17.864Z caller=collector.go:139 level=error msg="Failed to execute jsonpath" err="incompatible types for comparison" path="{.values[?(@.count == 2)]}" data="{\n    \"counter\": 1234,\n    \"timestamp\": 1657568506,\n    \"values\": [\n        {\n            \"id\": \"id-A\",\n            \"count\": 1,\n            \"some_boolean\": true,\n            \"state\": \"ACTIVE\"\n        },\n        {\n            \"id\": \"id-B\",\n            \"count\": 2,\n            \"some_boolean\": true,\n            \"state\": \"INACTIVE\"\n        },\n        {\n            \"id\": \"id-C\",\n            \"count\": 3,\n            \"some_boolean\": false,\n            \"state\": \"ACTIVE\"\n        }\n    ],\n    \"location\": \"mars\"\n}\n"
ts=2024-02-28T16:00:17.864Z caller=collector.go:76 level=error msg="Failed to extract json objects for metric" err="incompatible types for comparison" metric="Desc{fqName: \"example_value_boolean\", help: \"Example of sub-level value scrapes from a json\", constLabels: {}, variableLabels: [{environment <nil>} {id <nil>}]}"

Am I using the jsonpath filter the wrong way? Or is this some limitation of the jsonpath library implementation?
Can you suggest a workaround to filter based on numeric value in the original json?

R-Studio commented 4 months ago

Same issue here.