Fluentd教程(附實(shí)例)

fluentd是一個(gè)開源的日志收集系統(tǒng),能夠收集各式各樣的日志, 并將日志轉(zhuǎn)換成方便機(jī)器處理的json格式蔓倍。

fluentd日志架構(gòu)

安裝

不同操作系統(tǒng)的安裝方式不同,具體可以參考:

官方文檔: Installation

另外在生產(chǎn)環(huán)境中安裝Fluentd之前,也需要對(duì)操作系統(tǒng)做一些配置睬罗,如:

  • 設(shè)置好NTP時(shí)間同步
  • 調(diào)整允許操作的文件符最大個(gè)數(shù)
  • 優(yōu)化內(nèi)核中與網(wǎng)絡(luò)相關(guān)的參數(shù)等

具體配置可以參考:

官方文檔: Before Installation

本文為了便于快速測(cè)試患朱,直接使用fluentd的docker鏡像來啟動(dòng)fluentd服務(wù)鲁僚。

# 下載fluentd鏡像
$ docker pull fluent/fluentd:v1.7-1

準(zhǔn)備配置文件

首先創(chuàng)建一些簡單的文件方便測(cè)試。本文所有使用到的配置文件都已經(jīng)上傳到github,可以直接下載使用

$ git clone https://github.com/crazygit/fluentd_demo

當(dāng)然也可以自己動(dòng)手完成

$ mkdir fluentd_demo

# 注意: 本文后續(xù)所有命令都在fluentd_demo目錄下執(zhí)行
$ cd fluentd_demo

# 創(chuàng)建用于保存fluentd的配置文件的etc目錄和保存日志文件的log目錄
$ mkdir -p etc log

# 再創(chuàng)建一個(gè)簡單的配置文件
$ cat etc/fluentd_basic_setup.conf

<source>
  @type http
  port 8888
  bind 0.0.0.0
</source>
<match test.cycle>
  @type stdout
</match>

配置文件解釋:

  • source部分使用了http輸入插件裁厅,在8888端口啟動(dòng)一個(gè)web服務(wù)用于收集日志

  • match部分定義只要日志匹配test.cycle標(biāo)簽冰沙,就將日志輸出到標(biāo)準(zhǔn)輸出

目前不用太關(guān)心配置文件的格式,后面會(huì)有詳細(xì)的介紹执虹。

創(chuàng)建好的目錄結(jié)構(gòu)如下:

$ tree
.
├── etc
│   └── fluentd_basic_setup.conf
└── log

啟動(dòng)容器

$ docker run -p 8888:8888 --rm -v $(pwd)/etc:/fluentd/etc -v $(pwd)/log:/fluentd/log fluent/fluentd:v1.7-1 -c /fluentd/etc/fluentd_basic_setup.conf -v

命令參數(shù)解釋如下:

  • -p參數(shù)映射容器的8888端口到宿主機(jī)的8888端口拓挥,方便我們直接從宿主機(jī)直接訪問容器
  • 第一個(gè)-v參數(shù)用于掛載本地的etc目錄到容器內(nèi)的etc目錄,讓容器能夠使用本地的配置文件
  • 第二個(gè)-v參數(shù)用于掛載本地的log目錄到容器內(nèi)的log目錄声畏,便于保存輸出的日志文件
  • -c參數(shù)用于設(shè)置容器內(nèi)的fluentd時(shí)候啟動(dòng)的使用/fluentd/etc/fluentd_basic_setup.conf配置文件
  • 最后一個(gè)參數(shù)-v用于設(shè)置容器內(nèi)的fluentd時(shí)候啟動(dòng)的開啟verbose模式撞叽,便于調(diào)試發(fā)現(xiàn)問題。

正常啟動(dòng)后插龄,能看到如下輸出

fluentd -c /fluentd/etc/fluentd_basic_setup.conf -v
2019-11-27 02:03:22 +0000 [info]: fluent/log.rb:322:info: parsing config file is succeeded path="/fluentd/etc/fluentd_basic_setup.conf"
2019-11-27 02:03:22 +0000 [info]: fluent/log.rb:322:info: using configuration file: <ROOT>
  <source>
    @type http
    port 8888
    bind "0.0.0.0"
  </source>
  <match test.cycle>
    @type stdout
  </match>
</ROOT>
2019-11-27 02:03:22 +0000 [info]: fluent/log.rb:322:info: starting fluentd-1.7.4 pid=6 ruby="2.5.7"
2019-11-27 02:03:22 +0000 [info]: fluent/log.rb:322:info: spawn command to main:  cmdline=["/usr/bin/ruby", "-Eascii-8bit:ascii-8bit", "/usr/bin/fluentd", "-c", "/fluentd/etc/fluentd_basic_setup.conf", "-v", "-p", "/fluentd/plugins", "--under-supervisor"]
2019-11-27 02:03:23 +0000 [info]: fluent/log.rb:322:info: gem 'fluentd' version '1.7.4'
2019-11-27 02:03:23 +0000 [info]: fluent/log.rb:322:info: adding match pattern="test.cycle" type="stdout"
2019-11-27 02:03:23 +0000 [info]: fluent/log.rb:322:info: adding source type="http"
2019-11-27 02:03:23 +0000 [info]: #0 fluent/log.rb:322:info: starting fluentd worker pid=14 ppid=6 worker=0
2019-11-27 02:03:23 +0000 [debug]: #0 fluent/log.rb:302:debug: listening http bind="0.0.0.0" port=8888
2019-11-27 02:03:23 +0000 [info]: #0 fluent/log.rb:322:info: fluentd worker is now running worker=0

另外愿棋,也可以通過環(huán)境變量FLUENTD_CONF設(shè)置需要使用的配置文件

# 下面的命令和上面的是等效的
$ docker run -p 8888:8888 --rm -v $(pwd)/etc:/fluentd/etc/ -e FLUENTD_CONF=fluentd_basic_setup.conf fluent/fluentd:v1.7-1

測(cè)試

# 任意偽造一個(gè)用戶登錄的日志,向fluentd服務(wù)提交日志
$ curl -i -X POST -d 'json={"action":"login","user":2}' http://localhost:8888/test.cycle
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: Keep-Alive
Content-Length: 0

fluentd的容器里能看到如下輸出

2019-11-27 02:05:16.583154500 +0000 test.cycle: {"action":"login","user":2}

Fluentd事件的生命周期

什么是事件(Event)

正如開篇提到過均牢,F(xiàn)luentd是一個(gè)日志收集系統(tǒng)糠雨,那么一條日志消息,在Fluentd里就認(rèn)為是一個(gè)事件(Event)徘跪。

事件結(jié)構(gòu)

Fluentd的事件由下面三部分組成

  • 標(biāo)簽(tag): 用于說明這個(gè)事件是哪里產(chǎn)生的甘邀,可用于后面的事件路由
  • 時(shí)間(time): 事件是什么時(shí)候發(fā)生的,時(shí)間格式為: Epoch time, 即Unix時(shí)間戳
  • 記錄(record): 事件內(nèi)容本身垮庐,JSON格式

所有的輸入插件都需要解析原始日志松邪,生成滿足上面結(jié)構(gòu)的事件字段,比如哨查,一條Apache的訪問日志:

192.168.0.1 - - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777

通過in_tail輸入插件處理之后逗抑,將會(huì)得到下面的輸出

tag: apache.access # 由配置文件指定
time: 1362020400   # 28/Feb/2013:12:00:00 +0900
record: {"user":"-","method":"GET","code":200,"size":777,"host":"192.168.0.1","path":"/"}

事件的處理流程

當(dāng)fluentd收到一個(gè)事件之后,會(huì)經(jīng)過一系列的處理流程:

  1. 如修改事件的相關(guān)字段
  2. 過濾掉一些不關(guān)心的事件
  3. 路由事件輸出到不同的地方

下面將一一介紹介紹事件的處理流程

過濾器(Filter)

Filter用于定義一個(gè)事件是該被接受或者是被過濾掉(拋棄掉)。使用示例如下:

$ cat etc/fluentd_filter_demo.conf
<source>
  @type http
  port 8888
  bind 0.0.0.0
</source>

<filter test.cycle>
  @type grep
  <exclude>
    key action
    pattern ^logout$
  </exclude>
</filter>

<match test.cycle>
  @type stdout
</match>

上面的示例配置了讓我們直接過濾掉用戶logout的事件邮府。

重啟fluentd,使用上面的定義的配置文件

$ docker run -p 8888:8888 --rm -v $(pwd)/etc:/fluentd/etc -v $(pwd)/log:/fluentd/log fluent/fluentd:v1.7-1 -c /fluentd/etc/fluentd_filter_demo.conf -v

測(cè)試

$ curl -i -X POST -d 'json={"action":"login","user":2}' http://localhost:8888/test.cycle
HTTP/1.1 200 OK
Content-type: text/plain
Connection: Keep-Alive
Content-length: 0

$ curl -i -X POST -d 'json={"action":"logout","user":2}' http://localhost:8888/test.cycle
HTTP/1.1 200 OK
Content-type: text/plain
Connection: Keep-Alive
Content-length: 0

我們向fluentd發(fā)送了兩個(gè)事件荧关,分別是用戶loginlogout的事件。

檢查fluend的輸出

2019-11-27 03:38:28.973757600 +0000 test.cycle: {"action":"login","user":2}

可以看到只輸出了用戶login的事件褂傀,logout事件被過濾掉了忍啤。

標(biāo)識(shí)符(Labels)

從前面的例子里,我們可以看到仙辟,fluentd的處理流程是根據(jù)我們?cè)谂渲梦募械亩x同波,從上到下依次執(zhí)行的。假如我們?cè)谂渲梦募锒x了比較多輸入源叠国,不同的輸入源需要使用不同的filters時(shí)参萄,如果仍然按照從上到下執(zhí)行的順序的話,由于不同的處理需求煎饼,我們的配置文件可能變得非常復(fù)雜。

通過label校赤,我們可以為不同的輸入源指定不同的處理流程吆玖,示例如下:

$ cat etc/fluentd_labels.conf
<source>
  @type http
  bind 0.0.0.0
  port 8888
  @label @STAGING  # 注意這里我們添加了label
</source>

<filter test.cycle>
  @type grep
  <exclude>
    key action
    pattern ^login$
  </exclude>
</filter>

<label @STAGING>
  <filter test.cycle>
    @type grep
    <exclude>
      key action
      pattern ^logout$
    </exclude>
  </filter>

  <match test.cycle>
    @type stdout
  </match>
</label>

上面的示例文件里,我們首先定義了一個(gè)filter過濾掉login事件

<filter test.cycle>
  @type grep
  <exclude>
    key action
    pattern ^login$
  </exclude>
</filter>

接著又在label塊里面過濾掉了logout事件

<filter test.cycle>
  @type grep
  <exclude>
    key action
    pattern ^login$
  </exclude>
</filter>

如果按照從上到下的順序執(zhí)行马篮,那么我們將看不到任何loginlogout的事件沾乘。但是實(shí)際結(jié)果如何呢?讓我們來測(cè)試一下浑测。

使用上面定義的配置文件啟動(dòng)fluentd

$ docker run -p 8888:8888 --rm -v $(pwd)/etc:/fluentd/etc -v $(pwd)/log:/fluentd/log fluent/fluentd:v1.7-1 -c /fluentd/etc/fluentd_labels.conf -v

提交事件來測(cè)試, 同樣向fluentd發(fā)送兩個(gè)事件翅阵,分別是用戶loginlogout的事件。

$ curl -i -X POST -d 'json={"action":"login","user":2}' http://localhost:8888/test.cycle
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: Keep-Alive
Content-Length: 0

$ curl -i -X POST -d 'json={"action":"logout","user":2}' http://localhost:8888/test.cycle
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: Keep-Alive
Content-Length: 0

查看fluentd輸出

2019-11-27 03:51:45.088464900 +0000 test.cycle: {"action":"login","user":2}

可以看到迁央,只有logout事件被過濾了掷匠,原因是我們?yōu)檩斎朐O(shè)置了label

<source>
  @type http
  bind 0.0.0.0
  port 8888
  @label @STAGING  # 注意這里我們添加了label
</source>

因此跳過中間設(shè)置的一些filter,只運(yùn)行了<label @STAGING>...</lable>標(biāo)簽塊里的filter

緩沖區(qū)(Buffers)

在前面的例子中岖圈,我們使用的都是stdout這樣一個(gè)沒有緩沖區(qū)的輸出讹语,在生產(chǎn)環(huán)境中,我們用到的輸出基本都是有緩沖區(qū)
的,比如s3, forward,mongodb等蜂科,這些輸出插件在收到事件之后顽决,會(huì)將事件先保存到緩沖區(qū),然后等滿足特定條件之后导匣,再將事件輸出到目標(biāo)輸出才菠。

配置文件語法

配置文件由一下幾部分組成

配置文件中的術(shù)語

  • source: 指定輸入源

    例如:

    # 在24224端口接受TCP事件
    <source>
      @type forward
      port 24224
    </source>
    
    <source>
      @type http
      port 9880
    </source>
    

    輸入源可以一次指定多個(gè), @type參數(shù)指定使用哪一個(gè)輸入插件贡定。
    fluentd支持各種輸入插件, 比如:

    • in_tail
    • in_forward
    • in_udp
    • in_tcp
    • in_unix
    • in_http
    • in_syslog
    • in_exec
    • in_dummy
    • in_windows_eventlog

    插件的具體使用可以參考文檔:
    https://docs.fluentd.org/input

  • match: 指定輸出的目的地

    例如:

    # 將滿足myapp.acccess標(biāo)簽的事件全部輸出到
    # /var/log/fluent/access.%Y-%m-%d
    <match myapp.access>
      @type file
      path /var/log/fluent/access
    </match>
    

    輸出也可以一次指定多個(gè)赋访, @type參數(shù)指定使用哪一個(gè)輸出插件。
    fluentd支持各種輸出插件, 比如:

    • out_copy
    • out_null
    • out_roundrobin
    • out_stdout
    • out_exec_filter
    • out_forward
    • out_mongo or out_mongo_replset
    • out_exec
    • out_file
    • out_s3
    • out_webhdfs

    插件的具體使用可以參考文檔:
    https://docs.fluentd.org/output

  • filter: 指定事件的處理流程

    可以多個(gè)filter串聯(lián)起來,比如:

    Input -> filter 1 -> ... -> filter N -> Output
    

    例如:

    <filter myapp.access>
    @type record_transformer
    <record>
      host_param "#{Socket.gethostname}"
    </record>
    </filter>
    

    上面的filter會(huì)添加host_param參數(shù)到事件

    fluentd也內(nèi)置了各種filter, 比如:

    • grep
    • record-transformer
    • filter_stdout
    • geoip
    • parser

    filter的具體使用可以參考文檔:

    https://docs.fluentd.org/filter

  • system: 指定系統(tǒng)級(jí)別的配置

    可以設(shè)置的參數(shù)有

    • log_level
    • suppress_repeated_stacktrace
    • emit_error_log_interval
    • suppress_config_dump
    • without_source
    • process_name (only available in system directive. No fluentd option)

    例如:

    <system>
    # equal to -qq option
    log_level error
    # equal to --without-source option
    without_source
    # ...
    </system>
    
  • label: 用于分組特定的filter和match

    例如:

    <source>
    @type forward
    </source>
    
    <source>
      @type tail
      @label @SYSTEM
    </source>
    
    <filter access.**>
      @type record_transformer
      <record>
        # ...
      </record>
    </filter>
    <match **>
      @type elasticsearch
      # ...
    </match>
    
    <label @SYSTEM>
      <filter var.log.middleware.**>
        @type grep
        # ...
      </filter>
      <match **>
        @type s3
        # ...
      </match>
    </label>
    

    上面的配置文件中:

    in_forward的事件將經(jīng)過record_transformer 過濾器和elasticsearch輸出进每。

    in_tail輸入的事件將經(jīng)過grep過濾器和s3輸出汹粤。

另外: <label @ERROR>屬于內(nèi)置的配置,用于保存內(nèi)部錯(cuò)誤田晚,比如:
緩沖區(qū)已經(jīng)滿了或者無效的事件等嘱兼。

  • @include: 引入其它的配置文件∠屯剑可以將配置文件拆分為多個(gè)芹壕,便于復(fù)用。當(dāng)要使用的時(shí)候接奈,直接使用@include引入即可踢涌,例如:

    # 通過絕對(duì)路徑引入
    @include /path/to/config.conf
    
    # 通過相對(duì)路徑引入,相對(duì)于當(dāng)前配置文件的路徑
    @include extra.conf
    
    # 模糊匹配序宦,所有符合條件的會(huì)根據(jù)文件名的字母順序依次導(dǎo)入
    # 比如: a.conf, b.conf, ..., z.conf
    # 因此, 要注意各個(gè)配置文件不應(yīng)該有順#序依賴睁壁,如果有順序依賴,請(qǐng)明確指出導(dǎo)入的文件名
    @include config.d/*.conf
    
    # 使用在線的配置
    @include http://example.com/fluent.conf
    

    @include指定也可以用于導(dǎo)入相關(guān)的參數(shù)信息互捌,比如:

    有如下配置文件

    <match pattern>
      @type forward
      # other parameters...
      <buffer>
        @type file
        path /path/to/buffer/forward
        @include /path/to/out_buf_params.conf
      </buffer>
    </match>
    
    <match pattern>
      @type elasticsearch
      # other parameters...
      <buffer>
        @type file
        path /path/to/buffer/es
        @include /path/to/out_buf_params.conf
      </buffer>
    </match>
    

    參數(shù)配置文件/path/to/out_buf_params.conf

    flush_interval 5s
    total_limit_size 100m
    chunk_limit_size 1m
    

配置文件的模式匹配(patterns)

通配符

如前面的示例可以看到潘明,fluented主要根據(jù)事件的tag來分區(qū)不同的處理流程

雖然我們可以明確指定需要處理的tag,比如:<filter app.log>來指定只處理tag為app.log的事件秕噪。我們也可以在filtermatch中通過通配符钳降,來處理同一類tag的事件

tag通常是一個(gè)字符串,由.分隔腌巾,比如myapp.access

  • *: 匹配滿足一個(gè)tag部分的事件, 比如: a.*, 它將匹配a.b這樣的tag, 但是不會(huì)處理a或者a.b.c這類tag

  • **: 匹配滿足0個(gè)或多個(gè)tag部分遂填,比如: a.**, 它將匹配a, a.b, a.b.c這三種tag

  • {X, Y, Z}: 匹配滿足X,Y或者Z的tag, 比如: {a, b}將匹配a或者b,但是不會(huì)匹配c

    這種格式也可以和通配符組合使用,比如a.{b.c}.*a.{b.c}.**

  • #{...} 會(huì)把花括號(hào)內(nèi)的字符串當(dāng)做是ruby的表達(dá)式處理澈蝙。比如

    <match "app.#{ENV['FLUENTD_TAG']}">
      @type stdout
    </match>
    

    如果設(shè)置了環(huán)境變量FLUENTD_TAGdev,那上面等價(jià)于app.dev

  • 當(dāng)指定了多個(gè)模式時(shí)(使用一個(gè)或多個(gè)空格分開),只要滿足其中任意一個(gè)就行吓坚。

    比如:
    <match a b>匹配ab
    <match a.** b.*>匹配a, a.b, a.b.c, b.d

多個(gè)match之間的順序注意

當(dāng)有多個(gè)match, 需要注意一下它們的順序, 如下面的例子灯荧,第二個(gè)match永遠(yuǎn)也不會(huì)生效

# ** matches all tags. Bad :(
<match **>
  @type blackhole_plugin
</match>

<match myapp.access>
  @type file
  path /var/log/fluent/access
</match>

正確的寫發(fā)應(yīng)該是將確定的tag盡量寫在前面凌唬,模糊匹配的寫在后面。

<match myapp.access>
  @type file
  path /var/log/fluent/access
</match>

# Capture all unmatched tags. Good :)
<match **>
  @type blackhole_plugin
</match>

如果需要將輸出到多個(gè)match,需要使用out_copy插件漏麦。

另外需要注意順序的是filtermatch, 如果將filter放在match之后客税,那么它也永遠(yuǎn)不會(huì)生效,正確的用法如下:

# You should NOT put this <filter> block after the <match> block below.
# If you do, Fluentd will just emit events without applying the filter.
<filter myapp.access>
  @type record_transformer
  ...
</filter>

<match myapp.access>
  @type file
  path /var/log/fluent/access
</match>

常見的配置文件示例

下面給出了一些常見的使用場景的配置文件寫法

簡單的輸入撕贞,過濾更耻,輸出

<source>
  @type forward
</source>

<filter app.**>
  @type record_transformer
  <record>
    hostname "#{Socket.gethostname}"
  </record>
</filter>

<match app.**>
  @type file
  # ...
</match>

多個(gè)輸入

<source>
  @type forward
</source>

<source>
  @type tail
  tag system.logs
  # ...
</source>

<filter app.**>
  @type record_transformer
  <record>
    hostname "#{Socket.gethostname}"
  </record>
</filter>

<match {app.**,system.logs}>
  @type file
  # ...
</match>

使用Label的輸出

<source>
@type forward
</source>

<source>
  @type dstat
  @label @METRICS # dstat events are routed to <label @METRICS>
  # ...
</source>

<filter app.**>
  @type record_transformer
  <record>
    # ...
  </record>
</filter>

<match app.**>
  @type file
  # ...
</match>

<label @METRICS>
  <match **>
    @type elasticsearch
    # ...
  </match>
</label>

重新設(shè)置標(biāo)簽并重新路由(fluent-plugin-route插件的使用)

<match worker.**>
  @type route
  remove_tag_prefix worker
  add_tag_prefix metrics.event

  <route **>
    copy # For fall-through. Without copy, routing is stopped here.
  </route>
  <route **>
    copy
    @label @BACKUP
  </route>
</match>

<match metrics.event.**>
  @type stdout
</match>

<label @BACKUP>
  <match metrics.event.**>
    @type file
    path /var/log/fluent/bakcup
  </match>
</label>

根據(jù)事件內(nèi)容重新路由(fluent-plugin-rewrite-tag-filter插件的使用)

<source>
  @type forward
</source>

# event example: app.logs {"message":"[info]: ..."}
<match app.**>
  @type rewrite_tag_filter
  <rule>
    key message
    pattern ^\[(\w+)\]
    tag $1.${tag}
  </rule>
  # you can put more <rule>
</match>

# send mail when receives alert level logs
<match alert.app.**>
  @type mail
  # ...
</match>

# other logs are stored into file
<match *.app.**>
  @type file
  # ...
</match>

重新路由事件到其它的Label(out_relabel插件的使用)

<source>
  @type forward
</source>

<match app.**>
  @type copy
  <store>
    @type forward
    # ...
  </store>
  <store>
    @type relabel
    @label @NOTIFICATION
  </store>
</match>

<label @NOTIFICATION>
  <filter app.**>
    @type grep
    regexp1 message ERROR
  </filter>

  <match app.**>
    @type mail
  </match>
</label>

配置文件中的參數(shù)類型

在配置文件中使用的插件,大部分都可以接受1個(gè)或多個(gè)參數(shù)捏膨,也可以指定參數(shù)類型

  • string: 字符串類型

  • integer: 整型

  • float: 浮點(diǎn)型

  • size: 字節(jié)(bytes)類型.為了便于閱讀秧均,它的值有幾種常見的寫法

    • <INTEGER>k<INTEGER>K 表示使用單位KB
    • <INTEGER>m<INTEGER>M 表示使用單位M
    • <INTEGER>g<INTEGER>G 表示使用單位G
    • <INTEGER>t<INTEGER>T 表示使用單位T
    • 純數(shù)字時(shí)表示使用默認(rèn)單位為B
  • time: 時(shí)間類型食侮,默認(rèn)單位為秒, 同樣為了便于閱讀目胡,它的值也有幾種常見的寫法

    • <INTEGER>s, 表示使用單位
    • <INTEGER>m, 表示使用單位分鐘
    • <INTEGER>h, 表示使用單位小時(shí)
    • <INTEGER>d, 表示使用單位
    • 純數(shù)字時(shí)表示使用默認(rèn)單位為锯七, 0.1表示100ms
  • array: 數(shù)組類型。有兩種寫法:

    • 完整格式的寫法: ["key1", "key2"]
    • 簡寫: key1,key2
  • hash: 字典類型誉己。也有兩種寫法:

    • 完整格式的寫法: {"key1":"value1", "key2":"value2"}
    • 簡寫: key1:value1,key2:value2

常見的參數(shù)

@開始的參數(shù)表示fluented的保留參數(shù)

  • @type: 指定使用的參加類型
  • @id: 指定插件的ID
  • @label: 指定事件的標(biāo)識(shí)符
  • @log_level: 指定類型

模塊(section)支持

下面的模塊并不是所有的插件都支持眉尸,具體使用請(qǐng)結(jié)合使用的插件查看

  • parse: 指明如何解析原始內(nèi)容,如解析nginx, apache日志等
  • buffer: 配置如何緩沖輸出
  • format: 配置如何格式化事件
  • extract: 從事件中提取值
  • inject: 向事件注入一些屬性
  • transport: 用于指定某些插件的輸入輸出時(shí)server的連接信息
  • storage: 指定如何保存插件本身的狀態(tài)

每個(gè)模塊都有對(duì)應(yīng)的插件巨双,使用詳情可以查看官方文檔

檢查配置文件的格式

可以使用下面的命令檢查配置文件的格式是否正確

$ docker run --rm -v $(pwd)/etc:/fluentd/etc/ fluent/fluentd:v1.7-1 --dry-run -c /fluentd/etc/fluentd_basic_setup.conf

使用Fluentd收集docker容器的日志

docker容器日志格式

在使用fluentd收集docker日志時(shí)噪猾,默認(rèn)會(huì)將日志分成4個(gè)部分:

分別是:

  • container_id: 容器的ID
  • container_name:容器的名字
  • source: 日志的類型,stdoutstderr
  • log: 日志本身

收集Docker容器的日志示例

  1. 首先創(chuàng)建一個(gè)配置文件etc/fluentd_docker.conf
<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>
<match **>
    @type stdout
</match>
# 啟動(dòng)一個(gè)fluentd服務(wù)
$ docker run -it -p 24224:24224 -v $(pwd)/etc:/fluentd/etc/ -e FLUENTD_CONF=fluentd_docker.conf fluent/fluentd:v1.7-1

# 啟動(dòng)一個(gè)docker容器并使用fluentd收集日志
$ docker run --log-driver=fluentd -p 5000:80 httpd

# 訪問服務(wù)產(chǎn)生日志
$ curl http://127.0.0.1:5000
<html><body><h1>It works!</h1></body></html>

在fluentd的容器日志里筑累,能看到下面的輸出

2019-11-28 01:43:23.000000000 +0000 8da5b8365552: {"container_id":"8da5b8365552b4c0c610ff5df3dc28509bfc5781ec580628143b00cf997d5b72","container_name":"/confident_curie","source":"stdout","log":"172.17.0.1 - - [28/Nov/2019:01:43:23 +0000] \"GET / HTTP/1.1\" 200 45"}

在docker-compose中使用示例

為了介紹下對(duì)日志常用的處理場景袱蜡,這里將收集的日志分成三部分:

  • 輸出到fluentd的容器的標(biāo)準(zhǔn)輸出,方便直接查看
  • 保存一份到文件慢宗,按照日期自動(dòng)切割日志
  • 保存一份到Elasticsearch坪蚁,方便通過Kibana面板直接查看

同時(shí)為了方便人查看,輸出到fluentd標(biāo)準(zhǔn)輸出和保存到日志文件的镜沽,只顯示log字段的信息(不用contanier_id, container_name等暫時(shí)不關(guān)心的信息)迅细,保存到Elastisearch的日志保存完整的結(jié)構(gòu)。

首先淘邻,根據(jù)我們上面的需求,創(chuàng)建fluentd配置文件

$ cat etc/fluentd_docker_compose.conf
<source>
    @type forward
    port 24224
    bind 0.0.0.0
</source>

# docker相關(guān)的日志處理
<match docker.**>
    # docker相關(guān)的日志輸出三份湘换,一份輸出到fluentd容器的標(biāo)準(zhǔn)輸出宾舅,便于實(shí)時(shí)查看,另一份保存到文件, 還有一份保存到Elasticsearch
    @type copy

    # 輸出到標(biāo)準(zhǔn)輸出
    <store>
        @type stdout
        # 默認(rèn)輸出的格式是json格式彩倚,由于docker生成的日志筹我,包含了容器信息等其他信息,不是很方便人去閱讀帆离。
        # 這里只輸出我們關(guān)心的log字段
        # 使用stdout作為主format蔬蕊,single_value為子format,這樣可以在輸出log的同時(shí)保留直接tag和time信息
        <format>
           @type stdout
           output_type single_value
           message_key log
           add_newline true
        </format>
    </store>

    # 輸出到文件
    <store>
        @type file
        # 使用tag和日期作為保存日志的文件名
        path /fluentd/log/${tag}/%Y%m%d
        # 合并多個(gè)flush chunk塊到一個(gè)文件
        append true
        # 使用gzip壓縮生成的日志文件
        compress gzip
        <format>
            @type stdout
            output_type single_value
            message_key log
            add_newline true
        </format>
        # 使用文件作為緩沖區(qū)
        <buffer tag, time>
            @type file
            chunk_limit_size 1M
            # 每隔1分鐘寫一次日志
            flush_interval 1m
            flush_at_shutdown true
            flush_mode interval
        </buffer>
    </store>

    # 輸出到Eleastichsearch
    <store>
       @type elasticsearch
       host elasticsearch
       port 9200
       logstash_format true
       logstash_prefix fluentd
       logstash_dateformat %Y%m%d
       include_tag_key true
       type_name access_log
       tag_key @log_name
    </store>
</match>

# 其它日志處理
<match **>
    @type copy

    <store>
        @type stdout
    </store>

    # 輸出到others目錄
    <store>
        @type file
        path /fluentd/log/others/${tag}/%Y%m%d
        append true
        <buffer tag, time>
            @type file
            chunk_limit_size 1M
            flush_interval 1m
            flush_at_shutdown true
            flush_mode interval
        </buffer>
    </store>
</match>

由于使用到了elasticsearch輸出插件哥谷,而默認(rèn)的fluentd中并沒有安裝這個(gè)插件岸夯,因此,我們需要自己定義Dockfile來安裝elasticsearch插件

$ cat fluentd/Dockerfile

FROM fluent/fluentd:v1.7-1
USER root
RUN ["fluent-gem", "install", "fluent-plugin-elasticsearch"]
USER fluent

最后創(chuàng)建docker-compose.yaml文件

$ cat docker-compose.yaml
version: '3'
services:
  httpd:
    image: httpd
    ports:
      - "5000:80"
    networks:
      - webnet
    depends_on:
      - fluentd
    logging:
      driver: fluentd
      options:
        fluentd-address: "localhost:24224"
        fluentd-retry-wait: '1s'
        fluentd-max-retries: '10'
        tag: docker.httpd

  fluentd:
    build: ./fluentd/
    volumes:
      - ./etc/:/fluentd/etc
      - ./log/:/fluentd/log
    ports:
      - "24224:24224"
      - "24224:24224/udp"
    environment:
      - FLUENTD_CONF=fluentd_docker_compose.conf
    networks:
      - webnet
    depends_on:
      - elasticsearch
      - kibana

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.3
    ports:
      - "9200:9200"
    networks:
      - webnet
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      - discovery.type=single-node
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - http.host=0.0.0.0
      - transport.host=127.0.0.1
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - es_data:/usr/share/elasticsearch/data

  kibana:
    image: docker.elastic.co/kibana/kibana-oss:6.2.3
    environment:
      SERVER_NAME: kibana-server
      ELASTICSEARCH_URL: http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - webnet

networks:
  webnet:

volumes:
  es_data:
    driver: local

最后啟動(dòng)服務(wù)

$ docker-compose up --build

實(shí)際使用中發(fā)現(xiàn)们妥,采用上面的方式啟動(dòng)服務(wù)后猜扮,有時(shí)間fluentd沒法收集到httpd服務(wù)的日志,最后發(fā)現(xiàn)原因是如果在fluentd服務(wù)還沒準(zhǔn)備就緒的情況下就啟動(dòng)httpd服務(wù)监婶,就會(huì)產(chǎn)生這種現(xiàn)象旅赢。因此齿桃,建議的做法是先啟動(dòng)fluentd, 再啟動(dòng)httpd

$ docker-compose up --build fluentd
# 等fluentd服務(wù)就緒后,再啟動(dòng)httpd服務(wù)
$ docker-compose up httpd

當(dāng)然更優(yōu)雅點(diǎn)的做法是控制docker-compose中服務(wù)的啟動(dòng)順序煮盼,具體可以參考:

https://docs.docker.com/compose/startup-order/

測(cè)試短纵,訪問 httpd服務(wù)

# 可以多執(zhí)行幾次,產(chǎn)生多一些訪問記錄
$ curl http://127.0.0.1:5000

最后可以分別在fluentd的容器的終端僵控,log目錄香到,以及elasticsearch中看到保存的訪問記錄信息了。如下是通過Kibana面板看到的請(qǐng)求情況

Kibana面板

更多

更多關(guān)于Fluentd的使用方式可以參考官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末喉祭,一起剝皮案震驚了整個(gè)濱河市养渴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌泛烙,老刑警劉巖理卑,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蔽氨,居然都是意外死亡藐唠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門鹉究,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宇立,“玉大人,你說我怎么就攤上這事自赔÷栲冢” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵绍妨,是天一觀的道長润脸。 經(jīng)常有香客問我,道長他去,這世上最難降的妖魔是什么毙驯? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮灾测,結(jié)果婚禮上爆价,老公的妹妹穿的比我還像新娘。我一直安慰自己媳搪,他們只是感情好铭段,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秦爆,像睡著了一般稠项。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鲜结,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天展运,我揣著相機(jī)與錄音活逆,去河邊找鬼。 笑死拗胜,一個(gè)胖子當(dāng)著我的面吹牛蔗候,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播埂软,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锈遥,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了勘畔?” 一聲冷哼從身側(cè)響起所灸,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炫七,沒想到半個(gè)月后爬立,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡万哪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年侠驯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奕巍。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吟策,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出的止,到底是詐尸還是另有隱情檩坚,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布诅福,位于F島的核電站匾委,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏权谁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一憋沿、第九天 我趴在偏房一處隱蔽的房頂上張望旺芽。 院中可真熱鬧,春花似錦辐啄、人聲如沸采章。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悯舟。三九已至,卻和暖如春砸民,著一層夾襖步出監(jiān)牢的瞬間抵怎,已是汗流浹背奋救。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留反惕,地道東北人尝艘。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像姿染,于是被迫代替她去往敵國和親背亥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355