{"id":855,"date":"2016-11-02T19:38:24","date_gmt":"2016-11-02T19:38:24","guid":{"rendered":"http:\/\/tpodolak.com\/blog\/?p=855"},"modified":"2016-11-02T20:03:14","modified_gmt":"2016-11-02T20:03:14","slug":"getting-started-elastic-stack","status":"publish","type":"post","link":"https:\/\/tpodolak.com\/blog\/2016\/11\/02\/getting-started-elastic-stack\/","title":{"rendered":"Getting started with Elastic Stack"},"content":{"rendered":"<h3>1. Introduction<\/h3>\n<p>In one of my previous post I&#8217;ve shown how to improve logging in an application by tracking the flow of incoming requests. Now it is time to show the basics of <i>Elastic stack<\/i> to make searching across multiple log files\/sources a piece of cake. <i>Elastic stack<\/i> (previously called <i>ELK stack<\/i>) is set of three tools which allows you to parse (<i>Logstash<\/i>), query (<i>Elasticsearch<\/i>) and visualize (<i>Kibana<\/i>) logs with ease. <\/p>\n<h3>2. Installation<\/h3>\n<p>First of all (as usual) we have to get the tools, so go to <a href=\"https:\/\/www.elastic.co\/downloads\">elastic.co<\/a> and download apps mentioned before.<br \/>\nThese are stand-alone applications so no installation is required. The only requirement is to have <i>JAVA_HOME<\/i> system variable pointing to your java directory. In my case, this looks as follows<\/p>\n<pre lang=\"bash\">\r\nC:\\Program Files\\Java\\jre1.8.0_91\\\r\n<\/pre>\n<h3>3. Elasticsearch<\/h3>\n<p>Once all three applications are downloaded we can run <i>Elasticsearch<\/i> (as there is not additional configuration needed for basic usage) instance via an <i>elasticsearch.bat<\/i> file.<br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ElasticSearchWeb-1.png\" rel=\"attachment wp-att-867\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ElasticSearchWeb-1.png\" alt=\"elasticsearchweb\" width=\"367\" class=\"aligncenter size-full wp-image-867\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ElasticSearchWeb-1.png 367w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ElasticSearchWeb-1-150x140.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ElasticSearchWeb-1-300x280.png 300w\" sizes=\"(max-width: 367px) 100vw, 367px\" \/><\/a><\/p>\n<h3>4. Logstash<\/h3>\n<p>Having our <i>Elasticsearch<\/i> instance up and running, now it is time configure <i>Logstash<\/i> so that it will be able to parse logs.<br \/>\nConfiguration provided in next sections will be able to parse logs with the following format<\/p>\n<pre lang=\"bash\">\r\nTimeStamp=2016-07-20 21:22:46.0079 CorrelationId=dc665fe7-9734-456a-92ba-3e1b522f5fd4 Level=INFO Message=About to start GET \/ request\r\n<\/pre>\n<h4>4.1. Configuration<\/h4>\n<p><i>Logstash<\/i> configuration is done via config file in specific format. You can read about that <a href=\"https:\/\/www.elastic.co\/guide\/en\/logstash\/current\/configuration-file-structure.html\"> here<\/a><br \/>\nThe very first step is to define input and output sections<\/p>\n<pre lang=\"javascript\">\r\ninput {\r\n    file {\r\n        path => [\"C:\/logs\/*.log\"]\r\n        start_position => beginning\r\n    }\r\n}\r\noutput {\r\n    elasticsearch {\r\n        hosts => \"localhost:9200\"\r\n    }\r\n    stdout {}\r\n}\r\n<\/pre>\n<p>As you can see the logs will be read from <i>C:\\logs<\/i> directory and parsed content will be pushed to <i>Elasticsearch<\/i> instance and to the console output.<br \/>\nWe can verify correctness of configuration calling<\/p>\n<pre lang=\"bash\">\r\nlogstash.bat -f  \"Path\\To\\Config\\File.conf\" -t\r\n<\/pre>\n<p><a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ConfigurationTest.png\" rel=\"attachment wp-att-856\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ConfigurationTest.png\" alt=\"configurationtest\" width=\"899\" class=\"aligncenter size-full wp-image-856\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ConfigurationTest.png 899w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ConfigurationTest-150x36.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/ConfigurationTest-300x72.png 300w\" sizes=\"(max-width: 899px) 100vw, 899px\" \/><\/a><br \/>\nIf you are making your config file for the first time it is good idea to add additional properties to the <i>file <\/i>section<\/p>\n<pre lang=\"javascript\">\r\nignore_older => 0\r\nsincedb_path => \"NUL\"\r\n<\/pre>\n<p>This will force <i>Logstash<\/i> to reparse entire file when restarted and will also make sure that older files are not ignored (by default files modified more than 24 hours ago are ignored).<\/p>\n<p>At this point, <i>Logstash<\/i> can read the log file but it doesn\u2019t do anything special with it.  Next step is to configure a pattern which will be used for log parsing. <i>Logstash<\/i> uses <i>grok<\/i> for defining the patterns. Long story short it is kind of a regex which can use predefined patterns. The easiest way to play around with it is to use <a href=\"http:\/\/grokconstructor.appspot.com\/\">grokconstructor<\/a>, for list of ready to use patterns take a look at <a href=\"https:\/\/www.elastic.co\/guide\/en\/logstash\/current\/plugins-filters-grok.html\">this <\/a><\/p>\n<p>For parsing logs shown in previous section I&#8217;ve ended up with this grok pattern<\/p>\n<pre lang=\"bash\">\r\nTimeStamp=%{TIMESTAMP_ISO8601:logdate} CorrelationId=%{UUID:correlationId} Level=%{LOGLEVEL:logLevel} Message=%{GREEDYDATA:logMessage}\r\n<\/pre>\n<p>Notice that you are able to give aliases for particular fields, for instance<\/p>\n<pre lag=\"bash\">\r\nTimeStamp=%{TIMESTAMP_ISO8601:logdate} \r\n<\/pre>\n<p>means that everything that matches <I>TimeStamp=%{TIMESTAMP_ISO8601}<\/i> will be stored in <i>logdate<\/i> field.<br \/>\nHaving defined our pattern, now we can add it to the config file. After modifications, it looks as follows<\/p>\n<pre lang=\"javascript\">\r\ninput {\r\n    file {\r\n        path => [\"C:\/logs\/*.log\"]\r\n        start_position => beginning\r\n    }\r\n}\r\nfilter {\r\n    grok {\r\n        match => { \"message\" => \"TimeStamp=%{TIMESTAMP_ISO8601:logdate} CorrelationId=%{UUID:correlationId} Level=%{LOGLEVEL:logLevel} Message=%{GREEDYDATA:logMessage}\" }\r\n    }\r\n}\r\noutput {\r\n    elasticsearch {\r\n        hosts => \"localhost:9200\"\r\n    }\r\n    stdout {}\r\n}\r\n<\/pre>\n<p>Once we run this config and start querying elastic search for list of all indices via<\/p>\n<pre lang=\"bash\">\r\nhttp:\/\/localhost:9200\/_cat\/indices?v\r\n<\/pre>\n<p>we will see that our logs were parsed and stored in index called <i>logstash-2016.10.30<\/i><br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/indices.png\" rel=\"attachment wp-att-860\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/indices.png\" alt=\"indices\" width=\"872\"  class=\"aligncenter size-full wp-image-860\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/indices.png 872w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/indices-150x28.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/indices-300x56.png 300w\" sizes=\"(max-width: 872px) 100vw, 872px\" \/><\/a><br \/>\nIf we now go to <\/p>\n<pre lang=\"bash\">\r\nhttp:\/\/localhost:9200\/logstash-2016.10.30\r\n<\/pre>\n<p>we will be able to see index information<br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/IndexInfo-1.png\" rel=\"attachment wp-att-875\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/IndexInfo-1.png\" alt=\"indexinfo\" width=\"443\" class=\"aligncenter size-full wp-image-875\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/IndexInfo-1.png 443w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/IndexInfo-1-150x110.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/IndexInfo-1-300x219.png 300w\" sizes=\"(max-width: 443px) 100vw, 443px\" \/><\/a><\/p>\n<h4>4.2. Fixing the date fields <\/h4>\n<p>At this moment there are two main problems with our configuration. First of all, the indices are created based on read time from file. Second of all our <i>logdate<\/i> field is treated as string.<br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasstring.png\" rel=\"attachment wp-att-865\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasstring.png\" alt=\"logdateasstring\" width=\"443\" class=\"aligncenter size-full wp-image-865\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasstring.png 482w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasstring-150x90.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasstring-300x179.png 300w\" sizes=\"(max-width: 482px) 100vw, 482px\" \/><\/a><br \/>\nBy default <i>Logstash<\/i> creates indices based on read time of the source. However in my opinion it is better to create index names based on time given event occurred.<br \/>\nIn order to do that, we have to tell the <i>Logstash<\/i> which field is responsible for holding timestamp. In my case, this field is called <i>logdate<\/i>. All we have to do is to map this field into <i<@timestamp<\/i> field via date filter<\/p>\n<pre lang=\"javascript\">\r\ndate {\r\n        match => [ \"logdate\", \"yyyy-MM-dd HH:mm:ss.SSSS\" ]\r\n}\r\n<\/pre>\n<p>As you can see first argument is a filed name and rest of the arguments (you can specify more) are just date time formats. By default date filter maps a field from the <i>match<\/i> property into <i>@timestamp<\/i> field. So the config above equals this one<\/p>\n<pre lang=\"javascript\">\r\ndate {\r\n        match => [ \"logdate\", \"yyyy-MM-dd HH:mm:ss.SSSS\" ]\r\n        target => \"@timestamp\"\r\n}\r\n<\/pre>\n<p>If we restart <i>Logstash<\/i> and get the indices, we will see something similar to that<br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/multipleindices.png\" rel=\"attachment wp-att-866\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/multipleindices.png\" alt=\"multipleindices\" width=\"859\" class=\"aligncenter size-full wp-image-866\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/multipleindices.png 859w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/multipleindices-150x34.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/multipleindices-300x68.png 300w\" sizes=\"(max-width: 859px) 100vw, 859px\" \/><\/a><br \/>\nSecond problem can be handled in very similar way. We have to add second date filter and select as target <i>longdate<\/i> field<\/p>\n<pre lang=\"javascript\">\r\ndate {\r\n        match => [ \"logdate\", \"yyyy-MM-dd HH:mm:ss.SSSS\" ]\r\n        target => \"logdate\"\r\n}\r\n<\/pre>\n<p>From now on <i>logdate<\/i> field will be treated as date so we will be able to filter the logs easily with <i>Kibana<\/i><br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasdate.png\" rel=\"attachment wp-att-864\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasdate.png\" alt=\"logdateasdate\" width=\"334\" class=\"aligncenter size-full wp-image-864\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasdate.png 334w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasdate-150x112.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/logdateasdate-300x225.png 300w\" sizes=\"(max-width: 334px) 100vw, 334px\" \/><\/a><\/p>\n<h3>5. Running Kibana<\/h3>\n<p>Having all the configuration in place now we are ready to run <i>Kibana<\/i>. As in previous steps, no installation is needed so just run the <i>Kibana.bat<\/i> file<br \/>\n<a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanastarted.png\" rel=\"attachment wp-att-863\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanastarted.png\" alt=\"kibanastarted\" width=\"901\" class=\"aligncenter size-full wp-image-863\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanastarted.png 901w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanastarted-150x39.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanastarted-300x77.png 300w\" sizes=\"(max-width: 901px) 100vw, 901px\" \/><\/a><br \/>\nand go to <\/p>\n<pre lang=\"bash\">\r\nhttp:\/\/localhost:5601\/\r\n<\/pre>\n<p>If you run the app for the first time you will be asked to configure the indices. You can use the default parameters and just click &#8220;Create&#8221; button.<br \/>\nOnce the indices are setup you can start writing queries against the logs. By default entire message is searched for the search terms, however the real power comes with queries written against specific fields. For example, you can search for any errors in the application with this simple query<\/p>\n<pre lang=\"bash\">\r\nlogLevel: (FATAL OR ERROR)\r\n<\/pre>\n<p>Thanks to date type fields, you can combine this query with date range selector and narrow down time to specific values, just like that<\/p>\n<pre lang=\"bash\">\r\nlogdate:[2016-07-20 TO 2016-10-31] AND logLevel: (FATAL OR ERROR)\r\n<\/pre>\n<p><a href=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanasearchresults-1.png\" rel=\"attachment wp-att-878\"><img decoding=\"async\" src=\"http:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanasearchresults-1.png\" alt=\"kibanasearchresults\" width=\"1381\" class=\"aligncenter size-full wp-image-878\" srcset=\"https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanasearchresults-1.png 1381w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanasearchresults-1-150x71.png 150w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanasearchresults-1-300x143.png 300w, https:\/\/tpodolak.com\/blog\/wp-content\/uploads\/2016\/10\/getting-started-elastic-stack\/kibanasearchresults-1-1024x487.png 1024w\" sizes=\"(max-width: 1381px) 100vw, 1381px\" \/><\/a><br \/>\nThese are just the basic queries you can run in Kibana, for more advanced scenarios please visit <a href=\"https:\/\/www.elastic.co\/guide\/en\/elasticsearch\/reference\/5.0\/query-dsl-query-string-query.html#query-string-syntax\"> website <\/a>. I also strongly encourage you guys to take a look at other feature <i>Elastic stack<\/i> provides. Source code for this post can be found <a href=\"https:\/\/github.com\/tpodolak\/Blog\/tree\/master\/GettingStartedWithElasticStack\">here<\/a><\/p>\n<div>\nPS<br \/>\nConfiguration presented in this post will not be able to parse multiline log entries e.g. exceptions. I will show you how to do it in the next post.\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>1. Introduction In one of my previous post I&#8217;ve shown how to improve logging in an application by tracking the flow of incoming requests. Now it is time to show the basics of Elastic stack to make searching across multiple log files\/sources a piece of cake. Elastic stack (previously called ELK stack) is set of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[309],"tags":[311,312,310],"class_list":["post-855","post","type-post","status-publish","format-standard","hentry","category-elasticstack","tag-elasticsearch","tag-kibana","tag-logstash"],"_links":{"self":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/855","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/comments?post=855"}],"version-history":[{"count":33,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/855\/revisions"}],"predecessor-version":[{"id":923,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/855\/revisions\/923"}],"wp:attachment":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/media?parent=855"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/categories?post=855"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/tags?post=855"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}