1、搭建服务

1、搭建ElasticSearch

# 下载tar包
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.13.1.tar.gz 
# 解压缩
tar -zxvf elasticsearch-7.13.1.tar.gz 
# 放入文件路径中
mv elasticsearch-7.13.1 /usr/local/elasticsearch

修改配置文件

cd /usr/local/elasticsearch/config
vim elasticsearch.yml

在文件下面加入以下几行:

network.host: 0.0.0.0
http.port: 9200
http.cors.enabled: true
http.cors.allow-origin: "*"

创建elsearch用户组及用户

groupadd elsearch
useradd elsearch -g elsearch -p elasticsearch

elasticsearch文件的所属用户及其组改成elsearch:elsearch

cd /usr/local/
chown -R elsearch:elsearch elasticsearch

启动es

su elsearch
cd /usr/local/elasticsearch
nohup sh ./bin/elasticsh &

2、搭建kibana

文件下载和解压

wget https://artifacts.elastic.co/downloads/kibana/kibana-7.13.1-linux-x86_64.tar.gz
# 解压缩
tar -zxvf kibana-7.13.1.tar.gz 
# 放入文件路径中
mv kibana-7.13.1 /usr/local/kibana

修改配置文件:

vim /usr/local/kibana/config/kibana.yml

加上如下配置

# kibana web端口
server.port: 5601  
# 服务地址
server.host: "0.0.0.0"
# elasticsearch地址信息
elasticsearch.url: "http://127.0.0.1:9200"

启动kibana

nohup sh /usr/local/kibana/bin/kibana &

3、搭建Logstash

Logstash可以直接获取本地的日志文件然后上传到Elasticsearch中,logstash处理日志有三个过程:

  1. 获取数据,Input
  2. 过滤数据,Filter
  3. 输出数据,Output

Logstash的开销比较大,一般不推荐直接在生产机上部署。在生产环境一般来说用FileBeat作为一个轻量级的数据采集工具,将采集到的数据给到Rediskafka,或者直接给到Logstash。然后Logstash用来过滤数据后返回给到Elasticsearch

文件下载和解压

wget https://artifacts.elastic.co/downloads/logstash/logstash-7.13.1-linux-x86_64.tar.gz
# 解压缩
tar -zxvf logstash-7.13.1.tar.gz 
# 放入文件路径中
mv logstash-7.13.1 /usr/local/logstash

修改配置文件

vim /usr/local/logstash/conf/logstash.conf

加入一下内容


input {
   // .....
}
filter {
 // ....
}
output {
  // ..
}

1、数据输入

1、读取文件

file { # 从文件中来
        path => "E:/software/logstash-1.5.4/logstash-1.5.4/data/*" #单一文件
         #监听文件的多个路径
        path => ["E:/software/logstash-1.5.4/logstash-1.5.4/data/*.log","F:/*.log"]
        #排除不想监听的文件
        exclude => "1.log"
        #添加自定义的字段
        add_field => {"test"=>"test"}
        #增加标签
        tags => "tag1
        #设置新事件的标志
        delimiter => "\n"
        #设置多长时间扫描目录,发现新文件
        discover_interval => 15
        #设置多长时间检测文件是否修改
        stat_interval => 1
         #监听文件的起始位置,默认是end
        start_position => beginning
        #监听文件读取信息记录的位置
        sincedb_path => "E:/software/logstash-1.5.4/logstash-1.5.4/test.txt"
        #设置多长时间会写入读取的位置信息
        sincedb_write_interval => 15
}

2、读取数据库

input{
        jdbc{
        #jdbc sql server 驱动,各个数据库都有对应的驱动,需自己下载
        jdbc_driver_library => "/etc/logstash/driver.d/sqljdbc_2.0/enu/sqljdbc4.jar"
        #jdbc class 不同数据库有不同的 class 配置
    jdbc_driver_class => "com.microsoft.sqlserver.jdbc.SQLServerDriver"
        #配置数据库连接 ip 和端口,以及数据库
        jdbc_connection_string => "jdbc:sqlserver://200.200.0.18:1433;databaseName=test_db"
        #配置数据库用户名
        jdbc_user =>
        #配置数据库密码
        jdbc_password =>
        #上面这些都不重要,要是这些都看不懂的话,你的老板估计要考虑换人了。重要的是接下来的内容。
        # 定时器 多久执行一次SQL,默认是一分钟
        # schedule => 分 时 天 月 年
        # schedule => * 22  *  *  * 表示每天22点执行一次
        schedule => "* * * * *"
        #是否清除 last_run_metadata_path 的记录,如果为真那么每次都相当于从头开始查询所有的数据库记录
        clean_run => false
        #是否需要记录某个column 的值,如果 record_last_run 为真,可以自定义我们需要表的字段名称,
        #此时该参数就要为 true. 否则默认 track 的是 timestamp 的值.
        use_column_value => true
        #如果 use_column_value 为真,需配置此参数. 这个参数就是数据库给出的一个字段名称。当然该字段必须是递增的,可以是 数据库的数据时间这类的
        tracking_column => create_time
        #是否记录上次执行结果, 如果为真,将会把上次执行到的 tracking_column 字段的值记录下来,保存到 last_run_metadata_path 指定的文件中
        record_last_run => true
        #们只需要在 SQL 语句中 WHERE MY_ID > :last_sql_value 即可. 其中 :last_sql_value 取得就是该文件中的值
        last_run_metadata_path => "/etc/logstash/run_metadata.d/my_info"
        #是否将字段名称转小写。
        #这里有个小的提示,如果你这前就处理过一次数据,并且在Kibana中有对应的搜索需求的话,还是改为true,
        #因为默认是true,并且Kibana是大小写区分的。准确的说应该是ES大小写区分
        lowercase_column_names => false
        #你的SQL的位置,当然,你的SQL也可以直接写在这里。
        #statement => SELECT * FROM tabeName t WHERE  t.creat_time > :last_sql_value
        statement_filepath => "/etc/logstash/statement_file.d/my_info.sql"
        #数据类型,标明你属于那一方势力。单了ES哪里好给你安排不同的山头。
        type => "my_info"
        }
        #注意:外载的SQL文件就是一个文本文件就可以了,还有需要注意的是,一个jdbc{}插件就只能处理一个SQL语句,
        #如果你有多个SQL需要处理的话,只能在重新建立一个jdbc{}插件。
}

3、读取redis

input {
  redis {
    host => "192.168.10.1"
    port => "6379"
    db => "0"
    key => "filebeat"
    data_type => "list"
  }
}

4、读取Kafka

1、aop对日志进行收集,然后通过kafka发送出去,发送的时候,指定了topic(在spring配置文件中配置为 topic="mylog_topic")

2、logstash指定接手topic为 mylog_topic的kafka消息(在config目录下的配置文件中,有一个input的配置)

3、然后logstash还定义了将接收到的kafka消息,写入到索引为my_logs的库中(output中有定义)

input {
  kafka {
    bootstrap_servers => "192.168.113.101:9092,192.168.113.102:9092,192.168.113.103:9092"
    topic_id => "mylog_topic" ## 订阅的topic
 }
}

5、beats读取

input {
        beats {
        #接受数据端口
        port => 5044
        #数据类型
        type => "logs"
    }
}

关键配置:

  • path,在file类型中必填参数,指定读取日志位置
  • exclude,排除不想监听的文件
  • start_position,监听位置,默认为end,即一个文件如果没有记录它的读取信息,则从文件的末尾开始读取,也就是说,仅仅读取新添加的内容。
  • add_filed,在es的索引中添加一个字段
  • tags,添加标签

2、Codecs

Logstash不只是一个input|filter|output的数据流,而是一个

input->decode->filter->encode->output的数据流。

codec就是用来decode,encode 事件的。所以codec常用在input和output中

常用的codec插件有plain,json,multiline等

1、plain

plain是最简单的编码插件,你输入什么信息,就返回什么信息

2、json

如果数据为json格式,可直接使用该插件,从而省掉filter/grok的配置,降低过滤器的cpu消耗.数据内容较长时采用json_lines

input {
    beats {
        codec => json
    }
}

3、multiline

一般用来解析JAVA日志的功能,用在数据输入处。一般来说日志是按行来读取的,但是JAVA中的异常日志中含有异常堆栈信息,堆栈信息是有多行的。所以需要用multiline来解析。

如下面的一组日志:

2020-09-25 20:12:51,872 qtp2094548358-30 ERROR star.web.login.InnerServerLoginController:183 :: 登录异常
java.lang.NullPointerException
	at star.web.login.InnerServerLoginController.doLogin(InnerServerLoginController.java:173)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:178).....

采集方式需要配合多行采集:

input {
    file {
        path => "/home/dockermount/jinyiwei/logs/catalina.out" # 日志路径
        codec => multiline {
            pattern => "^%{TIMESTAMP_ISO8601}"  # 正则表达式,匹配开头为时间戳的日志
            negate => true     # true表示若pattern正则匹配失败,则执行合并;false表示若pattern正则匹配失败,则执行合并。默认为false
            what => "previous"   # previous表示跟前面的行合并;next表示跟后面的行合并
            auto_flush_interval => 10
        }
}

以下内容表示:所有不满足pattern正则的数据都是属于上一事件的内容,当抽取到满足pattern的数据时则是新的时间内容了,此外如果auto_flush_interval时间内没有数据读取到,那么事件也被读取完成

3、数据过滤

常用的过滤器如下:

  • grok,解析无规则的文字并转化为有结构的格式。
  • mutate,允许改变输入的文档,可以命名,删除,移动或者是修改字段
  • drop,丢弃一部分数据,如debug数据
  • clone,拷贝 event,这个过程中也可以添加或移除字段。
  • geoip,添加地理信息
  • date,转换日期,一般是将日志中的打印时间设置为@timestamp

1、grok的使用

Grok Debugger

语法:

filter {
  grok {
    match => { "message" => "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}" }
  }
}

例如:IP:client,IP就是解析的模板,而解析出来的数据放入到client域中。

常用模板有:

  1. IP,匹配IPV4,IPV6

  2. MAC,匹配MAC地址

  3. DATA,匹配*

  4. WORD,匹配大小写的字符串

  5. QS,匹配带引号的字符串

  6. EMAILADDRESS,匹配邮箱

  7. NUMBER,数字

  8. UUID,唯一标识符如 9584dba3-fe26-418d-8625-2d71a5d78049

  9. PATH ,匹配目录地址

  10. LOGLEVEL ,日志等级

  11. MONTH       //月份名称,如:Jan、January
    MONTHNUM    //月份数字,如:06、1、12
    MONTHDAY    //日期数字,如:15、29、31、09
    DAY         //星期几,如:Tues、Friday
    YEAR        //年份数字,如:2017、1995
    HOUR        //小时数字,如:24、13
    MINUTE      //分钟数字,如:13、59
    SECOND      //秒钟数字,如:12、54
    TIME        //时间,如:12:34:12
    DATE_US     //美国日期格式,如:10-15-1982、10/15/1982
    DATE_EU     //欧洲日期格式,如:15-10-1982、15.10.1982
    TIMESTAMP_ISO8601 //ISO8601时间戳格式,如:2016-07-03T00:34:06+08:00
    

例如:

2020-09-25 18:46:02,142 nioEventLoopGroup-2-1 INFO  com.taobao.diamond.httpclient.HttpClient:133 :: NETTY CLIENT PIPELINE: CLOSE 10.85.159.226:8889

解析如下:

%{TIMESTAMP_ISO8601:date} %{DATA:thread} %{LOGLEVEL:level} %{DATA:method} :: 

2、mutate使用

常用于在日志中抽取出需要用的数据,使用释放如下:

filter {
	mutate {
		split => ["message"," "]
		add_field => { "level" => "%{[message][3]}" }
	}
	mutate {
		join => ["message", " "]
	}
}

​ 上述脚本将日志的Level字段取出来,并放入索引的level域中。因为前面对message数据进行了切分所以下面采用了join将数组再次合并。

常用的方法:

  1. split,切分数据
  2. add_filed,添加域
  3. join,数据组合
  4. gsub,正则替换

4、数据输出

一般来说都是固定的将数据转换后发送给ElasticSearch中。

output{
	elasticsearch {
		hosts => ["192.168.2.101:9200","192.168.2.102:9201"]
		index => "%{project}"
	}
	stdout {
		codec  => rubydebug
	}
}

5、Logstash使用ILM

当我们使用ELK搭建索引日志系统时,咋让Logstash和ES的ILM无缝连接呢? Logstash的Elasticsearch output plugin插件自从9.3.1版本之后就支持ILM了,我们只需要在Logstash的配置文件中简单配置下就可以全部托管给ES ILM了。

 output {
      elasticsearch {
		//发生rollover时的写入索引的别名
        ilm_rollover_alias => "myindex"
		//将会附在ilm_rollover_alias的值后面共同构成索引名,myindex-00001
        ilm_pattern => "00001"
		//使用的索引策略
        ilm_policy => "my_policy"
		//使用的索引模版名称
        template_name => "my_template"
      }
}

4、搭建FileBeats

[Configure inputs | Filebeat Reference 7.13] | Elastic

FileBeats是一个简单的数据采集的工具,他可以将采集的数据直接发送给elasticsearchrediskafkalogstash

一个简单的数据采集配置

# ------------------------------ Filbeat Input ---------	----------------------
filebeat.inputs:
- type: log 
  paths:
    - /var/log/system.log
    - /var/log/wifi.log
  fields:
    project: project1 
- type: log 
  paths:
    - "/var/log/apache2/*"
  fields:
    project: project2
    
# ------------------------------ Logstash Output ---------	----------------------
output.logstash:
  hosts: ["127.0.0.1:5044"]

采集多行数据配置:

如这样的日志:

2020-09-25 18:44:16,270 main INFO  com.taobao.diamond.client.impl.DefaultDiamondSubscriber:536 :: 获取配置数据,第1次尝试, waitTime:0

配置:

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /root/logs/employment/*
    - /root/logs/*
    - /root/logs/oauth/*
  #以文件末尾开始读取数据,默认认为之前的数据已经加载过了。只加载刷新数据
  tail_files: true 
  multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
  # 不符合正则表达式的都是上一个事件
  multiline.negate: true
  multiline.match: after

如果是这样的日志:

Exception in thread "main" java.lang.IllegalStateException: A book has a null property
       at com.example.myproject.Author.getBookIds(Author.java:38)
       at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
       at com.example.myproject.Book.getId(Book.java:22)
       at com.example.myproject.Author.getBookIds(Author.java:35)
       ... 1 more

则可以这样写:

multiline.pattern: '^[[:space:]]+(at|\.{3})\b|^Caused by:'
## 符合正则的都是上一个事件
multiline.negate: false
multiline.match: after

1、输出到Logstash

FileBeat配置:

filebeat.inputs:
- input_type: log
  paths:
    - /data/logs/company/logs/*.log
  exclude_files: ['.gz$','INFO']
  multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
  multiline.negate: true
  multiline.match: after
  tags: ["company"]

- input_type: log
  paths:
    - /data/logs/store/logs/*.log
  exclude_files: ['.gz$','INFO']
  multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
  multiline.negate: true
  multiline.match: after
  tags: ["store"]

output.logstash:
  hosts: ["192.168.0.144:5044"]
  enabled: true
  worker: 2
  compression_level: 3

2、输出到redis

FileBeat配置:

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log
  json.keys_under_root: true
  json.overwrite_keys: true
  tags: ["access"]

- type: log
  enabled: true
  paths:
    - /var/log/nginx/error.log
  tags: ["error"]

setup.template.settings:
  index.number_of_shards: 5

setup.kibana:
  hosts: ["192.168.10.8"]

output.redis:
  hosts: ["192.168.10.1"]
  key: "filebeat"
  db: 0
  timeout: 5

logstash配置

input {
  redis {
    host => "192.168.10.1"
    port => "6379"
    db => "0"
    key => "filebeat"
    data_type => "list"
  }
}

filter {
  mutate {
    convert => ["upstream_time","float"]
    convert => ["request_time","float"]
  }
}

output {
  elasticsearch {
    hosts => ["http://192.168.10.8:9200"]
    index => "nginx_access-%{+YYYY.MM}"
    manage_template => false
  }
}

3、输出到kafka

filebeats配置

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/messages
    - /var/log/secure
fields:
    log_topic: osmessages
name: "192.168.113.99"
output.kafka:
  enabled: true
  hosts: ["192.168.113.101:9092", "192.168.113.102:9092", "192.168.113.103:9092"]
  version: "0.10"
  topic: '%{[fields][log_topic]}'
  partition.round_robin:
    reachable_only: true
  worker: 2
  required_acks: 1
  compression: gzip
  max_message_bytes: 10000000
logging.level: info

logstash配置

input {
    kafka {
        bootstrap_servers => "192.168.113.101:9092,192.168.113.102:9092,192.168.113.103:9092"
        topics => ["osmessages"]
        codec => "json"
          }
      }
            
output {
    elasticsearch {
        hosts => ["192.168.113.107:9200","192.168.113.108:9200","192.168.113.109:9200"]
        index => "osmessageslog-%{+YYYY-MM-dd}"
     }
 }
2、解析日志

1、解析java日志

日志格式类似如下:

2020-11-19 00:04:36,893 pool-2-thread-1 INFO  com.taobao.diamond.client.processor.ServerAddressProcessor:320 :: 没有可用的新服务器列表, RemoteAddress:[10.85.159.226:8889], RequestURI:[/ServerNodes], RequestMethod:[GET], StatusCode:[200]

分别是:

时间 现场id Level 日志堆栈地址 :: 日志体内容

1、FileBeats配置

- document_type: java
  paths:
    - /var/log/java/log #日志文件地址
  input_type: log #从文件中读取
  tail_files: true #以文件末尾开始读取数据
  multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
  multiline.negate: true
  multiline.match: after
  • multiline:合并多行日志
  • pattern:匹配规则
  • match:从该行开始向什么反向匹配
  • negate:是否开始新记录

2、Logstash配置

filter {
    mutate{
    	split=>["message"," "]
    	add_field => {"level"=>"%{[message][3]}"}
    }
    mutate {
		join => ["message", " "]
	}
	grok {
		match => { "message" => "%{TIMESTAMP_ISO8601:time}" }
	}
	date {
		match => ["time","ISO8601"]
	}
}

最后从Kibana上可以看到如下的数据:

ELK平台搭建笔记_数据

时间和日志等级都解析出来了