用SpringBoot+Kafka+ELK轻松完成海量日志收集

整体流程大概如下:

59cb20696db62ad4cf64ceb9bb0945d7.jpeg

服务器准备

在这先列出各服务器节点,方便同学们在下文中对照节点查看相应内容

f97db72b2b1324c780072c34a92b743f.jpeg

SpringBoot项目准备

引入log4j2替换SpringBoot默认log,demo项目结构如下:

8e79ef476481cd885e6b3e24e8733223.jpeg

pom

<dependencies>
&nbsp;&nbsp;&nbsp;&nbsp; <dependency>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <groupId>org.springframework.boot </groupId>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <artifactId>spring-boot-starter-web </artifactId>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--&nbsp;&nbsp;排除spring-boot-starter-logging&nbsp;-->
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <exclusions>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <exclusion>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <groupId>org.springframework.boot </groupId>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <artifactId>spring-boot-starter-logging </artifactId>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </exclusion>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </exclusions>
&nbsp;&nbsp;&nbsp;&nbsp; </dependency>&nbsp;
&nbsp; <!--&nbsp;log4j2&nbsp;-->
&nbsp; <dependency>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <groupId>org.springframework.boot </groupId>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <artifactId>spring-boot-starter-log4j2 </artifactId>
&nbsp; </dependency>&nbsp;
&nbsp;&nbsp;&nbsp; <dependency>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <groupId>com.lmax </groupId>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <artifactId>disruptor </artifactId>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <version>3.3.4 </version>
&nbsp;&nbsp;&nbsp; </dependency>&nbsp;
</dependencies>&nbsp;

log4j2.xml

<?xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"?>
<Configuration&nbsp;status="INFO"&nbsp;schema="Log4J-V2.0.xsd"&nbsp;monitorInterval="600"&nbsp;>
&nbsp;&nbsp;&nbsp;&nbsp; <Properties>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <Property&nbsp;name="LOG_HOME">logs </Property>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <property&nbsp;name="FILE_NAME">collector </property>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <property&nbsp;name="patternLayout">[%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ}]&nbsp;[%level{length=5}]&nbsp;[%thread-%tid]&nbsp;[%logger]&nbsp;[%X{hostName}]&nbsp;[%X{ip}]&nbsp;[%X{applicationName}]&nbsp;[%F,%L,%C,%M]&nbsp;[%m]&nbsp;##&nbsp;'%ex'%n </property>
&nbsp;&nbsp;&nbsp;&nbsp; </Properties>
&nbsp;&nbsp;&nbsp;&nbsp; <Appenders>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <Console&nbsp;name="CONSOLE"&nbsp;target="SYSTEM_OUT">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <PatternLayout&nbsp;pattern="${patternLayout}"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </Console>&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <RollingRandomAccessFile&nbsp;name="appAppender"&nbsp;fileName="${LOG_HOME}/app-${FILE_NAME}.log"&nbsp;filePattern="${LOG_HOME}/app-${FILE_NAME}-%d{yyyy-MM-dd}-%i.log"&nbsp;>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <PatternLayout&nbsp;pattern="${patternLayout}"&nbsp;/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <Policies>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <TimeBasedTriggeringPolicy&nbsp;interval="1"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SizeBasedTriggeringPolicy&nbsp;size="500MB"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </Policies>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <DefaultRolloverStrategy&nbsp;max="20"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </RollingRandomAccessFile>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <RollingRandomAccessFile&nbsp;name="errorAppender"&nbsp;fileName="${LOG_HOME}/error-${FILE_NAME}.log"&nbsp;filePattern="${LOG_HOME}/error-${FILE_NAME}-%d{yyyy-MM-dd}-%i.log"&nbsp;>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <PatternLayout&nbsp;pattern="${patternLayout}"&nbsp;/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <Filters>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <ThresholdFilter&nbsp;level="warn"&nbsp;onMatch="ACCEPT"&nbsp;onMismatch="DENY"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </Filters>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <Policies>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <TimeBasedTriggeringPolicy&nbsp;interval="1"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SizeBasedTriggeringPolicy&nbsp;size="500MB"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </Policies>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <DefaultRolloverStrategy&nbsp;max="20"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </RollingRandomAccessFile>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; </Appenders>
&nbsp;&nbsp;&nbsp;&nbsp; <Loggers>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--&nbsp;业务相关&nbsp;异步logger&nbsp;-->
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <AsyncLogger&nbsp;name="com.bfxy.*"&nbsp;level="info"&nbsp;includeLocation="true">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <AppenderRef&nbsp;ref="appAppender"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </AsyncLogger>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <AsyncLogger&nbsp;name="com.bfxy.*"&nbsp;level="info"&nbsp;includeLocation="true">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <AppenderRef&nbsp;ref="errorAppender"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </AsyncLogger>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <Root&nbsp;level="info">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <Appender-Ref&nbsp;ref="CONSOLE"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <Appender-Ref&nbsp;ref="appAppender"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <AppenderRef&nbsp;ref="errorAppender"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </Root>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; </Loggers>
</Configuration>

IndexController

测试Controller,用以打印日志进行调试

@Slf4j
@RestController
public&nbsp; class&nbsp; IndexController&nbsp;{

&nbsp; @RequestMapping(value&nbsp;=&nbsp; "/index")
&nbsp; public&nbsp;String&nbsp; index()&nbsp;{
&nbsp;&nbsp;InputMDC.putMDC();
&nbsp;&nbsp;
&nbsp;&nbsp;log.info( "我是一条info日志");
&nbsp;&nbsp;
&nbsp;&nbsp;log.warn( "我是一条warn日志");

&nbsp;&nbsp;log.error( "我是一条error日志");
&nbsp;&nbsp;
&nbsp;&nbsp; return&nbsp; "idx";
&nbsp;}


&nbsp; @RequestMapping(value&nbsp;=&nbsp; "/err")
&nbsp; public&nbsp;String&nbsp; err()&nbsp;{
&nbsp;&nbsp;InputMDC.putMDC();
&nbsp;&nbsp; try&nbsp;{
&nbsp;&nbsp;&nbsp; int&nbsp;a&nbsp;=&nbsp; 1/ 0;
&nbsp;&nbsp;}&nbsp; catch&nbsp;(Exception&nbsp;e)&nbsp;{
&nbsp;&nbsp;&nbsp;log.error( "算术异常",&nbsp;e);
&nbsp;&nbsp;}
&nbsp;&nbsp; return&nbsp; "err";
&nbsp;}
&nbsp;
}

InputMDC

用以获取log中的[%X{hostName}]、[%X{ip}]、[%X{applicationName}]三个字段值

@Component
public&nbsp; class&nbsp; InputMDC&nbsp; implements&nbsp; EnvironmentAware&nbsp;{

&nbsp; private&nbsp; static&nbsp;Environment&nbsp;environment;
&nbsp;
&nbsp; @Override
&nbsp; public&nbsp; void&nbsp; setEnvironment(Environment&nbsp;environment)&nbsp;{
&nbsp;&nbsp;InputMDC.environment&nbsp;=&nbsp;environment;
&nbsp;}
&nbsp;
&nbsp; public&nbsp; static&nbsp; void&nbsp; putMDC()&nbsp;{
&nbsp;&nbsp;MDC.put( "hostName",&nbsp;NetUtil.getLocalHostName());
&nbsp;&nbsp;MDC.put( "ip",&nbsp;NetUtil.getLocalIp());
&nbsp;&nbsp;MDC.put( "applicationName",&nbsp;environment.getProperty( "spring.application.name"));
&nbsp;}

}

NetUtil

public&nbsp; class&nbsp; NetUtil&nbsp;{&nbsp;&nbsp;&nbsp;
&nbsp;
&nbsp; public&nbsp; static&nbsp;String&nbsp; normalizeAddress(String&nbsp;address){
&nbsp;&nbsp;String[]&nbsp;blocks&nbsp;=&nbsp;address.split( "[:]");
&nbsp;&nbsp; if(blocks.length&nbsp;>&nbsp; 2){
&nbsp;&nbsp;&nbsp; throw&nbsp; new&nbsp;IllegalArgumentException(address&nbsp;+&nbsp; "&nbsp;is&nbsp;invalid");
&nbsp;&nbsp;}
&nbsp;&nbsp;String&nbsp;host&nbsp;=&nbsp;blocks[ 0];
&nbsp;&nbsp; int&nbsp;port&nbsp;=&nbsp; 80;
&nbsp;&nbsp; if(blocks.length&nbsp;>&nbsp; 1){
&nbsp;&nbsp;&nbsp;port&nbsp;=&nbsp;Integer.valueOf(blocks[ 1]);
&nbsp;&nbsp;}&nbsp; else&nbsp;{
&nbsp;&nbsp;&nbsp;address&nbsp;+=&nbsp; ":"+port;&nbsp; //use&nbsp;default&nbsp;80
&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;String&nbsp;serverAddr&nbsp;=&nbsp;String.format( "%s:%d",&nbsp;host,&nbsp;port);
&nbsp;&nbsp; return&nbsp;serverAddr;
&nbsp;}
&nbsp;
&nbsp; public&nbsp; static&nbsp;String&nbsp; getLocalAddress(String&nbsp;address){
&nbsp;&nbsp;String[]&nbsp;blocks&nbsp;=&nbsp;address.split( "[:]");
&nbsp;&nbsp; if(blocks.length&nbsp;!=&nbsp; 2){
&nbsp;&nbsp;&nbsp; throw&nbsp; new&nbsp;IllegalArgumentException(address&nbsp;+&nbsp; "&nbsp;is&nbsp;invalid&nbsp;address");
&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;String&nbsp;host&nbsp;=&nbsp;blocks[ 0];
&nbsp;&nbsp; int&nbsp;port&nbsp;=&nbsp;Integer.valueOf(blocks[ 1]);
&nbsp;&nbsp;
&nbsp;&nbsp; if( "0.0.0.0".equals(host)){
&nbsp;&nbsp;&nbsp; return&nbsp;String.format( "%s:%d",NetUtil.getLocalIp(),&nbsp;port);
&nbsp;&nbsp;}
&nbsp;&nbsp; return&nbsp;address;
&nbsp;}
&nbsp;
&nbsp; private&nbsp; static&nbsp; int&nbsp; matchedIndex(String&nbsp;ip,&nbsp;String[]&nbsp;prefix){
&nbsp;&nbsp; for( int&nbsp;i= 0;&nbsp;i<prefix.length;&nbsp;i++){
&nbsp;&nbsp;&nbsp;String&nbsp;p&nbsp;=&nbsp;prefix[i];
&nbsp;&nbsp;&nbsp; if( "*".equals(p)){&nbsp; //*,&nbsp;assumed&nbsp;to&nbsp;be&nbsp;IP
&nbsp;&nbsp;&nbsp;&nbsp; if(ip.startsWith( "127.")&nbsp;||
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip.startsWith( "10.")&nbsp;||&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip.startsWith( "172.")&nbsp;||
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip.startsWith( "192.")){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;i;
&nbsp;&nbsp;&nbsp;}&nbsp; else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp; if(ip.startsWith(p)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;i;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;}
&nbsp;&nbsp;
&nbsp;&nbsp; return&nbsp;- 1;
&nbsp;}
&nbsp;
&nbsp; public&nbsp; static&nbsp;String&nbsp; getLocalIp(String&nbsp;ipPreference)&nbsp;{
&nbsp;&nbsp; if(ipPreference&nbsp;==&nbsp; null){
&nbsp;&nbsp;&nbsp;ipPreference&nbsp;=&nbsp; "*>10>172>192>127";
&nbsp;&nbsp;}
&nbsp;&nbsp;String[]&nbsp;prefix&nbsp;=&nbsp;ipPreference.split( "[>&nbsp;]+");
&nbsp;&nbsp; try&nbsp;{
&nbsp;&nbsp;&nbsp;Pattern&nbsp;pattern&nbsp;=&nbsp;Pattern.compile( "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+");
&nbsp;&nbsp;&nbsp;Enumeration<NetworkInterface>&nbsp;interfaces&nbsp;=&nbsp;NetworkInterface.getNetworkInterfaces();
&nbsp;&nbsp;&nbsp;String&nbsp;matchedIp&nbsp;=&nbsp; null;
&nbsp;&nbsp;&nbsp; int&nbsp;matchedIdx&nbsp;=&nbsp;- 1;
&nbsp;&nbsp;&nbsp; while&nbsp;(interfaces.hasMoreElements())&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;NetworkInterface&nbsp;ni&nbsp;=&nbsp;interfaces.nextElement();
&nbsp;&nbsp;&nbsp;&nbsp;Enumeration<InetAddress>&nbsp;en&nbsp;=&nbsp;ni.getInetAddresses();&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; while&nbsp;(en.hasMoreElements())&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InetAddress&nbsp;addr&nbsp;=&nbsp;en.nextElement();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;ip&nbsp;=&nbsp;addr.getHostAddress();&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matcher&nbsp;matcher&nbsp;=&nbsp;pattern.matcher(ip);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp;(matcher.matches())&nbsp;{&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;idx&nbsp;=&nbsp;matchedIndex(ip,&nbsp;prefix);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(idx&nbsp;==&nbsp;- 1)&nbsp; continue;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(matchedIdx&nbsp;==&nbsp;- 1){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matchedIdx&nbsp;=&nbsp;idx;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matchedIp&nbsp;=&nbsp;ip;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(matchedIdx>idx){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matchedIdx&nbsp;=&nbsp;idx;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matchedIp&nbsp;=&nbsp;ip;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;&nbsp; if(matchedIp&nbsp;!=&nbsp; null)&nbsp; return&nbsp;matchedIp;
&nbsp;&nbsp;&nbsp; return&nbsp; "127.0.0.1";
&nbsp;&nbsp;}&nbsp; catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;
&nbsp;&nbsp;&nbsp; return&nbsp; "127.0.0.1";
&nbsp;&nbsp;}
&nbsp;}
&nbsp;
&nbsp; public&nbsp; static&nbsp;String&nbsp; getLocalIp()&nbsp;{
&nbsp;&nbsp; return&nbsp;getLocalIp( "*>10>172>192>127");
&nbsp;}
&nbsp;
&nbsp; public&nbsp; static&nbsp;String&nbsp; remoteAddress(SocketChannel&nbsp;channel){
&nbsp;&nbsp;SocketAddress&nbsp;addr&nbsp;=&nbsp;channel.socket().getRemoteSocketAddress();
&nbsp;&nbsp;String&nbsp;res&nbsp;=&nbsp;String.format( "%s",&nbsp;addr);
&nbsp;&nbsp; return&nbsp;res;
&nbsp;}
&nbsp;
&nbsp; public&nbsp; static&nbsp;String&nbsp; localAddress(SocketChannel&nbsp;channel){
&nbsp;&nbsp;SocketAddress&nbsp;addr&nbsp;=&nbsp;channel.socket().getLocalSocketAddress();
&nbsp;&nbsp;String&nbsp;res&nbsp;=&nbsp;String.format( "%s",&nbsp;addr);
&nbsp;&nbsp; return&nbsp;addr== null?&nbsp;res:&nbsp;res.substring( 1);
&nbsp;}
&nbsp;
&nbsp; public&nbsp; static&nbsp;String&nbsp; getPid(){
&nbsp;&nbsp;RuntimeMXBean&nbsp;runtime&nbsp;=&nbsp;ManagementFactory.getRuntimeMXBean();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;name&nbsp;=&nbsp;runtime.getName();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;index&nbsp;=&nbsp;name.indexOf( "@");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp;(index&nbsp;!=&nbsp;- 1)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;name.substring( 0,&nbsp;index);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp; return&nbsp; null;
&nbsp;}
&nbsp;
&nbsp; public&nbsp; static&nbsp;String&nbsp; getLocalHostName()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;(InetAddress.getLocalHost()).getHostName();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; catch&nbsp;(UnknownHostException&nbsp;uhe)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;host&nbsp;=&nbsp;uhe.getMessage();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp;(host&nbsp;!=&nbsp; null)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;colon&nbsp;=&nbsp;host.indexOf( ':');
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp;(colon&nbsp;>&nbsp; 0)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;host.substring( 0,&nbsp;colon);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp; "UnknownHost";
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
}

启动项目,访问/index和/ero接口,可以看到项目中生成了app-collector.log和error-collector.log两个日志文件

dbea74f3123fb4debcb83baf86a5cb98.jpeg

我们将Springboot服务部署在192.168.11.31这台机器上。

Kafka安装和启用

kafka下载地址:

http://kafka.apache.org/downloads.html

kafka安装步骤:首先kafka安装需要依赖与zookeeper,所以小伙伴们先准备好zookeeper环境(三个节点即可),然后我们来一起构建kafka broker。

##&nbsp;解压命令:
tar&nbsp;-zxvf&nbsp;kafka_2.12-2.1.0.tgz&nbsp;-C&nbsp;/usr/ local/
##&nbsp;改名命令:
mv&nbsp;kafka_2.12-2.1.0/&nbsp;kafka_2.12
##&nbsp;进入解压后的目录,修改server.properties文件:
vim&nbsp;/usr/ local/kafka_2.12/config/server.properties
##&nbsp;修改配置:
broker.id=0
port=9092
host.name=192.168.11.51
advertised.host.name=192.168.11.51
log.dirs=/usr/ local/kafka_2.12/kafka-logs
num.partitions=2
zookeeper.connect=192.168.11.111:2181,192.168.11.112:2181,192.168.11.113:2181

##&nbsp;建立日志文件夹:
mkdir&nbsp;/usr/ local/kafka_2.12/kafka-logs

##启动kafka:
/usr/ local/kafka_2.12/bin/kafka-server-start.sh&nbsp;/usr/ local/kafka_2.12/config/server.properties&nbsp;&

创建两个topic

##&nbsp;创建topic
kafka-topics.sh&nbsp;--zookeeper&nbsp;192.168.11.111:2181&nbsp;--create&nbsp;--topic&nbsp;app-log-collector&nbsp;--partitions&nbsp;1&nbsp;&nbsp;--replication-factor&nbsp;1
kafka-topics.sh&nbsp;--zookeeper&nbsp;192.168.11.111:2181&nbsp;--create&nbsp;--topic&nbsp;error-log-collector&nbsp;--partitions&nbsp;1&nbsp;&nbsp;--replication-factor&nbsp;1&nbsp;

我们可以查看一下topic情况

kafka-topics.sh&nbsp;--zookeeper&nbsp;192.168.11.111:2181&nbsp;--topic&nbsp;app-log-test&nbsp;--describe

可以看到已经成功启用了app-log-collector和error-log-collector两个topic

bbe23150dd4c42cdded37516e9e28ed3.jpeg

filebeat安装和启用

filebeat下载

cd&nbsp;/usr/ local/software
tar&nbsp;-zxvf&nbsp;filebeat-6.6.0-linux-x86_64.tar.gz&nbsp;-C&nbsp;/usr/ local/
cd&nbsp;/usr/ local
mv&nbsp;filebeat-6.6.0-linux-x86_64/&nbsp;filebeat-6.6.0

配置filebeat,可以参考下方yml配置文件

vim&nbsp;/usr/ local/filebeat-5.6.2/filebeat.yml
######################&nbsp;Filebeat&nbsp;Configuration&nbsp;Example&nbsp;#########################
filebeat.prospectors:

-&nbsp;input_type:&nbsp; log

&nbsp;&nbsp;paths:
&nbsp;&nbsp;&nbsp;&nbsp; ##&nbsp;app-服务名称.log,&nbsp;为什么写死,防止发生轮转抓取历史数据
&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;/usr/ local/logs/app-collector.log
&nbsp;&nbsp; #定义写入&nbsp;ES&nbsp;时的&nbsp;_type&nbsp;值
&nbsp;&nbsp;document_type:&nbsp; "app-log"
&nbsp;&nbsp;multiline:
&nbsp;&nbsp;&nbsp;&nbsp; #pattern:&nbsp;'^\s*(\d{4}|\d{2})\-(\d{2}|[a-zA-Z]{3})\-(\d{2}|\d{4})'&nbsp;&nbsp;&nbsp;#&nbsp;指定匹配的表达式(匹配以&nbsp;2017-11-15&nbsp;08:04:23:889&nbsp;时间格式开头的字符串)
&nbsp;&nbsp;&nbsp;&nbsp;pattern:&nbsp; '^\['&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;指定匹配的表达式(匹配以&nbsp;"{&nbsp;开头的字符串)
&nbsp;&nbsp;&nbsp;&nbsp;negate:&nbsp; true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;是否匹配到
&nbsp;&nbsp;&nbsp;&nbsp;match:&nbsp;after&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;合并到上一行的末尾
&nbsp;&nbsp;&nbsp;&nbsp;max_lines:&nbsp;2000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;最大的行数
&nbsp;&nbsp;&nbsp;&nbsp;timeout:&nbsp;2s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;如果在规定时间没有新的日志事件就不等待后面的日志
&nbsp;&nbsp;fields:
&nbsp;&nbsp;&nbsp;&nbsp;logbiz:&nbsp;collector
&nbsp;&nbsp;&nbsp;&nbsp;logtopic:&nbsp;app-log-collector&nbsp;&nbsp;&nbsp; ##&nbsp;按服务划分用作kafka&nbsp;topic
&nbsp;&nbsp;&nbsp;&nbsp;evn:&nbsp;dev

-&nbsp;input_type:&nbsp; log

&nbsp;&nbsp;paths:
&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;/usr/ local/logs/error-collector.log
&nbsp;&nbsp;document_type:&nbsp; "error-log"
&nbsp;&nbsp;multiline:
&nbsp;&nbsp;&nbsp;&nbsp; #pattern:&nbsp;'^\s*(\d{4}|\d{2})\-(\d{2}|[a-zA-Z]{3})\-(\d{2}|\d{4})'&nbsp;&nbsp;&nbsp;#&nbsp;指定匹配的表达式(匹配以&nbsp;2017-11-15&nbsp;08:04:23:889&nbsp;时间格式开头的字符串)
&nbsp;&nbsp;&nbsp;&nbsp;pattern:&nbsp; '^\['&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;指定匹配的表达式(匹配以&nbsp;"{&nbsp;开头的字符串)
&nbsp;&nbsp;&nbsp;&nbsp;negate:&nbsp; true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;是否匹配到
&nbsp;&nbsp;&nbsp;&nbsp;match:&nbsp;after&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;合并到上一行的末尾
&nbsp;&nbsp;&nbsp;&nbsp;max_lines:&nbsp;2000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;最大的行数
&nbsp;&nbsp;&nbsp;&nbsp;timeout:&nbsp;2s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;如果在规定时间没有新的日志事件就不等待后面的日志
&nbsp;&nbsp;fields:
&nbsp;&nbsp;&nbsp;&nbsp;logbiz:&nbsp;collector
&nbsp;&nbsp;&nbsp;&nbsp;logtopic:&nbsp;error-log-collector&nbsp;&nbsp;&nbsp; ##&nbsp;按服务划分用作kafka&nbsp;topic
&nbsp;&nbsp;&nbsp;&nbsp;evn:&nbsp;dev
&nbsp;&nbsp;&nbsp;&nbsp;
output.kafka:
&nbsp;&nbsp;enabled:&nbsp; true
&nbsp;&nbsp;hosts:&nbsp;[ "192.168.11.51:9092"]
&nbsp;&nbsp;topic:&nbsp; '%{[fields.logtopic]}'
&nbsp;&nbsp;partition.hash:
&nbsp;&nbsp;&nbsp;&nbsp;reachable_only:&nbsp; true
&nbsp;&nbsp;compression:&nbsp;gzip
&nbsp;&nbsp;max_message_bytes:&nbsp;1000000
&nbsp;&nbsp;required_acks:&nbsp;1
logging.to_files:&nbsp; true

filebeat启动:

检查配置是否正确

cd&nbsp;/usr/ local/filebeat-6.6.0
./filebeat&nbsp;-c&nbsp;filebeat.yml&nbsp;-configtest
##&nbsp;Config&nbsp;OK

启动filebeat

/usr/ local/filebeat-6.6.0/filebeat&nbsp;&

检查是否启动成功

ps&nbsp;-ef&nbsp;|&nbsp;grep&nbsp;filebeat

可以看到filebeat已经启动成功

be21b14f11bb694c55c31f06850f44f9.jpeg

然后我们访问192.168.11.31:8001/index和192.168.11.31:8001/err,再查看kafka的logs文件,可以看到已经生成了app-log-collector-0和error-log-collector-0文件,说明filebeat已经帮我们把数据收集好放到了kafka上。

logstash安装

我们在logstash的安装目录下新建一个文件夹

mkdir&nbsp;scrpit

然后cd进该文件,创建一个logstash-script.conf文件

cd&nbsp;scrpit
vim&nbsp;logstash-script.conf
## multiline 插件也可以用于其他类似的堆栈式信息,比如 linux 的内核日志。
input&nbsp;{
&nbsp;&nbsp;kafka&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp; ##&nbsp;app-log-服务名称
&nbsp;&nbsp;&nbsp;&nbsp;topics_pattern&nbsp;=>&nbsp; "app-log-.*"
&nbsp;&nbsp;&nbsp;&nbsp;bootstrap_servers&nbsp;=>&nbsp; "192.168.11.51:9092"
&nbsp;codec&nbsp;=>&nbsp;json
&nbsp;consumer_threads&nbsp;=>&nbsp;1&nbsp; ##&nbsp;增加consumer的并行消费线程数
&nbsp;decorate_events&nbsp;=>&nbsp; true
&nbsp;&nbsp;&nbsp;&nbsp; #auto_offset_rest&nbsp;=>&nbsp;"latest"
&nbsp;group_id&nbsp;=>&nbsp; "app-log-group"
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;kafka&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp; ##&nbsp;error-log-服务名称
&nbsp;&nbsp;&nbsp;&nbsp;topics_pattern&nbsp;=>&nbsp; "error-log-.*"
&nbsp;&nbsp;&nbsp;&nbsp;bootstrap_servers&nbsp;=>&nbsp; "192.168.11.51:9092"
&nbsp;codec&nbsp;=>&nbsp;json
&nbsp;consumer_threads&nbsp;=>&nbsp;1
&nbsp;decorate_events&nbsp;=>&nbsp; true
&nbsp;&nbsp;&nbsp;&nbsp; #auto_offset_rest&nbsp;=>&nbsp;"latest"
&nbsp;group_id&nbsp;=>&nbsp; "error-log-group"
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;
}

filter&nbsp;{
&nbsp;&nbsp;
&nbsp;&nbsp; ##&nbsp;时区转换
&nbsp;&nbsp;ruby&nbsp;{
&nbsp;code&nbsp;=>&nbsp; "event.set('index_time',event.timestamp.time.localtime.strftime('%Y.%m.%d'))"
&nbsp;&nbsp;}

&nbsp;&nbsp; if&nbsp; "app-log"&nbsp; in&nbsp;[fields][logtopic]{
&nbsp;&nbsp;&nbsp;&nbsp;grok&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ##&nbsp;表达式,这里对应的是Springboot输出的日志格式
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;=>&nbsp;[ "message",&nbsp; "\[%{NOTSPACE:currentDateTime}\]&nbsp;\[%{NOTSPACE:level}\]&nbsp;\[%{NOTSPACE:thread-id}\]&nbsp;\[%{NOTSPACE:class}\]&nbsp;\[%{DATA:hostName}\]&nbsp;\[%{DATA:ip}\]&nbsp;\[%{DATA:applicationName}\]&nbsp;\[%{DATA:location}\]&nbsp;\[%{DATA:messageInfo}\]&nbsp;##&nbsp;(\'\'|%{QUOTEDSTRING:throwable})"]
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}

&nbsp;&nbsp; if&nbsp; "error-log"&nbsp; in&nbsp;[fields][logtopic]{
&nbsp;&nbsp;&nbsp;&nbsp;grok&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ##&nbsp;表达式
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;=>&nbsp;[ "message",&nbsp; "\[%{NOTSPACE:currentDateTime}\]&nbsp;\[%{NOTSPACE:level}\]&nbsp;\[%{NOTSPACE:thread-id}\]&nbsp;\[%{NOTSPACE:class}\]&nbsp;\[%{DATA:hostName}\]&nbsp;\[%{DATA:ip}\]&nbsp;\[%{DATA:applicationName}\]&nbsp;\[%{DATA:location}\]&nbsp;\[%{DATA:messageInfo}\]&nbsp;##&nbsp;(\'\'|%{QUOTEDSTRING:throwable})"]
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}
&nbsp;&nbsp;
}

##&nbsp;测试输出到控制台:
output&nbsp;{
&nbsp;&nbsp;stdout&nbsp;{&nbsp;codec&nbsp;=>&nbsp;rubydebug&nbsp;}
}


## elasticsearch:
output&nbsp;{

&nbsp;&nbsp; if&nbsp; "app-log"&nbsp; in&nbsp;[fields][logtopic]{
&nbsp; ##&nbsp;es插件
&nbsp;elasticsearch&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;es服务地址
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hosts&nbsp;=>&nbsp;[ "192.168.11.35:9200"]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;用户名密码&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user&nbsp;=>&nbsp; "elastic"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password&nbsp;=>&nbsp; "123456"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ##&nbsp;索引名,+&nbsp;号开头的,就会自动认为后面是时间格式:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ##&nbsp;javalog-app-service-2019.01.23&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;=>&nbsp; "app-log-%{[fields][logbiz]}-%{index_time}"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;是否嗅探集群ip:一般设置true;http://192.168.11.35:9200/_nodes/http?pretty
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;通过嗅探机制进行es集群负载均衡发日志消息
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sniffing&nbsp;=>&nbsp; true
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;logstash默认自带一个mapping模板,进行模板覆盖
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template_overwrite&nbsp;=>&nbsp; true
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;}
&nbsp;&nbsp;
&nbsp;&nbsp; if&nbsp; "error-log"&nbsp; in&nbsp;[fields][logtopic]{
&nbsp;elasticsearch&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hosts&nbsp;=>&nbsp;[ "192.168.11.35:9200"]&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user&nbsp;=>&nbsp; "elastic"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password&nbsp;=>&nbsp; "123456"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;=>&nbsp; "error-log-%{[fields][logbiz]}-%{index_time}"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sniffing&nbsp;=>&nbsp; true
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template_overwrite&nbsp;=>&nbsp; true
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;}
&nbsp;&nbsp;

}

启动logstash

/usr/ local/logstash-6.6.0/bin/logstash&nbsp;-f&nbsp;/usr/ local/logstash-6.6.0/script/logstash-script.conf&nbsp;&

等待启动成功,我们再次访问192.168.11.31:8001/err

可以看到控制台开始打印日志

b0a5135b2250214aba1ee8a8eb0e1732.jpeg

ElasticSearch与Kibana

244ece68c176e5b104a1db6c0401e08f.jpeg

ES和Kibana的搭建之前没写过博客,网上资料也比较多,大家可以自行搜索。

搭建完成后,访问Kibana的管理页面192.168.11.35:5601,选择Management -> Kinaba - Index Patterns

5f5569c9fad93164485e40029e7e916c.jpeg

然后Create index pattern

  • index pattern 输入&nbsp;app-log-*
  • Time Filter field name 选择 currentDateTime

这样我们就成功创建了索引。

我们再次访问192.168.11.31:8001/err,这个时候就可以看到我们已经命中了一条log信息

7170bc2ecb13ea40e375990e1664b1b0.jpeg

里面展示了日志的全量信息

6e69e734772321f92bdbc8af7260f60a.jpeg

到这里,我们完整的日志收集及可视化就搭建完成了!

猜你喜欢

转载自blog.csdn.net/jjc4261/article/details/125761666