1.开局一张图
全文架构如上。
注意使用的jdk版本:1.8
2.logstash
个人理解:类似水泵,抽啊抽,把不同服务器上的日志抽取到同一个地方。上手也简单,几行配置的事。
安装
官网下载:Download Logstash Free | Get Started Now | Elastic | Elastic
检验
执行命令:bin/logstash -e 'input { stdin { } } output { stdout {} }'
-e选项允许你在命令行快速配置而不必修改配置文件
Logstash启动之后你可以在屏幕上看到"Pipeline main started",输入hello world并回车:
出现以上信息则为成功。
如果要退出在命令行运行的Logstash可以按CTRL+D组合键。
命令行运行logstash
bin/logstash [options]
--help
来查看相关信息。
-f, --path.config CONFIG_PATH
从给定的文件或目录加载配置文件。如果给定的是目录,目录下的所有文件会按照字母顺序解析为一个文件加载。
--log.level LEVEL
Logstash的日志目录。
--log.level LEVEL
设置日志等级
-r, --config.reload.automatic
监控配置文件的变化,并在其发生变化的是后重载。NOTE:使用SIGHUP信号也可以重载配置文件,默认此配置为false。
更多配置详见官网。
服务方式运行logstash
在生产环境运行logstash建议使用服务的方式运行
进入logsttash的config目录下,修改startup.options文件:
一处是指定启动读取配置文件的目录
一处是指定启动用户和用户组
以root身份执行logstash命令创建服务,该命令位于logstash的bin目录下:system-install
执行完后,会生成一个环境变量文件 /etc/default/logstash
另一个生成的则是主要的服务文件 /etc/systemd/system/logstash.service
启动logstash:
systemctl start logstash
停止logstash:
systemctl stop logstash
日志查看
默认情况下日志会保存在以下两个位置
/var/log/messages
/usr/local/logstash/logs
3.kafka
消息队列,没啥好说的。加上这一层方便后期对日志进行自定义的处理逻辑。
安装
官网下载:Apache Kafka
启动
启动自带的zk
bin/zookeeper-server-start.sh -daemon config/zookeeper.properties
关闭自带的zk
bin/zookeeper-server-stop.sh -daemon config/zookeeper.properties
启动kafka
bin/kafka-server-start.sh -daemon config/server.properties
停止kafka
bin/kafka-server-stop.sh config/server.properties
测试
创建topic:
bin/kafka-topics.sh --create --zookeeper 192.168.59.128:2181 --replication-factor 3 --partitions 3 --topic test
查看主题:
bin/kafka-topics.sh --list --zookeeper 192.168.59.128:2181
发送消息:
bin/kafka-console-producer.sh --broker-list 192.168.59.128:9092 --topic test
消费消息:
bin/kafka-console-consumer.sh --bootstrap-server 192.168.59.128:9092 --from-beginning --topic test.logstash
--from-beginning:会把first主题中以往所有的数据都读取出来。根据业务场景选择是否增加该配置。
--bootstrap-server:生产消息的服务器
配置外网访问
1.修改主机名
hostnamectl set-hostname k8s-master
2.编辑host文件
vi /etc/hosts
3.保存退出后重启服务器,可以看到主机名变了。
4.Kafka 配置文件修改,修改 server.properties 配置文件,需要留意一下 advertised.listeners 要注释掉,listeners 才会有效。
5.修改 zookeeper.connect 配置,如果 Zookeeper 和 Kafka 不在同一台机器,请配置 Zookeeper 地址。
6.客户端 host 配置,在客户端机器修改 host 文件映射到远程外网 IP,内网的 consumer 机器请配置内网 IP 映射。
4.elasticsearch
安装
es官网下载地址:Past Releases of Elastic Stack Software | Elastic
配置
1.配置es用户
[root@localhost bin]# adduser es #添加es用户
[root@localhost bin]# passwd es #设置密码
[root@localhost bin]# chown -R es /opt/elasticsearch-7.12.0 #将对应的文件夹权限赋给该用户
2.配置es外网访问
编辑elasticsearch.yml,添加配置:
network.host: 0.0.0.0
cluster.initial_master_nodes: ["node-1"]
3.配置系统设置
切换到root用户下,编辑 /etc/security/limits.conf 文件,增加配置:
* soft nofile 65536
* hard nofile 65536
增加配置后,用户退出后重新登录生效。
再次编辑 /etc/sysctl.conf 文件,增加配置 vm.max_map_count=262144,保存退出后然后执行 sysctl -p 使其生效。
启动
sh /opt/elasticsearch-7.12.0/bin/elasticsearch
打开浏览器访问 ip:9200,返回一个 json 字符串,es 启动成功!
5.kibana
安装
下载kibana安装包时注意和es的版本保持一致。
官网下载地址:Download Kibana Free | Get Started Now | Elastic | Elastic
修改配置文件
编辑kibana.yml,增加如下配置,注意es的ip:
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://192.168.200.110:9200"]
启动
在kibana的bin目录下执行:
./kibana --allow-root
启动成功后,登录地址:http://192.168.200.110:5601/
6.演示案例
案例基于第一张图,并且假设已经启动好了kafka、es和kibana。
部署业务服务
业务服务只要能出日志文件就行了,这里贴上日志logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<!-- <include resource="org/springframework/boot/logging/logback/base.xml" /> -->
<contextName>demo-logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="logging.maxFileSize" value="10MB"/>
<property name="logging.maxHistory" value="60"/>
<property name="logging.totalSizeCap" value="20GB"/>
<property name="logging.path" value="./logs"/>
<property name="spring.application.name" value="demo-logback"/>
<property name="logging.pattern.file" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %logger - %msg%n"/>
<property name="logging.pattern.console"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<property name="LOG_STASH_HOST" value="192.168.59.128"/>
<!--输出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>${logging.pattern.console}</Pattern>
</encoder>
</appender>
<!--输出到文件,小时分割时间滚动输出-->
<!-- all.log -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${logging.path}/${spring.application.name}/all.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${logging.path}/${spring.application.name}/all/log-all-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<maxHistory>${logging.maxHistory}</maxHistory>
<maxFileSize>${logging.maxFileSize}</maxFileSize>
<totalSizeCap>${logging.maxFileSize}</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${logging.pattern.file}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!--warn.log-->
<appender name="warn-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logging.path}/${spring.application.name}/log_warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${logging.path}/${spring.application.name}/warn/log-warn-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<maxHistory>${logging.maxHistory}</maxHistory>
<maxFileSize>${logging.maxFileSize}</maxFileSize>
<totalSizeCap>${logging.maxFileSize}</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${logging.pattern.file}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--error.log-->
<appender name="error-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logging.path}/${spring.application.name}/log_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${logging.path}/${spring.application.name}/error/log-error-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<maxHistory>${logging.maxHistory}</maxHistory>
<maxFileSize>${logging.maxFileSize}</maxFileSize>
<totalSizeCap>${logging.maxFileSize}</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${logging.pattern.file}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--info.log-->
<appender name="info-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logging.path}/${spring.application.name}/log_info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${logging.path}/${spring.application.name}/info/log-info-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<maxHistory>${logging.maxHistory}</maxHistory>
<maxFileSize>${logging.maxFileSize}</maxFileSize>
<totalSizeCap>${logging.maxFileSize}</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${logging.pattern.file}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--debug.log-->
<appender name="debug-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logging.path}/${spring.application.name}/log_debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${logging.path}/${spring.application.name}/debug/log-debug-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<maxHistory>${logging.maxHistory}</maxHistory>
<maxFileSize>${logging.maxFileSize}</maxFileSize>
<totalSizeCap>${logging.maxFileSize}</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${logging.pattern.file}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="INFO">
<appender-ref ref="error-file"/>
<appender-ref ref="warn-file"/>
<appender-ref ref="info-file"/>
<appender-ref ref="debug-file"/>
<appender-ref ref="file"/>
<appender-ref ref="console"/>
</root>
</configuration>
部署logstash
logstash存在的意义就是抽取业务产生的日志文件。因此需要配置
file-filter-kafka.conf
input {
file {
id => "2"
path => "/opt/logstash/demo/logs/demo-logback/all.log" # 目标文件路径
type => "demo-yuwen-logstash-to-file" # 自定义的值,向此输入处理的所有事件添加一个字段。相当于类型
start_position => "beginning" # 选择 Logstash 开始读取文件的位置:开头或结尾。默认行为将文件视为实时流
codec => multiline {
pattern => "^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d.\d{3}"
negate => true
what => "previous"
auto_flush_interval => 3
}
}
}
filter{
grok{
patterns_dir => ["/opt/logstash/mypatterns/postfix"]
match => {"message" => "%{ttj_info:ttj_date}%{ttj_space:ttj_space}\[%{ttj_info:ttj_thread_info}\]%{ttj_space:ttj_space}%{ttj_info:ttj_log_level}%{ttj_space:ttj_space}%{ttj_info:ttj_package}%{ttj_space:ttj_space}-%{ttj_space:ttj_space}%{ttj_info:ttj_log_content}"}
remove_field => ["ttj_space"]
}
date{
match => ["ttj_date","yyyy-MM-dd HH:mm:ss.SSS"]
}
}
output {
kafka {
bootstrap_servers => "localhost:9092" # kafka集群地址,默认值为 "localhost:9092"。格式为 host1:port1,host2:port2
topic_id => "test.logstash" # kafka的主题
codec => json
}
}
配置中要注意的值:
path:日志文件的目录
codec => multiline :合并异常堆栈日志为一条日志。
pattern:表示匹配的正则
negate:表示正选还是反选,默认为false,如果true,与模式不匹配的消息将构成多行
过滤器的匹配并what应用
what:表示是记录匹配到的日志为上一个时间还是下一个时间
auto_flush_interval:当看到匹配的新行或在这么多秒内没有附加新数据时,多行的累积将转换为事件。没有默认。如果未设置,则没有 auto_flush。单位:秒
patterns_dir :正则语法文件的位置。在filter插件中,我们需要对日志格式进行解析,这里使用的grok正则解析。
正则语法文件 postfix:
ttj_info .* ttj_space ( +)
部署数据存储服务
这个服务用来消费kafka消息,存储消息到es。
springboot整合kafka:Kafka基础概念_Yuwen_forJava的博客-CSDN博客
springboot整合es:elasticsearch 简介、安装与使用_Yuwen_forJava的博客-CSDN博客
在kibana上浏览
使用postman访问业务服务,产生日志。
打开kibana,点击Stack Management,然后新建索引模式:
索引建立好之后,点击如下:
可以看到对应的文档和日志信息都已经被kibana读取到了。
接下来就可以使用kibana定制自己的图表进行展示了。