elk实践
创始人
2024-02-11 12:18:03

1、背景

鉴于现在项目中的日志比较乱,所以建议使用现在较为流行的elk收集日志并展示;

2下载、配置与启动

在下载 Elastic 产品 | Elastic 官网下载filebeat、logstash、elasticSearch、kibana 版本要一致 本人测试用的7.14 mac版本 实际生产使用7.14 linux版本

2.1Filebeat:

tar -zxvf filebeat-7.14.0-darwin-x86_64.tar.gz

Cd filebeat-7.14.0-darwin-x86_64

配置:filebeat.yml

- type: logenabled: truepaths:- /Users/admin/IdeaProjects/maijia-tebu/log/info/*.log- /Users/admin/IdeaProjects/taosj-aliexpress-data/log/*/*.logmultiline.pattern: '^[0-9][0-9][0-9][0-9]'multiline.negate: truemultiline.match: after
output.logstash:hosts: ["localhost:5044”]

sudo chown root:root /Users/admin/IdeaProjects/maijia-tebu/log/info root:为执行用户

sudo chown root filebeat.yml

测试配置 ./filebeat test config -e

sudo ./filebeat -e

配置说明:

Paths:后面可以配置多个目录,配置的目录不会去递归,只会在最后的子目录里面寻找.log的文件;

multiline:以 '^[0-9][0-9][0-9][0-9]' 格式后面的识别为一行,这样报错等信息就在一行了;

output.logstash:logstash的地址;

sudo chown admin:admin /Users/admin/IdeaProjects/maijia-tebu/log/info admin:为执行用户 给log目录设置权限

sudo chown root filebeat.yml 给配置文件权限

./filebeat test config -e 测试配置

sudo ./filebeat -e 启动

2.2Logstash:

tar -zxvf logstash-7.14.0-darwin-x86_64.tar.gz

Cd logstash-7.14.0

配置:

Vi ./config/logstash-test.conf

input {beats {port => 5044  }
}
filter{dissect {mapping => {"message" => "%{log_time}|%{ip}|%{serverName}|%{profile}|%{level}|%{logger}|%{thread}|%{traceId}|%{msg}" //与项目中的日志输出格式相对应}}date{match => ["log_time", "yyyy-MM-dd HH:mm:ss.SSS"]target => "@timestamp"}
}
output {elasticsearch {hosts => ["localhost:9200"]index => "logs-%{+YYYY.MM.dd}"  //创建索引的格式}
}

sudo ./bin/logstash -f config/logstash-test.conf

2.3elaticSearch:

tar -zxvf elasticsearch-7.14.0-darwin-x86_64.tar.gz

Cd elasticsearch-7.14.0

Sodu ./bin/elasticSearch

检查服务:curl http://127.0.0.1:9200

2.4kibana

tar -zxvf kibana-7.14.0-darwin-x86_64.tar.gz

Cd kibana-7.14.0-darwin-x86_64

配置:如果es与kibana不在同一台服务器,在config/kibana.yml,添加 elasticsearch.url: "http://ip:port"

Sudo ./bin/kibana

检查:浏览器打开http://127.0.0.1:5601

3、新建jar

新建jar包  写一些工具类

3.1Snowflake

import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.baomidou.mybatisplus.core.toolkit.SystemClock;import java.io.Serializable;
import java.util.Date;
public class Snowflake implements Serializable {private static final long serialVersionUID = 1L;private final long twepoch;private final long workerIdBits = 5L;private final long dataCenterIdBits = 5L;// 最大支持数据中心节点数0~31,一共32个@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})private final long maxWorkerId = -1L ^ (-1L << workerIdBits);@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})private final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits);// 序列号12位private final long sequenceBits = 12L;// 机器节点左移12位private final long workerIdShift = sequenceBits;// 数据中心节点左移17位private final long dataCenterIdShift = sequenceBits + workerIdBits;// 时间毫秒数左移22位private final long timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits;@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})private final long sequenceMask = -1L ^ (-1L << sequenceBits);// 4095private final long workerId;private final long dataCenterId;private final boolean useSystemClock;private long sequence = 0L;private long lastTimestamp = -1L;/*** 构造** @param workerId     终端ID* @param dataCenterId 数据中心ID*/public Snowflake(long workerId, long dataCenterId) {this(workerId, dataCenterId, false);}/*** 构造** @param workerId         终端ID* @param dataCenterId     数据中心ID* @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳*/public Snowflake(long workerId, long dataCenterId, boolean isUseSystemClock) {this(null, workerId, dataCenterId, isUseSystemClock);}/*** @param epochDate        初始化时间起点(null表示默认起始日期),后期修改会导致id重复,如果要修改连workerId dataCenterId,慎用* @param workerId         工作机器节点id* @param dataCenterId     数据中心id* @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳* @since 5.1.3*/public Snowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock) {if (null != epochDate) {this.twepoch = epochDate.getTime();} else {
// Thu, 04 Nov 2010 01:42:54 GMTthis.twepoch = 1288834974657L;}if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(format("worker Id can't be greater than {} or less than 0", maxWorkerId));}if (dataCenterId > maxDataCenterId || dataCenterId < 0) {throw new IllegalArgumentException(format("datacenter Id can't be greater than {} or less than 0", maxDataCenterId));}this.workerId = workerId;this.dataCenterId = dataCenterId;this.useSystemClock = isUseSystemClock;}/*** 根据Snowflake的ID,获取机器id** @param id snowflake算法生成的id* @return 所属机器的id*/public long getWorkerId(long id) {return id >> workerIdShift & ~(-1L << workerIdBits);}/*** 根据Snowflake的ID,获取数据中心id** @param id snowflake算法生成的id* @return 所属数据中心*/public long getDataCenterId(long id) {return id >> dataCenterIdShift & ~(-1L << dataCenterIdBits);}/*** 根据Snowflake的ID,获取生成时间** @param id snowflake算法生成的id* @return 生成的时间*/public long getGenerateDateTime(long id) {return (id >> timestampLeftShift & ~(-1L << 41L)) + twepoch;}/*** 下一个ID** @return ID*/public synchronized long nextId() {long timestamp = genTime();if (timestamp < lastTimestamp) {if (lastTimestamp - timestamp < 2000) {
// 容忍2秒内的回拨,避免NTP校时造成的异常timestamp = lastTimestamp;} else {
// 如果服务器时间有问题(时钟后退) 报错。throw new IllegalStateException(format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp));}}if (timestamp == lastTimestamp) {sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - twepoch) << timestampLeftShift) | (dataCenterId << dataCenterIdShift) | (workerId << workerIdShift) | sequence;}/*** 下一个ID(字符串形式)** @return ID 字符串形式*/public String nextIdStr() {return Long.toString(nextId());}// ------------------------------------------------------------------------------------------------------------------------------------ Private method start/*** 循环等待下一个时间** @param lastTimestamp 上次记录的时间* @return 下一个时间*/private long tilNextMillis(long lastTimestamp) {long timestamp = genTime();// 循环直到操作系统时间戳变化while (timestamp == lastTimestamp) {timestamp = genTime();}if (timestamp < lastTimestamp) {
// 如果发现新的时间戳比上次记录的时间戳数值小,说明操作系统时间发生了倒退,报错throw new IllegalStateException(format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp));}return timestamp;}/*** 生成时间戳** @return 时间戳*/private long genTime() {return this.useSystemClock ? SystemClock.now() : System.currentTimeMillis();}public  String format(String target, Object... params) {return target.contains("%s") && ArrayUtils.isNotEmpty(params) ? String.format(target, params) : target;}
}

3.2 TraceIdAdvice


import com.alibaba.dubbo.rpc.RpcContext;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.MDC;/**  * 类 描 述:traceId切面
*/
public class TraceIdAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {String tid = MDC.get("traceId");String rpcTid = RpcContext.getContext().getAttachment("traceId");if (tid != null) {RpcContext.getContext().setAttachment("traceId", tid);} else {if (rpcTid != null) {MDC.put("traceId",rpcTid);}}Object result = invocation.proceed();return result;}
}

3.3 TraceIdAdviceConfig


import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/** * 类 描 述:traceId切面动态配置
*/
@Configuration
public class TraceIdAdviceConfig {@Value("${traceId.pointcut.property}")private String pointcut;@Beanpublic AspectJExpressionPointcutAdvisor configurabledvisor() {AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();advisor.setExpression(pointcut);advisor.setAdvice(new TraceIdAdvice());return advisor;}
}

3.4 IPConverterConfig

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;/*** 类 描 述:log打出ip*/
public class IPConverterConfig extends ClassicConverter {private String url;@Overridepublic String convert(ILoggingEvent iLoggingEvent) {try {if (url == null){String hostAddress = getLocalHostLANAddress().getHostAddress();url = hostAddress;}return url;} catch (UnknownHostException e) {e.printStackTrace();}return null;}// 正确的IP拿法,即优先拿site-local地址private static InetAddress getLocalHostLANAddress() throws UnknownHostException{try {InetAddress candidateAddress = null;// 遍历所有的网络接口for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) {NetworkInterface iface = (NetworkInterface) ifaces.nextElement();//服务器上eth0才是正确的ipif (!"eth0".equals(iface.getName())){continue;}// 在所有的接口下再遍历IPfor (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();if (!inetAddr.isLoopbackAddress()) {// 排除loopback类型地址if (inetAddr.isSiteLocalAddress()) {// 如果是site-local地址,就是它了return inetAddr;} else if (candidateAddress == null) {// site-local类型的地址未被发现,先记录候选地址candidateAddress = inetAddr;}}}}if (candidateAddress != null) {return candidateAddress;}// 如果没有发现 non-loopback地址.只能用最次选的方案InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();if (jdkSuppliedAddress == null) {throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");}return jdkSuppliedAddress;} catch (Exception e) {e.printStackTrace();}return null;}}

3.5 TraceIdInterceptor

/*** 类 描 述:traceId 用于追踪链路*/
@Slf4j
@Component
public class TraceIdInterceptor implements HandlerInterceptor {/*@AutowiredRedisHelper redisHelper;*/Snowflake snowflake = new Snowflake(1,0);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){String tid = snowflake.nextIdStr();MDC.put("traceId",tid);RpcContext.getContext().setAttachment("traceId", tid);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView){MDC.remove("traceId");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex){}//生成导入批次号/*public  String getTraceId() {String dateString = DateUtils.formatYYYYMMDD(new Date());Long incr = redisHelper.incr("taosj-common-traceId" + dateString, 24);if (incr == 0) {incr = redisHelper.incr("taosj-common-traceId" + dateString, 24);}DecimalFormat df = new DecimalFormat("000000");return dateString + df.format(incr);}*/
}

3.6 WebAppConfigurer

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 类 描 述:TODO*/
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {@Autowiredprivate TraceIdInterceptor traceIdInterceptor;/*** 注册拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(traceIdInterceptor).addPathPatterns("/**");//.excludePathPatterns("/admin/login")//.excludePathPatterns("/admin/getLogin");//  - /**: 匹配所有路径//  - /admin/**:匹配 /admin/ 下的所有路径//  - /admin/*:只匹配 /admin/login,不匹配 /secure/login/tologin ("/*"只匹配一级子目录,"/**"匹配所有子目录)}}

3.7 jar pom

org.springframeworkspring-contextorg.springframeworkspring-webmvccom.alibabadubboorg.slf4jslf4j-apicom.baomidoumybatis-plus-corech.qos.logbacklogback-classicorg.apache.tomcat.embedtomcat-embed-core

 4、jar包的使用

1、pom文件:

添加自己的jar包

2、启动类增加类扫描:步骤3的包名 

3、配置文件增加切面pointcut配置:例如:traceId.pointcut.property=execution(public * com.taosj.tebu.service..*.*(..)) 自己项目的包名

4、logback-spring文件修改:ip 日志输出格式



应该是把现在正在运行的日志拿过来,所以要把之前的日志删除掉,以及把形成的日志名改掉:

比如${dir}/info/info.%d{yyyy-MM-dd}.%i.log 改成

${dir}/info/info.log.%d{yyyy-MM-dd}.%i

5、springboot项目logback-spring.xml例子

${dir}/info/info.log${dir}/info/info.log.%d{yyyy-MM-dd}.%i100MB105GB${pattern_log}UTF-8${dir}/debug/debug.log${dir}/debug/debug.%i.log.%d{yyyy-MM-dd}.%i100MB105GB${pattern_log}UTF-8${dir}/error/error.log${dir}/error/error.log.%d{yyyy-MM-dd}.%i100MB105GB${pattern_log}UTF-8${dir}/biz/biz.log${dir}/biz/biz.log.%d{yyyy-MM-dd}.%i100MB105GB${pattern_log}UTF-8${pattern}

7、部署时候的小tip:

7.1:filebeat启动时

nohup ./filebeat & 这样shell关闭了还是会停

nohup ./filebeat & disown 要这样启动

7.2: filebeat推送logstash的地址:

116.62.126.104 35044 可以查看filebeat.yml配置文件

7.4:ip

ip获取的是eth0网卡的ip

7.4:小问题

springmvc项目使用log4j不能一开始就注入servername、ip、profile等信息 所以启动等信息没有这些字段,调用接口等是有这些信息的;springboot项目使用logback没有这个问题

 

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...