Logstash实践

Logstash简介

一个开源的数据收集引擎,具有实时数据传输能力,可以统一过滤来自不同源的数据,并按照开发者制定的规范输出到目的地。

顾名思义,Logstash 收集数据对象就是日志文件,由于日志文件来源众多(如,系统日志,服务器日志等),且内容杂乱,不便于人类进行观察。因此,可以使用Logstash对日志文件进行收集和统一过滤,变成可读性高的内容。

组成结构

Logstash 通过管道进行运作,管道有两个必需的元素,输入和输出,还有一个可选的元素:过滤器

输入插件从数据源读取数据,过滤器插件根据用户指定的数据格式修改数据,输出插件则将数据写入到目的地,如下图

接下来讲解一个工作中的实例。

需求概述

本次需求如下:

统一各语言日志格式

将各个项目生成的日志进行过滤分析存入Elasticsearch

解决方案

统一log格式

因小组内测试代码语言较多(go/java/shell/python等),为了简化更确切的应该是统一过滤规则,首先需要统一日志格式。

熟悉java语言的童鞋对log4j一定不陌生,log4j可以控制日志信息输送的目的地,控制日志的输出格式,日志级别,而且这些只需一个配置文件即可灵活配置,无需修改代码。

那么go,python,shell是否有类似的框架呢,答案是肯定的,它们分别是log4go,log4p,log4sh

我们先来统一日志格式,根据以往经验及今后扩展,日志格式如下:

时间 - 日志级别 - 日志logid- 文件名及行数 - 日志内容

2018-07-09 15:50:35,907 [DEBUG] logid:000 demo.py:fun1:10 Type some log.

此处对各语言log4日志框架不详细说明,可参见本人实现的demo:https://github.com/tianruiMM/log4pgoshj 查看各语言日志模版

其他说明:本项目中的bin/init.sh可以根据给定的语言初始化log4相关的项目,可参考脚本中的说明

应用logstash

添加过滤规则

2018-07-09 15:50:35,907 [DEBUG] logid:000 demo.py:fun1:10 Type some log.

统一日志格式后,接下来将每行日志转换成结构化的日志,在Logstash中,这项工作由logstash-filter-grok来完成,它有超过200个可用的,大家都认为比较有用的Grok模式,例如IPv6地址,UNIX路径等。

使用Grok库,我们可以很容易的就完成日志格式化提取的任务

%{TIMESTAMP_ISO8601:timestamp}\s+\[%{LOGLEVEL:loglevel}\]\s+%{DATA:logid}\s+%{DATA:method}\s+%{GREEDYDATA:msg}


提取后的数据格式如下:

{

  "timestamp": [

    "2018-07-09 15:50:35,907"

  ],

  "loglevel": [

    "DEBUG"

  ],

  "logid": [

    "logid:000"

  ],

  "method": [

    "demo.py:fun1:10"

  ],

  "msg": [

    "Type some log."

  ]

}

Grok部分模式对应的正则如下:

TIMESTAMP_ISO8601:%{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?

LOGLEVEL:([A-a]lert|ALERT|[T|t]race|TRACE|[D|d]ebug|DEBUG|[N|n]otice|NOTICE|[I|i]nfo|INFO|[W|w]arn?(?:ing)?|WARN?(?:ING)?|[E|e]rr?(?:or)?|ERR?(?:OR)?|[C|c]rit?(?:ical)?|CRIT?(?:ICAL)?|[F|f]atal|FATAL|[S|s]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)

DATA:.*?

SPACE:\s* 其中\s+匹配一个或多个空格

grok其它模式说明请参考:http://grokdebug.herokuapp.com/patterns#

备注:可以使用在线调试器Grok Debugger进行调试

生成配置文件

在生产环境中,Logstash的管道要复杂很多,可能需要配置多个输入,过滤器和输出插件。

因此需要一个配置文件管理输入,过滤器和输出相关的配置,配置文件内容格式如下:

# 输入

input {

  ...

}

# 过滤器

filter {

  ...

}

# 输出

output {

  ...

}

在实际测试过程中,日志目录往往配置在当前项目路径下。对于收集单一项目日志,这没有什么问题,但当收集多个项目日志或增加新项目时,每次都需要手动更新input、output内容。为了解决上述问题,首先统一日志放置目录,其次根据目录自动生成配置文件。

本人实现了一个shell脚本:

- 根据给定目录,遍历当前路径下最深子目录;

- 根据子目录列表生成Logstash配置文件

- 根据配置文件及最深子目录列表,启动Logstash Docker容器以启动Logstash服务

精简后的代码如下:

#!/usr/bin/env bash

# 存储最深子目录列表

dir_list=()

# 给定的log根目录

base_dir="/data0/dorylus/local/gitlab/logs"

# logstash目录

conf_path="/data0/dorylus/pipeline"

conf_file="$conf_path/logstash.conf"

# elasticsearch服务

address="127.0.0.1:9200"

# logstash docker image

docker_file="docker.elastic.co/logstash/logstash:6.3.2"

# container name

container_name="logstash"

# 递归读取最深子目录

function read_dir(){

    # echo -e $1

    if [ "`ls $1`" = "" ] || [ `ls -l $1|grep ^d|wc -l` -eq 0 ]

    then

        dir_list[${#dir_list[@]}]=$1

    else

        for file in `ls $1`

        do

            if [ -d $1"/"$file ]

            then

                read_dir $1"/"$file

            fi

        done

    fi

}

# 将根目录下所有最深文件夹写入配置文件

function write_conf_file(){

    # 写入input配置

    echo -e "input {" > $conf_file

    for dir in ${dir_list[@]}

    do

        path=$dir

        # 除根路径的子目录

        obj_dir=${dir:((${#base_dir}+1))}

        # 将/替换成-,type为索引名

        type=${obj_dir//\//-}

        echo "  file {

        path => [\"$path/*.log*\"]

        type => \"$type\"

        start_position => "beginning"

        }"  >> $conf_file


    done

    echo -e "}" >> $conf_file

    # 写入filter配置,过滤日志信息

    echo  "filter {

    grok {

        match => [

            \"message\", \"%{TIMESTAMP_ISO8601:logtime}\s+\[%{LOGLEVEL:loglevel}\]\s+%{DATA:logid}\s+%{DATA:method}\s+%{GREEDYDATA:msg}\",

            \"message\", \"\[%{DATA:logtime}\] *\[%{LOGLEVEL:loglevel}\] *%{DATA:method} * %{GREEDYDATA:msg}\"

        ]

        }

    }" >> $conf_file

    # 写入output配置

    echo -e "output {" >> $conf_file

    for dir in ${dir_list[@]}

    do

        obj_dir=${dir:((${#base_dir}+1))}

        type=${obj_dir//\//-}

        echo "  if [type] == \"$type\" {

        elasticsearch {

        hosts => [\"$address\"]

        index => \"$type-%{+YYYY.MM.dd}\"

        }

    }" >> $conf_file


    done

    echo  "}" >> $conf_file

}

function conf(){

    if [ ! -d $conf_path ];then

        mkdir -p $conf_path

    fi

    read_dir $base_dir

    write_conf_file $dir_list

}

# 启动logstash服务

function start(){

    conf $1

    # echo ${dir_list[*]}

    v_conf=""

    # 根据获取的子目录列表,挂载各子目录

    for dir in ${dir_list[@]}

    do

        v_conf=$v_conf" -v $dir/:$dir/"

    done

    command="sudo docker run --name $container_name --net=host -d  --env XPACK.MONITORING.ELASTICSEARCH.URL=http://$address -v $conf_path/:/usr/share/logstash/pipeline/ $v_conf  $docker_file"

    $command

    # sudo docker run --name $container_name --net=host --rm -ti -v $conf_path/:/usr/share/logstash/pipeline/ -v /data0/dorylus/config/logstash.yml:/usr/share/logstash/config/logstash.yml  $docker_file

}

完整版参见:https://github.com/tianruiMM/log4pgoshj/blob/master/bin/operateLogstash.sh

日志目录如下:

├── durian

│   └── case

│      ├── 20180822-065527_deploy.log

│      ├── 20180823-032739_deploy.log

│      ├── 20180824-041952_deploy.log

│      ├── 20180824-085657_deploy.log

│      ├── 20180824-091059_deploy.log

│      ├── consul.log

│      ├── debug.log

│      ├── error.log

│      ├── FailedCaseId.txt

│      ├── nginx.log

│      └── result.log

└── fig

    └── case

        ├── error.log

        └── info.log

生成的配置文件如下:

input {

  file {

        path => ["/data0/dorylus/local/gitlab/logs/durian/case/*.log*"]

        type => "durian-case"

        start_position => beginning

        }

  file {

        path => ["/data0/dorylus/local/gitlab/logs/fig/case/*.log*"]

        type => "fig-case"

        start_position => beginning

        }

}

filter {

    grok {

        match => [

            "message", "%{TIMESTAMP_ISO8601:logtime}\s+\[%{LOGLEVEL:loglevel}\]\s+%{DATA:logid}\s+%{DATA:method}\s+%{GREEDYDATA:msg}",

            "message", "\[%{DATA:logtime}\] *\[%{LOGLEVEL:loglevel}\] *%{DATA:method} * %{GREEDYDATA:msg}"

        ]

        }

    }

output {

  if [type] == "durian-case" {

        elasticsearch {

        hosts => ["127.0.0.1:9200"]

        index => "durian-case-%{+YYYY.MM.dd}"

        }

    }

  if [type] == "fig-case" {

        elasticsearch {

        hosts => ["127.0.0.1:9200"]

        index => "fig-case-%{+YYYY.MM.dd}"

        }

    }

}

通过kibana查看格式化日志结果:

参考文档:

https://www.jianshu.com/p/86133dd66ca4

https://www.elastic.co/guide/en/logstash/current/index.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容