Skip to content

Instantly share code, notes, and snippets.

@pranavraja
Last active August 29, 2015 14:14
Show Gist options
  • Save pranavraja/9938203030ddf11a6473 to your computer and use it in GitHub Desktop.
Save pranavraja/9938203030ddf11a6473 to your computer and use it in GitHub Desktop.
Find when stuff happened in elasticsearch

Suppose you had an elasticsearch query but want to find out the time period during which the query would return results (for example, when tracking a spike in latency/load on a service).

Running esbisect '<query>' will give you the time period (within the last two days) during which the events occured.

e.g. assuming you track events of type http-transaction with a field latencySeconds, running

esbisect 'http://yourelasticsearch.host:9200/_search?q=eventType:http-transaction%20AND%20latencySeconds:{10%20TO%20*}'

Would find the period within the last two days in which the latency spiked above 10 seconds.

Assuming that the event only occured within the last day or two, the printed "First occurence" and "Last occurence" are accurate to within a few seconds.

package main
import (
"encoding/json"
"log"
"net/http"
"os"
"time"
)
func hit(start, end time.Time, query string) (bool, error) {
url := query + "%20AND%20@timestamp:{" + start.Format(time.RFC3339) + "%20TO%20" + end.Format(time.RFC3339) + "}"
log.Printf("esdata: GET %s", url)
res, err := http.Get(url)
if err != nil {
return false, err
}
defer res.Body.Close()
var apiResponse struct {
Hits struct {
Total int
}
}
if err := json.NewDecoder(res.Body).Decode(&apiResponse); err != nil {
return false, err
}
return apiResponse.Hits.Total > 0, nil
}
// Return the first and last occurence of a match for the provided query
// in the last two days, provided that it occured within 2 days ago to now
func bisect(query string) (first, last time.Time, err error) {
now := time.Now().UTC()
twoDaysAgo := now.Add(-48 * time.Hour)
first = now.Add(-24 * time.Hour)
last = first
precision := 12 * time.Hour
iterations := 10
for i := 0; i < iterations; i++ {
ok, err := hit(twoDaysAgo, first, query)
if err != nil {
return first, last, err
}
if ok {
first = first.Add(-1 * precision)
} else {
first = first.Add(precision)
}
ok, err = hit(last, now, query)
if err != nil {
return first, last, err
}
if ok {
last = last.Add(precision)
} else {
last = last.Add(-1 * precision)
}
precision /= 2
}
return first, last, nil
}
func main() {
if len(os.Args) <= 1 {
println("Usage: esbisect '<query>'")
os.Exit(1)
}
first, last, err := bisect(os.Args[1])
if err != nil {
log.Fatal(err)
}
log.Printf("First occurence: %s, Last occurence: %s", first.Format(time.RFC3339), last.Format(time.RFC3339))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment