How to integrate your Go service with ELK
Tags: go, elasticsearch, microservices
Published: 2020-05-16 07:03:24

---
title: How to integrate your Go service with ELK
published: true
description: A tutorial on bringing up a go application with the ELK stack
tags: go, elasticsearch, microservice
series: Integrating your Go service with ELK
cover_image: https://i1.wp.com/pmihaylov.com/wp-content/uploads/2020/05/Screenshot-at-May-16-09-48-45.png?w=1352
canonical_url: https://pmihaylov.com/go-service-with-elk
---
<!-- wp:paragraph -->
<p>In my <a href="https://pmihaylov.com/analysing-logs-elk/">last post</a>, I shared how much value the ELK stack could bring for your application in terms of the monitoring capabilities it gives you.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In this post, I will walk you through how to integrate your Go application with ELK, what are the different parts of ELK, how they work and how to create a basic configuration for them.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let's jump straight in, shall we?</p>
<!-- /wp:paragraph -->

<!-- wp:more -->
<!--more-->
<!-- /wp:more -->

<!-- wp:heading -->
<h2>The Starting Point</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>First, make sure you have <strong>docker</strong> and <strong>docker-compose</strong> installed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For <strong>docker</strong>, follow the installation instructions for your platform <a href="https://docs.docker.com/get-docker/">here</a>.<br>For <strong>docker-compose</strong>, follow the installation instructions <a href="https://docs.docker.com/compose/install/">here</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/faf47c44cfc49e20508f0ce7cba822ab.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Currently, the repo simply has a <strong>main.go</strong> file which logs random log lines on certain intervals. Occasionally, it propagates error log lines.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will use this as a backbone to integrate the <strong>go app</strong> with ELK.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Setting Up the ELK Stack</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>ELK stands for <strong>Elasticsearch</strong>, <strong>Logstash</strong> and <strong>Kibana</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>These are three different tools, created by the <a href="https://www.elastic.co/">elastic company</a>, which are typically used together to enable developers &amp; sys admins to monitor production systems based on application or system logs.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>There is one additional component the ELK stack, which is <strong>Beats</strong>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Beats is a collection of small programs which are fine-tuned to gather different kinds of logging data - e.g. from files, from OS system logs, from Windows event logs, etc.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Since ELBK doesn’t sound as fancy as ELK, we still refer to the stack as the ELK stack.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In the following sections, we will explore each of these components separately &amp; install them accordingly.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>What is Elasticsearch?</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Elasticsearch is a NoSQL database which is optimized for storing <strong>structured documents</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This database also has a REST API in order to easily interact with it.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>A structured document is one which structures its metadata into JSON format.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This can be any JSON-serialized object. This can be used, for example, to create a user-facing search bar in your application.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Instead of doing manual &amp; lame string processing of search terms, you can outsource this to elasticsearch which will do a much better job than both of us.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>However, in our use-case, we will use Elasticsearch for storing <strong>structured logs</strong>. A structured log is one, which organizes its contents into a JSON object.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This is an example of an unstructured log:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/9fec4bc423dab0e8c4d6e097a488a46b.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>This is an example of a structured log:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/45a876b407bd3e2cc81c2a0224b0c991.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Using a structured log, you can later index into these keys and analyse bulks of your logs fast &amp; seamlessly. This is exactly what the ELK stack provides.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Elasticsearch, in particular, will store this log line in a way optimized for search &amp; analysis later.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Setting up Elasticsearch</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>To install elasticsearch, first create a <code>docker-compose.yml</code> file in the root of the repo and add this initial yaml:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/72187fd548cd7579be5147de454459d1.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Let’s break this config down.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In docker-compose, we enumerate the services we want to bring up in this manner:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/ab60a8264fb3d756433db5c5aa81922a.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>In this case, we only bring up a single service which is called <strong>elasticsearch</strong>. You can choose any name you like, but this one is the most descriptive, given what it does.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let’s now interpret the elasticsearch service config line by line.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/4eaae9683eafac689bf37a0759a05b2b.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>This means that we are pulling an already setup docker image with the given version.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This enables us to not bother with setting up an image from scratch. Someone has already provided that out of the box, so we are reusing it.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Otherwise, you will have to bother with setting up the environment, installing dependencies, configuring them, installing elasticsearch manually, etc.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>With this line, we are getting all this out of the box.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/b274be0e626ae7b78a0d43fde8b365f0.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>With this line, we are indicating that the local directory <code>./config/elasticsearch.yml</code> will be mounted on <code>/usr/share/elasticsearch/…</code> in the container and it will be read-only (indicated by the <code>ro</code> flag).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The designated folder is where the elasticsearch default config directory resides.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The file <code>./config/elasticsearch.yml</code> is not created yet, but we’ll create it soon.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/68bf2646bf4b04d542c3261e73e41e66.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>This part designates that we will make health checks on the container by running the command:&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/481b7fe55a5285fd47b2fe204a9bfb9c.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>The command will run periodically, every 3s with a 3s timeout.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will do 10 retries in total and if all fail, docker marks this container as <code>unhealthy</code> and notifies dependent containers.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The final part of the configuration maps the container’s internal <code>9200 port</code> to our real <code>9200 port</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/003ab0da25be850af0bd74bc3694b53d.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>This is all we need to add to <code>docker-compose.yml</code> for elasticsearch. Finally, add this configuration in <code>./config/elasticsearch.yml</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/445feee137522f8c294212b86cf39d7f.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>What this configuration means is that we will use <code>single-node discovery</code><strong> </strong>mode.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Typically, elasticsearch runs in a cluster of nodes with masters &amp; slaves in them which have to be configured.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To keep things simple &amp; digestible for this exercise, we will use a single elasticsearch node.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The <code>network.host</code> option indicates that elasticsearch can bind to any network interface.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Starting Elasticsearch</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>To boot up our new container, run <code>docker-compose up</code><strong>.</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If all went well, you should start seeing the elasticsearch logs after a while and the container should not show any error lines or anything pointing to an issue:</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://lh5.googleusercontent.com/YlB34MO1fHfATM61oP4zNwWrhyqh_9LACK7qcbKWLX8mmUyhb0Et5l4TVpTtj3_yW7g57dZSO-1vjABHYHrEFWGXIX8FTQp9dlfx-AufKwUxZzvMph6rsA7OaWMFZgiv1vXtQhS7" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>At this point, have in mind that there might be some issues which might pop-up.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Here is a reference to common issues on elasticsearch startup:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><a href="https://github.com/laradock/laradock/issues/1699">elasticsearch exit code 78</a><br><a href="https://github.com/10up/wp-local-docker/issues/6">elasticsearch exit code 137</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If all went went, you can continue with the next component in our stack - <strong>logstash</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>What is Logstash?</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Logstash is a component which stands between elasticsearch &amp; applications and does several things:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Filtering input documents based on some criteria (e.g. ignore all <strong>DEBUG </strong>log lines)</li><li>Adding extra metadata to the input log lines (e.g. ip, location info, timestamp, etc.)</li><li>Sanitizing the log lines if needed (e.g. turning unstructured logs into structured ones)</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>In reality, you can interact with elasticsearch directly, but logstash is typically used as a helpful intermediary to save yourself some work on the application side.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Setting up Logstash</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Add another service to your <strong>docker-compose.yml</strong> file:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/5c438f4e3c3bf661c8fd763c8b2587f1.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>This config section is simpler than the previous one.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>First, we use the standard logstash docker image as a baseline.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>As before, we are mounting the <code>./config/logstash.conf</code> file into <strong>logstash</strong>’s default config location.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Finally, the <strong>depends_on</strong> section indicates that this service should only boot up when the elasticsearch service is up and healthy.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Otherwise, the container won’t start at all.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Next up, add this logstash configuration in <code>./config/logstash.conf</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/c05dab9add036a9c5b92a81a2b0b4d37.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>The logstash configuration typically has three sections - <strong>input</strong>, <strong>filter</strong> &amp; <strong>output</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The <strong>input</strong> section specifies where logstash accepts data from. It has a built-in plugin called <strong>beats</strong>, which automatically integrates with beats applications, such as filebeat, which we’ll use later.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Here, we indicate that we’ll accept input from beats applications on <code>port 5044</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In the <code>filter</code> section, you can add any custom filters or mappings (e.g. transforming one input field to another in a custom format).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Here, we only specify that the source structured log will come from the <strong>message</strong> field, which is the default key where <strong>filebeat</strong> stores the actual application log.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This will enable us to index the custom application keys in our log, not only the ones plugged in by <strong>filebeat</strong> and/or <strong>logstash</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The final <strong>output</strong> section specifies where the filtered logs should be forwarded to.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>It can by default connect to <strong>elasticsearch</strong> (as we’ve done here) and integrate with it via its <code>default port 9200</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you change <strong>elasticsearch</strong>’s default port to something else, you will have to modify this section as well.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now run both elasticsearch and logstash and make sure they both boot up without any issues:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/efc7ee86da89407ac7f553c2bd4cfda0.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>If everything goes well, your output should look like this:</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://lh4.googleusercontent.com/YO80LRNEi9q-kJRQ5QfUj-F6_3Z2LhewJyHXtA9LMosz34Xok_FGStrOWqsHdbEGPSge-A_Lw_hA-sj6aUcVIYLKCZT6dU2DFxT9-UWDUdV_Bib1-aCzvr0VbMup1QfLoEAkpMJJ" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:heading {"level":3} -->
<h3>What is filebeat?</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p><strong>Filebeat</strong> is a beats application (there are more), which is responsible for monitoring changes in log files and forwarding them to logstash.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Without filebeat, you would have to manage your application’s integration with <strong>logstash</strong> yourself.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The way it works is - you specify a path to your logs which it should monitor &amp; it will handle propagating those logs on regular intervals to logstash.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Setting up filebeat &amp; your Go application</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In this section, we will add filebeat &amp; the Go application as docker containers.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Add this to your <code>docker-compose.yml</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/e7054a23e9445eb85ec8781a1818a099.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>The bulk of the new sections are pretty similar to what we already did for the rest of our services.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Both new services depend on <strong>elasticsearch</strong> being healthy, both depend on their respective baseline docker images.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The differences are in the <code>volumes</code> sections.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For our go app, we’ve mounted the current directory in a subdirectory of the container’s <code>GOPATH</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The logs, on the other hand, have been mounted in both containers.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Our Go application will use that directory to output its logging info.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The <strong>filebeat</strong> service will use it to monitor changes in the logging info.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In addition to that, we’ve mounted the <strong>filebeat</strong> configuration in the standard config directory on the container.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For our Go app, we’ve also specified that once the container is setup, we’ll run our application via the command:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/193ac073b3f95d8587a8ee3c0f4d3068.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Now, add this to <code>config/filebeat.yml</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/acada1a25e43073833b07f3c725ad683.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>This configuration specifies that the service will listen for changes to all log files in <code>/logs</code>. Additionally, It will output any new logging info to logstash via <code>port 5044</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We also whitelisted that port in our <strong>logstash</strong> service config for inputs from beats applications.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>What is Kibana?</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The final piece of the setup is <strong>Kibana</strong>. It is a front-end for analysing the data stored in Elasticsearch.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>With it, you can visualize a huge array of data via graphs, pie charts, data tables, etc, in order to monitor what’s happening in your application via its logs.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You will see this in action in the final section of this exercise.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Setting up Kibana</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Add this final piece of config to your <code>docker-compose.yml</code> file:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/79e94cc6f7ec03a5095f5eaac011d767.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>There is nothing new in this configuration section.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>It installs the baseline docker image, depends on <strong>elasticsearch</strong>, has a health check of its own and maps its internal <code>port 5601</code> to the machine’s real <code>port 5601</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In addition to this, you can, optionally, add a dependency of your golang application on <code>kibana</code> to make sure your entire container stack boots up only after <strong>Kibana</strong>’s server is ready:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
{%gist https://gist.github.com/preslavmihaylov/a486619fdca1eeb3685757d66f803b28.js %}
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Now, test that everything works properly by running <code>docker-compose up</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, you should be able to go to <a href="http://localhost:5601/app/kibana">http://localhost:5601/app/kibana</a> and see Kibana’s home page load.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you didn’t do that last optional step, you might have to wait awhile before Kibana boots up:</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://lh4.googleusercontent.com/D4sh4ur4mJd4uYF6vGW-WZ_0mc421476ZxxcXmkEmaBxaqHtTTzdBUJMNUo_lDbEPsJDVpaxGzZmxvzRVwBVjrhy_vkinzLi1-aolBNbP0PFcX5kMWHRTTsvoP2kQ3LGRy5f72ui" alt="The Kibana landing page"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>If you instead get asked for defining an Index Pattern, use<strong> </strong><code>logstash-*</code>:</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://lh5.googleusercontent.com/jd2TkhUMhbVF4MdF4vTZRzACFYMMpjKoQV5miX3WKXh6v_hOgoS8PQQEkv_cQ5GUPXAVaAtjH4upk2JZxxl8x48EDAssC8HMv31Jh1QH7i1rxEkKIKtMJZLea-gbpuAaAKNQscpO" alt="selecting the index pattern in Kibana"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>On the next step, select <code>@timestamp</code> as a time filter:</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://lh4.googleusercontent.com/weu-tHxwp7PAGeAfxtlNk0_7jW3ahArV5myDzqbSOHVJEm-ZRQkSg3i0XvwVbe8nvK7BadyOz1KeqJmkk_c3sSeB5w1PSTkIZ0YPX6fw821kDwzhtwKlw_XSz23yweCXJEVwFM23" alt="selecting timestatmp as a time filter field"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>This finishes the Kibana setup.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In the final section, we will test that everything is integrated correctly by searching through our application logs via Kibana.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Search through your logs via Kibana</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Open Kibana and expand your tabs first in the bottom-left corner of the site:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"width":368,"height":256} -->
<figure class="wp-block-image is-resized"><img src="https://lh4.googleusercontent.com/zm0q6TcgnWX0WQzhPsQS1AGb4V84E6rQnM-PiAS1xe6ZyAT1J-4EXNIJO8yKolI2qixwQGp3a9mR4Y7Xknbf4ntrbAMLiO1CV1UmyU2tofDh39qRhQAe_i3qd0LCY58vjnnUrdlJ" alt="The collapse button in Kibana" width="368" height="256"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Next up, open the <strong>Discover</strong> tab:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"width":375,"height":207} -->
<figure class="wp-block-image is-resized"><img src="https://lh3.googleusercontent.com/_LExO2XFAW6k8ONsrhdbGcEDN1ePGUgSTdUVg5u_zSujmwkWGVh0UPriHV4SHqPkjR54V2ckzqqzcu-WGSCYq64uG3dy8r1n7GBI1JCbXW3grFe04_SawU7WznTV8HDNiqDG-rPO" alt="The discover tab button" width="375" height="207"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>After you open it, you should see all your logs here:</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://lh4.googleusercontent.com/v6nn7ACZ1CxNOHPBPyNU7FmJezHI_UK24BcgfeWX-otyDcjMigm8OXM5OafuQpo3AIUS0DJaBDnMwhlCH5LEAqxiOfMhBqUG3DKSjNAOUNk3lGaNSsop4Rr24-4L_j8e2tXHBbZa" alt="viewing your logs in Kibana"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Filter only the application log fields on the left:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"width":327,"height":494} -->
<figure class="wp-block-image is-resized"><img src="https://lh5.googleusercontent.com/aNIxOiIQWuU_UXH_AGeKJtr1XYGvUunantI-SgKRkU52r0650s2wBrexCX9Atr9BmUDHEhqBbHnCprY6Ya9tc2qaO-Ovs52v57OYiUn9MbQpyxlSujYBMmEQ2dPvBy-1ToXjyiH3" alt="select the error and msg fields from your logs" width="327" height="494"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>And voila, you should be able to see all your application logs:</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://lh5.googleusercontent.com/EptgT_xi43SLH6S0P0HXIJgGOurLTN6F9D486kDYMLEKJ-47qv6GWrbEJGdMtx5rcFppZFrhwp6H_tS-A3o_Sw6azxFVWCicbgZKvhGsdDMwEzjWVOWhHuW0y1n-Lpg-57oHgXGS" alt="logs visible in Kibana"/></figure>
<!-- /wp:image -->

<!-- wp:heading -->
<h2>&nbsp;Conclusion</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>This wraps up the tutorial to integrate a Go service with the ELK stack.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You should now have a good understanding of how the ELK stack works &amp; each of its different components. Additionally, you should now have a good grasp of how to configure your ELK setup correctly &amp; wire it to your Go application.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>From here, you can start playing with Kibana by setting up useful dashboards based on your data. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Watch out for a follow-up tutorial for doing just that!</p>
<!-- /wp:paragraph -->