Make the email body of my alert easier to read

Hello,

I have created an advanced watcher alert in order to monitor for each of my hosts which transactions have an http status code 500 to 600 . My alert code is the one below:

{
  "trigger": {
    "schedule": {
      "cron": [
        "0 * 0-1 * * ?",
        "0 * 3-22 * * ?",
        "0 15-59 23 * * ?",
        "0 58-59 2 * * ?"
      ]
    }
  },
  "input": {
    "search": {
      "request": {
        "search_type": "query_then_fetch",
        "indices": [
          "apm-*"
        ],
        "rest_total_hits_as_int": true,
        "body": {
          "size": 0,
          "query": {
            "bool": {
              "must_not": {
                "term": {
                  "transaction.name": "TokenEndpoint#postAccessToken"
                }
              },
              "must": [
                {
                  "terms": {
                    "host.hostname": [
                      "sag-prd-cas-025.sag.services",
                      "sag-prd-cas-026.sag.services",
                      "sag-prd-cas-027.sag.services",
                      "sag-prd-cas-028.sag.services",
                      "sag-prd-cas-029.sag.services",
                      "sag-prd-cas-030.sag.services"
                    ]
                  }
                }
              ],
              "filter": [
                {
                  "range": {
                    "@timestamp": {
                      "gte": "now-1m"
                    }
                  }
                },
                {
                  "range": {
                    "http.response.status_code": {
                      "gte": 500,
                      "lte": 600
                    }
                  }
                }
              ]
            }
          },
          "aggs": {
            "hosts": {
              "terms": {
                "field": "host.hostname"
              },
              "aggs": {
                "transactions": {
                  "terms": {
                    "field": "transaction.name"
                  },
                  "aggs": {
                    "status": {
                      "terms": {
                        "field": "http.response.status_code"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": {
      "ctx.payload.hits.total": {
        "gt": 30
      }
    }
  },
  "actions": {
    "send_email": {
      "email": {
        "profile": "standard",
        "to": [
          "alexandros.ananikidis@sag-ag.ch"
        ],
        "subject": "5xx HTTP status code dedected",
        "body": {
          "text": "The Watcher has detected {{ctx.payload.hits.total}} times a 5xx HTTP status code during the last 1 minute.\n\n The detailed results are the following: \n\n {{ctx.payload.aggregations.hosts.buckets}} "
        }
      }
    }
  }
}

The alert works perfectly but the email body that i receive has a terrible structure for someone to read and understand where the http failures occure.

The email that i get has the following body:

The Watcher has detected 121 times a 5xx HTTP status code during the last 1 minute.

The detailed results are the following:

{0={doc_count=119, transactions={doc_count_error_upper_bound=0, sum_other_doc_count=0, buckets=[{doc_count=119, key=ArticlesController#getUpdatedAvailabilities, status={doc_count_error_upper_bound=0, sum_other_doc_count=0, buckets=[{doc_count=119, key=500}]}}]}, key=sag-prd-cas-029.sag.services}, 1={doc_count=2, transactions={doc_count_error_upper_bound=0, sum_other_doc_count=0, buckets=[{doc_count=1, key=ArticleSearchController#searchArticlesByCateIdsAndVehIds, status={doc_count_error_upper_bound=0, sum_other_doc_count=0, buckets=[{doc_count=1, key=500}]}}]}, key=sag-prd-cas-027.sag.services}}

What can i do in order to show that info in a more nice and clear way?

Thank you in advance

watcher allows you to make use of mustache templates to format data https://www.elastic.co/guide/en/x-pack/current/actions-email.html#configuring-email-actions
If you just need to convert data to a proper JSON format, you can leverage built-in formatter "{{#toJson}}ctx.payload{{/toJson}}"

Hello Mikhail,

Thank you for your asnwer.

I have put the command in my email body as you suggested and the code now is like this:

{
  "trigger": {
    "schedule": {
      "cron": [
        "0 * 0-1 * * ?",
        "0 * 3-22 * * ?",
        "0 15-59 23 * * ?",
        "0 58-59 2 * * ?"
      ]
    }
  },
  "input": {
    "search": {
      "request": {
        "search_type": "query_then_fetch",
        "indices": [
          "apm-*"
        ],
        "rest_total_hits_as_int": true,
        "body": {
          "size": 0,
          "query": {
            "bool": {
              "must_not": {
                "term": {
                  "transaction.name": "TokenEndpoint#postAccessToken"
                }
              },
              "must": [
                {
                  "terms": {
                    "host.hostname": [
                      "sag-prd-cas-025.sag.services",
                      "sag-prd-cas-026.sag.services",
                      "sag-prd-cas-027.sag.services",
                      "sag-prd-cas-028.sag.services",
                      "sag-prd-cas-029.sag.services",
                      "sag-prd-cas-030.sag.services"
                    ]
                  }
                }
              ],
              "filter": [
                {
                  "range": {
                    "@timestamp": {
                      "gte": "now-1m"
                    }
                  }
                },
                {
                  "range": {
                    "http.response.status_code": {
                      "gte": 200,
                      "lte": 600
                    }
                  }
                }
              ]
            }
          },
          "aggs": {
            "hosts": {
              "terms": {
                "field": "host.hostname"
              },
              "aggs": {
                "transactions": {
                  "terms": {
                    "field": "transaction.name"
                  },
                  "aggs": {
                    "status": {
                      "terms": {
                        "field": "http.response.status_code"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": {
      "ctx.payload.hits.total": {
        "gt": 30
      }
    }
  },
  "actions": {
    "send_email": {
      "email": {
        "profile": "standard",
        "to": [
          "alexandros.ananikidis@sag-ag.ch"
        ],
        "subject": "5xx HTTP status code dedected",
        "body": {
          "text": "The Watcher has detected {{#toJson}}ctx.payload.hits.total{{/toJson}} times a 5xx HTTP status code during the last 1 minute.\n\n The detailed results are the following: \n\n {{ctx.payload.aggregations.hosts.buckets}} "
        }
      }
    }
  }
}

Nevertheless the output is still very difficult for someone to read as the image shows below:

I would like a solution that will provide an email body that someone will easily understand.
Is there a way?

Hi! What is output if you apply {{#toJson}} to the aggregations?

Hello
When i apply your change the code is like that

{
  "trigger": {
    "schedule": {
      "cron": [
        "0 * 0-1 * * ?",
        "0 * 3-22 * * ?",
        "0 15-59 23 * * ?",
        "0 58-59 2 * * ?"
      ]
    }
  },
  "input": {
    "search": {
      "request": {
        "search_type": "query_then_fetch",
        "indices": [
          "apm-*"
        ],
        "rest_total_hits_as_int": true,
        "body": {
          "size": 0,
          "query": {
            "bool": {
              "must_not": {
                "term": {
                  "transaction.name": "TokenEndpoint#postAccessToken"
                }
              },
              "must": [
                {
                  "terms": {
                    "host.hostname": [
                      "sag-prd-cas-025.sag.services",
                      "sag-prd-cas-026.sag.services",
                      "sag-prd-cas-027.sag.services",
                      "sag-prd-cas-028.sag.services",
                      "sag-prd-cas-029.sag.services",
                      "sag-prd-cas-030.sag.services"
                    ]
                  }
                }
              ],
              "filter": [
                {
                  "range": {
                    "@timestamp": {
                      "gte": "now-1m"
                    }
                  }
                },
                {
                  "range": {
                    "http.response.status_code": {
                      "gte": 200,
                      "lte": 600
                    }
                  }
                }
              ]
            }
          },
          "aggs": {
            "hosts": {
              "terms": {
                "field": "host.hostname"
              },
              "aggs": {
                "transactions": {
                  "terms": {
                    "field": "transaction.name"
                  },
                  "aggs": {
                    "status": {
                      "terms": {
                        "field": "http.response.status_code"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": {
      "ctx.payload.hits.total": {
        "gt": 30
      }
    }
  },
  "actions": {
    "send_email": {
      "email": {
        "profile": "standard",
        "to": [
          "alexandros.ananikidis@sag-ag.ch"
        ],
        "subject": "5xx HTTP status code dedected",
        "body": {
          "text": "The Watcher has detected {{#toJson}}ctx.payload.hits.total{{/toJson}} times a 5xx HTTP status code during the last 1 minute.\n\n The detailed results are the following: \n\n {{#toJson}}ctx.payload.aggregations.hosts.buckets{{/toJson}} "
        }
      }
    }
  }
}

But as the image show nothing changes