ELK系列(1) - Elasticsearch + Logstash + Kibana + Log4j2快速入門與搭建用例


前言

最近公司分了個ELK相關的任務給我,在一邊學習一邊工作之余,總結下這些天來的學習歷程和踩坑記錄。

首先介紹下使用ELK的項目背景:在項目的數據庫里有個表用來存儲消息隊列的消費日志,這些日志用於開發者日后的維護。每當客戶端生產一條消息並發送到消息隊列后,就會插入一條對應的記錄到數據庫里。當這條消息被消費之后,又會更新數據庫里對應的記錄的幾個column的值,比如status、updated_on這些常用的column。

由於客戶每天生產消費的消息很多,導致數據庫里的這個表里的數據很多,長年累月下來,會達到數以億計。領導決定不再把這些消費日志保存到數據庫,而是改為通過Log4j2 + ELK架構把這些日志保存到Elasticsearch里。

ELK簡介

ELk是Elasticsearch + Logstash + Kibana的縮寫,ELK一般用來收集分布式架構下各個節點的日志,並進行統一地管理。

Elasticsearch是個開源分布式搜索引擎,提供搜集、分析、存儲數據三大功能。它的特點有:分布式,零配置,自動發現,索引自動分片,索引副本機制,restful風格接口,多數據源,自動搜索負載等。

Logstash主要是用來日志的搜集、分析、過濾日志的工具,支持大量的數據獲取方式。一般工作方式為c/s架構,client端安裝在需要收集日志的主機上,server端負責將收到的各節點日志進行過濾、修改等操作在一並發往elasticsearch上去。

Kibana也是一個開源和免費的工具,Kibana可以為Logstash和ElasticSearch提供的日志分析友好的Web界面,可以幫助匯總、分析和搜索重要數據日志。

上面的官方介紹可能會比較抽象,按我個人的理解,可以簡單將ELK理解為一個MVC架構的Java web應用:Elasticsearch對應M,Logstash對應C,Kibana對應V。

由於項目使用的是6.4.2版本的Elasticsearch,所以整個ELK都采用了同樣的版本6.4.2。這三個軟件都可以直接從官網下載到,下面是官網地址。

官方下載地址

ELK的下載安裝與快速入門

本文只是基於Windows平台下,進行簡單的快速入門,先搭建好ELK框架並測試通過,后續文章再記錄更多的細節。

Elasticsearch 6.4.2

從官網下載了6.4.2版本的Elasticsearch的壓縮版后,解壓即可使用,使用默認的配置即可。

在Elasticsearch的安裝目錄下,進入/bin目錄,可以看到有兩個文件:

  1. elaticsearch
  2. elaticsearch.bat

這兩個文件都可以啟動Elasticsearch,暫時沒發現在Windows平台下通過這兩個文件啟動Elasticsearch有什么不同。我一般使用沒有后綴名的那個文件來啟動Elasticsearch。

啟動成功后,在瀏覽器輸入127.0.0.1:9200,如果訪問成功會反饋信息:

{
  "name" : "erwbgE5",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "QQvV3hBnSCSGsf-ycD3fng",
  "version" : {
    "number" : "6.4.2",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "04711c2",
    "build_date" : "2018-09-26T13:34:09.098244Z",
    "build_snapshot" : false,
    "lucene_version" : "7.4.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

注意,如果使用Elasticsearch5.X及以上的版本,需要使用jdk 1.8;5.X以下版本使用jdk 1.6或1.7。

Logstash 6.4.2

同樣從官網下載6.4.2版本的Logstash安裝包,解壓之后進入/config目錄,創建一個配置文件tcp.conf,內容如下:

input {
    stdin {
    }
}
filter {
}
output {
    stdout {
        codec => rubydebug
    }
}

接着進入/bin目錄,運行命令如下:

logstash -f ../config/test.conf

當看到Successfully started Logstash API endpoint的字眼時表示啟動成功,此時輸入任意字符,比如輸入hello,可以得到相應的反饋,如下:

{
       "message" => "hello\r",
    "@timestamp" => 2019-05-09T14:48:04.033Z,
          "host" => "DESKTOP-S7HJJKD",
      "@version" => "1"
}

這里解釋下,Logstash的配置非常簡單,就是一套流程:input -> filter -> output

input用來收集信息,這里配置的是stdin插件,即標准輸入,也就是剛剛在控制台里輸入的字符串。
filter表示過濾信息,這里沒有進行任何過濾。
output表示輸出信息,這里配置的是stdout插件,即標准輸出,也就是將信息輸出到控制台上。這里的codec指明使用rubydebug作為編解碼器。

接着是運行的命令,使用了-f參數來指定使用某個配置文件。如果想要熱加載的效果,可以加上-r參數,這樣就可以在運行Logstash的時候去修改配置文件並自動重加載生效。這個-r參數等同於--config.reload.automatic。如下:

logstash -f ../config/test.conf -r
logstash -f ../config/test.conf --config.reload.automatic

注意,如果在輸入源里使用了stdin或者syslog等輸入插件,是不支持熱加載的,會一直報錯。

Kibana 6.4.2

從官網上下載Kibana6.4.2的壓縮包,解壓后即可使用。接着進入/bin目錄,運行kibana.bat。運行成功后,在瀏覽器輸入localhost:5601,即可訪問Kibana的頁面,之后就可以通過這個Kibana提供的web界面來對Elasticsearch里的文檔進行各種操作。

Logstash + Log4j2的快速搭建用例其一

配置tcp插件並啟動Logstash

修改之前創建的Logstash的配置文件test.config,內容如下:

input {
    tcp {
        mode => "server"
        host => "127.0.0.1"
        port => 4567
    }
}
filter {
}
output {
    stdout {
        codec => rubydebug
    }
}

然后運行命令logstash -f ../config/test.conf -r來啟動Logstash。由於我們這里通過-r來啟用了熱加載功能,所以可以在運行中直接修改配置並生效,比如修改input里的port。熱加載成功后會看到如下字眼:

Reloading pipeline {"pipeline.id"=>:main}

使用了Socket Appender的Log4j2項目demo

接着准備一個使用了Log4j2的項目demo,如下是一個測試類Test.java

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {
    public static final Logger LOGGER = LogManager.getLogger("elk.test");

    public static void main(final String[] args) {
        LOGGER.info("Hello world!");
    }
}

這里使用的是2.11.1版本的Log4j2,Maven依賴如下:

<dependency>
	<groupId>org.apache.logging.log4j</groupId>
	<artifactId>log4j-core</artifactId>
	<version>2.11.1</version>
</dependency>

接着是配置Log4j2的配置文件log4j2.xml,如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:xi="http://www.w3.org/2001/XInclude" monitorInterval="30">

    <Properties>
        <Property name="LOG_PATTERN">{"logger": "%logger", "level": "%level", "msg": "%message"}%n</Property>
    </Properties>

	<Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="${LOG_PATTERN}" />
        </Console>

        <Socket name="logstash-tcp" host="127.0.0.1" port="4567" protocol="TCP">
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </Socket>
	</Appenders>

	<Loggers>
		<Logger name="elk.test" level="info" additivity="false">
            <AppenderRef ref="stdout" />
            <AppenderRef ref="logstash-tcp" />
		</Logger>
		<Root level="error">
			<AppenderRef ref="stdout" />
		</Root>
	</Loggers>

</configuration>

從配置文件中可以看到,這里使用的是Socket Appender來將日志打印的信息發送到Logstash。

注意了,Socket的Appender必須要配置到下面的Logger才能將日志輸出到Logstash里!

另外這里的host是部署了Logstash服務端的地址,並且端口號要和你在Logstash里配置的一致才行。

運行該項目demo,可以看到Logstash的控制台收集到了數據,如下:

{
          "host" => "127.0.0.1",
       "message" => "{\"logger\": \"elk.test\", \"level\": \"INFO\", \"msg\": \"Hello world!\"}\r",
    "@timestamp" => 2019-05-09T16:20:35.940Z,
      "@version" => "1",
          "port" => 49781
}

注意

這里由於使用的是Socket方式來連接Logstash的服務端,如果在連接期間,Logstash的服務停止了或者斷掉了,就算接下來重啟了Logstash,項目工程也無法自動重新連接上Logstash,除非重啟項目工程。

在生產環境中,Logstash自然是有可能半路出問題重啟的,所以不能使用這種Socket方式來傳輸日志。

可以使用gelf的方式來傳輸日志到Logstash,用例如下所示。

Logstash + Log4j2的快速搭建用例其二

配置gelf插件並啟動Logstash

修改之前創建的Logstash的配置文件test.config,內容如下:

input {
    gelf {
        host => "127.0.0.1"
        port => 4567
		use_tcp => true
    }
}
filter {
}
output {
    stdout {
        codec => rubydebug
    }
}

運行命令logstash -f ../config/test.conf -r啟動Logstash。

在Log4j2項目中使用Gelf Appender

將之前的項目工程里的log4j2.xml的Socket Appender改為使用Gelf Appender,如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:xi="http://www.w3.org/2001/XInclude" monitorInterval="30">

    <Properties>
        <Property name="LOG_PATTERN">{"logger": "%logger", "level": "%level", "msg": "%message"}%n</Property>
    </Properties>

	<Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="${LOG_PATTERN}" />
        </Console>

        <Gelf name="logstash-gelf" host="tcp:localhost" port="4567" version="1.1" ignoreExceptions="true"
             extractStackTrace="true" filterStackTrace="false">
            <Field name="timestamp" pattern="%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ}" />
            <Field name="level" pattern="%level" />
            <Field name="simpleClassName" pattern="%C{1}" />
            <Field name="className" pattern="%C" />
            <Field name="server" pattern="%host" />
        </Gelf>
	</Appenders>

	<Loggers>
		<Logger name="elk.test" level="info" additivity="false">
            <AppenderRef ref="stdout" />
            <AppenderRef ref="logstash-gelf" />
		</Logger>
		<Root level="error">
			<AppenderRef ref="stdout" />
		</Root>
	</Loggers>

</configuration>

另外,這個Gelf Appender需要導入另一個依賴,如下:

<dependency>
    <groupId>biz.paluch.logging</groupId>
    <artifactId>logstash-gelf</artifactId>
    <version>1.11.1</version>
</dependency>

接着運行項目工程,可以看到Logstash的控制台已經把收集到的日志打印出來了:

{
            "message" => "Hello world!",
         "@timestamp" => 2019-05-10T14:09:43.267Z,
          "className" => "lewky.cn.Test",
        "source_host" => "127.0.0.1",
          "timestamp" => "2019-05-10T22:09:43.211+0800",
    "simpleClassName" => "Test",
           "facility" => "logstash-gelf",
              "level" => "INFO",
               "host" => "DESKTOP-S7HJJKD",
           "@version" => "1",
             "server" => "DESKTOP-S7HJJKD"
}

ELK + Log4j2快速搭建用例

接下來就可以把Logstash收集到的日志輸出到Elasticsearch,並通過Kibana顯示到界面上。

Logstash配置Elasticsearch插件

修改配置文件如下:

input {
    gelf {
        host => "127.0.0.1"
        port => 4567
        use_tcp => true
    }
}
filter {
}
output {
    stdout {
        codec => rubydebug
    }
    elasticsearch {
        hosts => ["127.0.0.1:9200"]
		document_id => "%{docId}"
        index => "%{indexName}"
    }
}

output里添加了elasticsearch插件:

  1. hosts里配置Elasticsearch server的地址
  2. document_id是index到ES時使用的索引id
  3. index是index到ES是使用的索引名字

修改log4j2.xml和項目代碼

在項目的log4j2.xml里的Gelf Appender加上兩個個新的Field:indexNamedocId,如下:

<Gelf name="logstash-gelf" host="tcp:localhost" port="4567" version="1.1" ignoreExceptions="true"
     extractStackTrace="true" filterStackTrace="false">
    <Field name="timestamp" pattern="%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ}" />
    <Field name="level" pattern="%level" />
    <Field name="simpleClassName" pattern="%C{1}" />
    <Field name="className" pattern="%C" />
    <Field name="server" pattern="%host" />

    <Field name="indexName" mdc="indexName" />
    <Field name="docId" mdc="docId" />
</Gelf>

這里添加的兩個新的Field對應於上邊Logstash配置文件里的兩個變量,然后這里用到了mdc,這個是Log4j2里的ThreadContext的東西,有興趣可以去了解下Log4j2里的MDC和NDC。

接着修改測試類的代碼,如下:

public class Test {
    public static final Logger LOGGER = LogManager.getLogger("elk.test");

    public static void main(final String[] args) {
        ThreadContext.put("docId", "1");
        ThreadContext.put("indexName", "test");

        LOGGER.info("Hello world!");
    }
}

接着依次啟動ELK三個軟件,然后運行項目,可以發現Logstash控制台里收集到了日志信息:

{
    "simpleClassName" => "Test",
             "server" => "DESKTOP-S7HJJKD",
            "message" => "Hello world!",
           "@version" => "1",
        "source_host" => "127.0.0.1",
          "indexName" => "test",
              "level" => "INFO",
         "@timestamp" => 2019-05-11T16:40:14.996Z,
           "facility" => "logstash-gelf",
          "className" => "lewky.cn.Test",
          "timestamp" => "2019-05-12T00:40:14.877+0800",
              "docId" => 1,
               "host" => "DESKTOP-S7HJJKD"
}

而在我們的IDE控制台(我用的是Eclipse)里也可以看到輸出了信息:

{"logger": "elk.test", "level": "INFO", "msg": "Hello world!"}

配置Kibana查看Elasticsearch的index數據

接下來就是最后一步了,通過Kibana來查看我們剛剛index到Elasticsearch里的數據。

啟動了Kibana后,在瀏覽器訪問localhost:5601,進入界面后,操作如下:

  1. Management -> Index Patterns
  2. 輸入index的名字,我們這里填的是test;然后點擊Next step
  3. Time Filter field name下方的下拉框里選擇timestamp作為我們的一個排序字段,默認是desc,即遞減排序
  4. 最后點擊Create index pattern

現在已經配置好了Index pattern,我們就可以直接在左側菜單欄里的Discover去查看對應的index里的數據了。如果不出意外,現在在Discover里已經看到剛剛被我們index進去的日志信息了。

默認只會顯示Time_source兩個字段的數據,Time就是排序字段,它的值和之前我們選擇的那個timestamp一樣。_source里則是所有字段的數據總和。

可以根據需要,在顯示字段的左側把任意的字段add到右側以顯示出來。當你添加了新的字段之后,_source字段會自動消失。

這就是最簡單的一個ELK快速搭建例子,有興趣的可以接着看后續的文章以了解更多和ELK相關的問題或知識。

參考鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM