Cannot find correct ctx.payload path to use

Hi,

I made this watch but I'm unable to find the right values. The query returns various locations (key) and their usage (value). For each key that exceeds the gte I want to create an alert but I'm struggling to even get compare to look at the right value. I'm not sure what the correct path is. I've tried about every variation I could think of but no joy.

{
  "trigger": {
    "schedule": {
      "interval": "30m"
    }
  },
"input" : {
  "search" : {
    "request" : {
      "indices" : [ "netflow-test-*" ],
      "body" : {
 "size":"0",
	"query": {
		"bool": {
			"filter": {
				"match": {
					"int_wan": "wan1"
				}
			}
		}
	},
    "aggs": {
        "range": {
            "date_range": {
                "field": "@timestamp",
                "format": "YYYY/MM/DD, HH:mm:ss",
                "ranges": [
                    { "from": "now/1M" } 
                ]
            },
    "aggs" : {
        "switch_location" : {
            "terms" : {
                "field" : "location"
            },
            "aggs" : {
            "total_bytes": {
            "sum": {
            "script" : "doc['in_bytes'].value + doc['out_bytes'].value"
         }
       }
      }
     }
    }
   }
 }
}
}
}
},
  "condition": {
    "array_compare": {
      "ctx.payload.aggregations.range.buckets": {
        "path": "total_bytes",  
        "gte": {
        "value": 1000
      }
     }
    }
  },
  "actions": {
    "my-logging-action": {
      "logging": {
        "text": "There are {{ctx.payload.aggregations.range.buckets}} documents in your index. Threshold is 10."
      }
    }
  }
}

Example of the output of the search query

{
  "took": 8,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 17046,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "range": {
      "buckets": [
        {
          "key": "2018/07/182, 00:00:00-*",
          "from": 1530403200000,
          "from_as_string": "2018/07/182, 00:00:00",
          "doc_count": 17046,
          "switch_location": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "locationA",
                "doc_count": 17046,
                "total_bytes": {
                  "value": 140610423
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Output of the simulated watch

    "condition": {
      "type": "array_compare",
      "status": "success",
      "met": false,
      "array_compare": {
        "resolved_values": {
          "ctx.payload.aggregations.range.buckets": [
            {
              "from_as_string": "2018/07/182, 00:00:00",
              "switch_location": {
                "doc_count_error_upper_bound": 0,
                "sum_other_doc_count": 0,
                "buckets": [
                  {
                    "doc_count": 17046,
                    "total_bytes": {
                      "value": 140610423
                    },
                    "key": "locationA"
                  }
                ]
              },
              "doc_count": 17046,
              "from": 1530403200000,
              "key": "2018/07/182, 00:00:00-*"
            }
          ]
        }
      }
    },
    "actions": []
  },
  "messages": []

The indentation in the aggregation in the watch was a bit misleading, the problem is the following: There is more than one array to check for, as your ctx.payload.aggregations.range.buckets and for each element inside of that array there is switch_location.buckets, which then contains the total_bytes.

As you provided the output of a search, we can use the execute watch API to try and get this running without needing your data

PUT _xpack/watcher/watch/_execute
{
  "alternative_input": {
    "took": 8,
    "timed_out": false,
    "_shards": {
      "total": 1,
      "successful": 1,
      "skipped": 0,
      "failed": 0
    },
    "hits": {
      "total": 17046,
      "max_score": 0,
      "hits": []
    },
    "aggregations": {
      "range": {
        "buckets": [
          {
            "key": "2018/07/182, 00:00:00-*",
            "from": 1530403200000,
            "from_as_string": "2018/07/182, 00:00:00",
            "doc_count": 17046,
            "switch_location": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "locationA",
                  "doc_count": 17046,
                  "total_bytes": {
                    "value": 140610423
                  }
                }
              ]
            }
          }
        ]
      }
    }
  },
  "watch": {
    "trigger": {
      "schedule": {
        "interval": "10h"
      }
    },
    "input": {
      "simple": {}
    },
    "condition" : {
      "script" : "return ctx.payload.aggregations.range.buckets.stream().anyMatch(b -> b.switch_location.buckets.stream().anyMatch(b2 -> b2.total_bytes.value> 140610424))"
    },
    "actions": {
      "logme": {
        "logging": {
          "text": "{{ctx.payload}}"
        }
      }
    }
  }
}

hope this helps!

Thanks, that helps to check for a true/false condition. The problem is it doesn't actually do what I want. Maybe I should rephrase the question and ask what a practical way of achieving this would be.

Use case:
I have 300 switches that I'm monitoring. Each switch has a monthly data allowance. If the limit is exceeded I want to send a alert email & report at set intervals (e.g. when usage exceeds 100GB, 150GB and 200GB).

Because I want to send reports I think I must write at least one watcher per switch no matter what. I got only one reporting dashboard so I will need to pass the search query for the location in the URL field because I don't think its possible to apply a filter to reporting from the watch itself.

I can write a watch that gets the data for a single switch and sends the report but I'm struggling to think of a way to throttle the action until A) the next value is reached while B) keeping the number of watches to a minimum.

the one watch per switch approach is definitely the easiest one here, if you want to attach the reporting PDF via email.

You also can add parameters to the report generation (time and query filters), see https://www.elastic.co/guide/en/kibana/6.3/automating-report-generation.html#automating-report-generation

Regarding the mechanism of only sending one report per exceed level. Would it work if you ran the same query with a time offset (like the last 30-60 minutes) and then compare if the threshold was already exceeded then, and if not send the alert?

That could work. That would need some kind of compare in the conditional and a query that returns 2 results (current value and offset value)?

I want to change from SUM to last known value (I have a different index containing total values). The only thing the offset would have to keep in mind there might not be a known value at exactly 60 minutes offset so it should return the last known value 60+ minutes ago.

Okay I think I have the search query part working.

POST /usage_alert_test/_search?size=0
{
  "size": 0,
  "_source": {
    "excludes": []
  },
  "aggs": {
    "usage_current": {
      "top_hits": {
        "_source": "usage",
        "size": 1,
        "sort": [
          {
            "@timestamp": {
              "order": "desc"
            }
          }
        ]
      }
    },
    "usage_offset": {
      "top_hits": {
        "_source": "usage",
        "size": 1,
        "sort": [
          {
            "@timestamp": {
              "order": "asc"
            }
          }
        ]
      }
    }
  },
  "query": {
    "bool": {
      "must": [
        {
    "match": {
      "switch": "switchA"
    }
        },
        {
          "range": {
            "@timestamp": {
              "gte": "now-20h"
            }
          }
        }
      ]
    }
  }
}

And the output

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "usage_current": {
      "hits": {
        "total": 2,
        "max_score": null,
        "hits": [
          {
            "_index": "usage_alert_test",
            "_type": "_doc",
            "_id": "4M0m2WQBd15ZPnoFyt6p",
            "_score": null,
            "_source": {
              "usage": "100"
            },
            "sort": [
              1532610000000
            ]
          }
        ]
      }
    },
    "usage_offset": {
      "hits": {
        "total": 2,
        "max_score": null,
        "hits": [
          {
            "_index": "usage_alert_test",
            "_type": "_doc",
            "_id": "380m2WQBd15ZPnoFst57",
            "_score": null,
            "_source": {
              "usage": "90"
            },
            "sort": [
              1532608200000
            ]
          }
        ]
      }
    }
  }
}

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.