Logstash: API analysis using ELK stack

Extracting data through the API is not one of the most common use cases for ELK Stack users, but this situation is very useful for some cases. For example, developers who use rest APIs to wrap their database services might be interested in analyzing this data for business intelligence purposes. In today's article, let's talk about how to use the ELK Stack to analyze a Service API.

For whatever reason, ELK Stack provides some simple ways to integrate with the API. One of these methods is Logstash HTTP poller Enter the plug-in. In the following example, I'll use this plug-in to get some weather data exposed through the public API.

To perform these steps and build your own pipeline for HTTP API analysis in ELK, you need to set up the following:

 

Preparation data

As mentioned above, we use the OpenWeatherMap API to collect current weather data. The dataset includes statistics from 40000 weather stations on existing weather conditions around the world.

The data itself can be provided in JSON, XML or HTML format, but the default format is JSON, which is very suitable for our use case, because we are using elastic search to index data. There are many ways to call data - you can do so by providing the city name (the method we'll use here), City ID, geographic coordinates, or zip code. You can also call multiple cities in specific coordinates.

The following example invokes the weather statistics in a bounding box with longitude and latitude coordinates:

http://api.openweathermap.org/data/2.5/box/city?bbox=12,32,15,37,10&appid=YourAppKey

On top,  bbox Defined as [lon left, lat bottom, lon right, lat top, zoom], that is, it represents a rectangular area. In the above appid, we must fill in our own App Key to work.

The data returned by API provides us with all the statistical information needed to measure the current weather conditions, including temperature, humidity, atmospheric pressure, wind speed and wind direction.

Here is an example:

{"cod":200,"calctime":0.00256473,"cnt":15,"list":[{"id":2563191,"dt":1581912559,"name":"Birkirkara","coord":{"Lon":14.46,"Lat":35.9},"main":{"temp":8,"feels_like":6.94,"temp_min":8,"temp_max":8,"pressure":1028,"humidity":93},"visibility":10000,"wind":{"speed":0.5},"rain":null,"snow":null,"clouds":{"today":1},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2210247,"dt":1581912558,"name":"Tripoli","coord":{"Lon":13.19,"Lat":32.88},"main":{"temp":14.62,"feels_like":12.78,"temp_min":14.62,"temp_max":14.62,"pressure":1027,"sea_level":1027,"grnd_level":1027,"humidity":59},"wind":{"speed":1.53,"deg":42},"rain":null,"snow":null,"clouds":{"today":12},"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}]},{"id":2216885,"dt":1581912558,"name":"Zawiya","coord":{"Lon":12.73,"Lat":32.75},"main":{"temp":10.33,"feels_like":8.14,"temp_min":10.33,"temp_max":10.33,"pressure":1027,"sea_level":1027,"grnd_level":1015,"humidity":77},"wind":{"speed":1.96,"deg":87},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2212771,"dt":1581912558,"name":"Sabratah","coord":{"Lon":12.49,"Lat":32.79},"main":{"temp":14.59,"feels_like":12.27,"temp_min":14.59,"temp_max":14.59,"pressure":1027,"sea_level":1027,"grnd_level":1027,"humidity":57},"wind":{"speed":2.05,"deg":57},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2215163,"dt":1581912558,"name":"Masallatah","coord":{"Lon":14,"Lat":32.62},"main":{"temp":8.75,"feels_like":6.93,"temp_min":8.75,"temp_max":8.75,"pressure":1027,"sea_level":1027,"grnd_level":995,"humidity":77},"wind":{"speed":0.98,"deg":309},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2219905,"dt":1581912558,"name":"Al Khums","coord":{"Lon":14.26,"Lat":32.65},"main":{"temp":12.93,"feels_like":11.96,"temp_min":12.93,"temp_max":12.93,"pressure":1027,"sea_level":1027,"grnd_level":1023,"humidity":71},"wind":{"speed":0.65,"deg":51},"rain":{"3h":0.19},"snow":null,"clouds":{"today":27},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}]},{"id":2208425,"dt":1581912558,"name":"Zuwarah","coord":{"Lon":12.08,"Lat":32.93},"main":{"temp":12.65,"feels_like":10.83,"temp_min":12.65,"temp_max":12.65,"pressure":1027,"sea_level":1027,"grnd_level":1027,"humidity":64},"wind":{"speed":1.3,"deg":63},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2210221,"dt":1581912558,"name":"Tarhuna","coord":{"Lon":13.63,"Lat":32.44},"main":{"temp":7.58,"feels_like":6.11,"temp_min":7.58,"temp_max":7.58,"pressure":1027,"sea_level":1027,"grnd_level":992,"humidity":85},"wind":{"speed":0.56,"deg":142},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2208485,"dt":1581912558,"name":"Zlitan","coord":{"Lon":14.57,"Lat":32.47},"main":{"temp":12.93,"feels_like":11.96,"temp_min":12.93,"temp_max":12.93,"pressure":1027,"sea_level":1027,"grnd_level":1023,"humidity":71},"wind":{"speed":0.65,"deg":51},"rain":{"3h":0.19},"snow":null,"clouds":{"today":27},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}]},{"id":2217362,"dt":1581912558,"name":"Gharyan","coord":{"Lon":13.02,"Lat":32.17},"main":{"temp":5.59,"feels_like":4.01,"temp_min":5.59,"temp_max":5.59,"pressure":1027,"sea_level":1027,"grnd_level":940,"humidity":90},"wind":{"speed":0.4,"deg":209},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2523693,"dt":1581912495,"name":"Pozzallo","coord":{"Lon":14.85,"Lat":36.73},"main":{"temp":5.56,"feels_like":2.34,"temp_min":3.89,"temp_max":7.78,"pressure":1028,"humidity":87},"visibility":10000,"wind":{"speed":2.6,"deg":60},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2524119,"dt":1581912495,"name":"Modica","coord":{"Lon":14.77,"Lat":36.85},"main":{"temp":5.73,"feels_like":2.54,"temp_min":3.89,"temp_max":7.78,"pressure":1028,"humidity":87},"visibility":10000,"wind":{"speed":2.6,"deg":60},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2208791,"dt":1581912558,"name":"Yafran","coord":{"Lon":12.53,"Lat":32.06},"main":{"temp":7.01,"feels_like":5.31,"temp_min":7.01,"temp_max":7.01,"pressure":1027,"sea_level":1027,"grnd_level":959,"humidity":84},"wind":{"speed":0.68,"deg":209},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2523581,"dt":1581912494,"name":"Rosolini","coord":{"Lon":14.95,"Lat":36.82},"main":{"temp":5.32,"feels_like":2.06,"temp_min":3.89,"temp_max":7.78,"pressure":1028,"humidity":87},"visibility":10000,"wind":{"speed":2.6,"deg":60},"rain":null,"snow":null,"clouds":{"today":0},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]},{"id":2523650,"dt":1581912495,"name":"Ragusa","coord":{"Lon":14.72,"Lat":36.93},"main":{"temp":5.52,"feels_like":2.29,"temp_min":3.89,"temp_max":7.78,"pressure":1028,"humidity":87},"visibility":10000,"wind":{"speed":2.6,"deg":60},"rain":null,"snow":null,"clouds":{"today":22},"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}]}]}

 

Configure Logstash

The way to import the data returned through the API into the ELK stack is to use the Logstash http poller Input plug-in, which can aggregate, decode, and ship data from defined endpoint URL s. Let's first create a configuration file called logstash ou openweathermap.conf.

Logstash input

The input part defines the HTTP poller input plug-in - polling URL endpoint, request timeout, CRON based schedule (every 5 minutes) and codec to be used (JSON). The metadata? Target setting is optional and adds some fields to the response about poller performance.

input {
  http_poller {
    urls => {
      url => "http://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=7dbe7341764f682c2242e744c4f167b0&units=metric"
    }
    request_timeout => 60
    schedule => { every => "5m"}
    codec => "json"
    metadata_target => "http_poller_metadata"
  }
}

The API we want to insert here contains the following query parameters after calling the URL:

  • q =London, uk - weather data to be returned to London
  • APPID = – OpenWeatherMap API key
  • units = metrics – convert unit format to Celsius

The url above shows microservices Interface . It returns:

{
  "coord": {
    "lon": -0.13,
    "lat": 51.51
  },
  "weather": [
    {
      "id": 802,
      "main": "Clouds",
      "description": "scattered clouds",
      "icon": "03n"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 6.7,
    "feels_like": 0.46,
    "temp_min": 5,
    "temp_max": 8.33,
    "pressure": 1006,
    "humidity": 65
  },
  "visibility": 10000,
  "wind": {
    "speed": 6.2,
    "deg": 230
  },
  "clouds": {
    "all": 40
  },
  "dt": 1581916140,
  "sys": {
    "type": 1,
    "id": 1414,
    "country": "GB",
    "sunrise": 1581923520,
    "sunset": 1581959845
  },
  "timezone": 0,
  "id": 2643743,
  "name": "London",
  "cod": 200
}

You can use https://jsonformatter.org/json-viewer To format the results returned by the API.

Logstash filter

Because API responses use JSON, Logstash requires little processing or parsing. Therefore, we can now leave the filter section empty.

filter {}

Logstash output

The following part is very direct:

output {
   	elasticsearch {
     	index => "openweather"
     	document_type => "_doc"
     	hosts => "localhost:9200"
	} 
 }

Above, we import the data into the elastic search of localhost:9200, and the index name is openweather.

Based on the above configuration, our final longstash_openweather.conf is as follows:

input {
  http_poller {
    urls => {
      url => "http://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=7dbe7341764f682c2242e744c4f167b0&units=metric"
    }
    request_timeout => 60
    schedule => { every => "1m"}
    codec => "json"
    metadata_target => "http_poller_metadata"
  }
}

filter {}

output {
  stdout {
    codec => rubydebug
    }

  elasticsearch {
     	index => "openweather"
     	document_type => "_doc"
     	hosts => "localhost:9200"
  }
}

Start logstash. We run logstash in the installation directory of logstash:

./bin/logstash -f ~/data/logstash_openweather.conf

You will see a new Elasticsearch index created with weather data. Define a new index pattern in Kibana to start the analysis:

 

Analysis data

We can create an index pattern called openweather. You can then view it through Discover:

 

With openweather index pattern, we can create our dashboard:

 

 

489 original articles published, 107 praised, 840000 visitors+
His message board follow

Keywords: JSON ElasticSearch codec REST

Added by etrooper on Mon, 17 Feb 2020 12:21:37 +0200