[[customizing-watches]]
== Customizing Watches

Now that you've seen how to set up simple watches to <<watch-log-data, watch your log data>>
and <<watch-cluster-status, monitor your cluster health>>, let's take a closer look at how 
you can customize a watch by modifying its <<changing-inputs, inputs>>,
<<changing-conditions, conditions>>, <<using-transforms, transforms>>, and
<<customizing-actions, actions>>.

[[changing-inputs]]
=== Changing Inputs
Watcher supports three types of inputs <<loading-static-data, simple>>,
<<loading-search-results, search>>, and <<loading-http-data, http>>.

[[loading-static-data]]
==== Loading Static Data with the Simple Input

To load static data into the watch payload for testing purposes, you can use the
<<input-simple, simple>> input. For example, the following input stores three fields in the
payload:

[source,js]
-------------------------------------------------- 
"input" : { 
  "simple" : {
    "color"  : "red",
    "status" : "error",
    "count"  : 3
  } 
}
--------------------------------------------------

[[loading-search-results]]
==== Loading Search Results with the Search Input

To load search results into the watch payload, you use the `search` input. In addition to simple
match queries like the one shown in the <<watch-log-data, Getting Started>> guide, you can use the
full Elasticsearch query language. 

A <<input-search, search>> input contains a `request` object that specifies the indices you want to
search, the {ref}/search-request-search-type.html[search type], and the search request body. The
`body` field of a search input is the same as the body of an Elasticsearch `_search` request.

NOTE:   The default search type is {ref}/search-request-search-type.html#count[`count`], which 
        differs from the Elasticsearch default of `query_then_fetch`. 

 
////////////
For example, the following search input searches the watch history indices for watch records whose execution_duration exceeded 2.5 seconds.

[source,js]
-------------------------------------------------- 
"input" : {
    "search": {
      "request": {
        "indices": [
          ".watch_history*"
        ],
        "body": {
          "size" : 0,
          "query" : {
            "filtered": {
              "query" : {
                "match_all" : { }
              },
              "filter": {
                "range": {
                  "result.execution_duration": {
                    "gt": 2500
                  }
                }
              }
            }
          }
        }
      }
    }
  },
--------------------------------------------------
////////////

[[loading-http-data]]
==== Loading a Webserver Response with the HTTP Input

To query a webserver and load the response into the watch payload, you use the `http` input. In
addition to calling Elasticsearch APIs as shown in the <<watch-cluster-status, Getting Started>>
guide, you can submit requests to any webserver that returns a response in JSON. 

////////////
For example, the following input gets excerpts for all of the questions posted to Stack Overflow
during the month of May, 2015 that were tagged with `elasticsearch`. 

[source,js]
-------------------------------------------------- 
"input" : { 
  "http" : {
    "request" : {
      "host" : "api.stackexchange.com",
      "port" : 80,
      "path" : "https://api.stackexchange.com/2.2/search/excerpts",
      "params" : { <1>
        "fromdate" : 1430438400,
        "todate" : 1433030400,
        "order" : "desc",
        "sort" : "activity",
        "tagged" : "elasticsearch",
        "site" : "stackoverflow"
      } 
    }
  } 
}
-------------------------------------------------- 
      
<1> The query string parameters are passed to the server using a `params` field, they are not
    included as part of the path.
////////////    

[[changing-conditions]]
=== Changing Conditions

Watcher supports four types of conditions <<condition-always, always>>, <<condition-never, never>>, 
<<condition-compare, compare>>,  and <<condition-script, script>>.

The first two are pretty self-explanatory--they are shortcuts for setting a watch's condition to
`true` or `false`. 

The `compare` condition enables you to perform simple comparisons against values in the Watch
payload. While you can also do this with a `script` condition, with `compare` you can define
inline comparisons without having to enable dynamic scripting. You can use the `script` condition 
to perform more complex evaluations of the data in the watch payload. 

For example, the following compare condition checks to see if the 'search' input returned any
hits:

[source,js]
-------------------------------------------------- 
"condition" : {
    "compare" : { "ctx.payload.hits.total" : { "gt" : 0 }}
  },
-------------------------------------------------- 

////////////
The following script condition checks Stack Overflow excerpts loaded by an 'http' input to see if
there are unanswered questions that have a question_score of 3 or higher.

[source,js]
-------------------------------------------------- 
"condition" : {
    "script" : "def items = ctx.payload.items; def createResult = {if (it.question_score.value >= 3 && it.has_accepted_answer.value == false) {return true}}; items.each(createResult)"
  }
-------------------------------------------------- 
////////////

[[using-transforms]]
=== Using Transforms

Watcher supports three types of transforms <<transform-search, search>>,
<<transform-script, script>> and <<transform-chain, chain>>. A `search` transform replaces the
existing payload with the results of a new search request. You can use `script` transforms to
modify the existing payload. A `chain` transform enables you to perform a series of `search` and
`script` transforms.

////////////

For example, the following chain transform performs a 'query_then_fetch' search to load the source
of the watch records that have an 'execution_duration' of more than 2.5 seconds. A script transform
then extracts selected information from the search results and updates the watch payload.

[source,js]
-------------------------------------------------- 
"transform" : {
  "chain" : [ 
    {
      "search" : {  
        "search_type" : "query_then_fetch",
        "indices" : [ ".watch_history*" ],
        "body" : {
          "query" : {
            "filtered": {
              "query" : {
                "match_all" : { }
              },
              "filter": {
              "range": {
                "result.execution_duration": {
                  "gt": 2500
                  }
                }
              }
            }
          }
        }
      }
    },
    {
      "script" : "def records = ctx.payload.hits.hits; def result = [ ]; def createResult = {if (!it) { result = '0'} else {result << it._source.result.execution_duration.value}}; records.each(createResult); return result"  
    }
  ]
},
-------------------------------------------------- 

////////////

[[customizing-actions]]
=== Customizing Actions

Watcher supports four types of actions <<actions-email, email>>, 
<<actions-index, index>>, <<actions-logging, logging>>, and <<actions-webhook, webhook>>. 

To use the `email` action, you need to <<email-services, configure an email account>> in 
`elasticsearch.yml` that Watcher can use to send email. Your custom email messages can be
plain text or styled using HTML. You can include information from the watch payload using
<<templates, templates>>, as well as attach the entire watch payload to the message. For example,
the following email action uses a template in the subject line and attaches the payload data to the 
message.

[source,js]
-------------------------------------------------- 
"actions" : {
  "send_email" : {
    "email" : {
      "to" : "<username>@<domainname>",
      "subject" : "Watcher Notification",
      "body" : "{{ctx.payload.hits.total}} watches took more than 2.5 seconds to execute.",
      "attach_data" : true
    }
  }
}
-------------------------------------------------- 

The `index` action enables you to load data from the watch payload into an Elasticsearch index. The
entire payload can be indexed as a single document, or you can use a transform to populate a 
`_doc` field with an array of objects that are indexed as separate documents. 

////////////
For example, 
the following index action indexes each of the excerpts extracted from Stack Overflow as a separate 
document.

[source,js]
-------------------------------------------------- 
"actions" : {
  "index_payload" : { 
    "transform": { 
      ...
     },
    "index" : {
      "index" : "questions", 
      "doc_type" : "stackoverflow-excerpt" 
    }
  }
}
-------------------------------------------------- 

////////////

The `logging` action enables you to add entries to the Elasticsearch logs, which is useful
during development and testing. For example, the following logging action logs the number
of watches that took longer than 2.5 seconds to run.

[source,js]
-------------------------------------------------- 
"actions" : {
  "log" : { 
    "logging" : {
      "text" : "{{ctx.payload.hits.total}} watches took more than 2.5 seconds to execute" 
    }
  }
}
--------------------------------------------------

The `webhook` action enables you to submit a request to any external webservice. For example,
the following webhook action creates a Pagerduty trigger event.

[source,js]
-------------------------------------------------- 
"actions" : {
  "send_trigger" : { 
    "throttle_period" : "5m", 
    "webhook" : {
      "method" : "POST", 
      "host" : "https://events.pagerduty.com", 
      "port" : 443, 
      "path": ":/generic/2010-04-15/create_event.json}", 
      "body" : "{    
        \"service_key\": \"e93facc04764012d7bfb002500d5d1a6\",
        \"incident_key\": \"long_watches\",
        \"event_type\": \"trigger\",
        \"description\": \"{{ctx.payload.hits.total}} watches took more than 2.5 seconds to execute\",
        \"client\": \"Watcher\"      
      }" 
      "headers": {"Content-type": "application/json"}
    }
  }
}
--------------------------------------------------
