前言
日志框架经常使用 老是现场查询 最近抽空做个整理 方便自己速查
虽然现在在一些k8s 之类的集群上 日志收集一般是收集 stdout stderr 来采集日志
不过更多的拥有自己的elk集群或者log文件分析集群 所以还是需要log框架来输出日志
日志主要就是layouts(样式)、appender(追加器)、
slf4j 是一中日志框架标准 其中常用的实现为log4j2 logback
logback
参考文档: http://www.logback.cn/
spring boot 默认就是使用logback 这个是现在用的比较多的方式
常用xml配置
输出到console 和生成log文件 按照日期建立目录 单个文件100mb 最大90天 日志最大100GB
1 |
|
自定义appender
- 自定义appender
继承于AppenderBase
1 | package com.ming.base; |
- 配置使用 自定义appender
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<configuration>
<!--自定义变量-->
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg,50是logger名称最大长度:日志消息,%n是换行符-->
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}- %msg%n"/>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<!--%highlight(%-5level) %cyan表示高亮日志等级,并使用藏青色打印logger部分-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}) - %msg%n</pattern>
</encoder>
</appender>
<appender name="mingAppender" class="com.ming.base.MingAppender"/>
<!--默认的日志级别,如果上面的logger没有命中,则按照root的级别打印日志,root是所有logger的父节点,如果addtivity是false,则不会抛到这里-->
<root level="INFO">
<appender-ref ref="Console"/>
<appender-ref ref="mingAppender"/>
</root>
</configuration>
log4j2
参考文档:
http://logging.apache.org/log4j/2.x/download.html
https://www.cnblogs.com/frankwin608/p/log4j2.html
https://blog.csdn.net/lnkToKing/article/details/79563460
log4j2 也不错 配置方法和logback差不多 主要是增强了异步输出日志的特性 其他的差不多功能
常用xml配置
1 |
|
自定义appender
- 自定义appender
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168package com.ming.log;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.plugins.*;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.layout.PatternSelector;
import org.apache.logging.log4j.core.pattern.RegexReplacement;
import java.io.File;
import java.nio.charset.Charset;
/**
* boss json格式日志
* <p>
* 配合elk的配置 使用
* 原作者文章地址: https://blog.csdn.net/lnkToKing/article/details/79563460
*
* @author ming
* @date 2018-06-22 10:59:56
*/
public class MingJsonPatternLayout extends AbstractStringLayout {
/**
* 项目路径
*/
private static String PROJECT_PATH;
private PatternLayout patternLayout;
private String projectName;
private String logType;
static {
PROJECT_PATH = new File("").getAbsolutePath();
}
private BossJsonPatternLayout(Configuration config, RegexReplacement replace, String eventPattern,
PatternSelector patternSelector, Charset charset, boolean alwaysWriteExceptions,
boolean noConsoleNoAnsi, String headerPattern, String footerPattern, String projectName, String logType) {
super(config, charset,
PatternLayout.createSerializer(config, replace, headerPattern, null, patternSelector, alwaysWriteExceptions,
noConsoleNoAnsi),
PatternLayout.createSerializer(config, replace, footerPattern, null, patternSelector, alwaysWriteExceptions,
noConsoleNoAnsi));
this.projectName = projectName;
this.logType = logType;
this.patternLayout = PatternLayout.newBuilder()
.withPattern(eventPattern)
.withPatternSelector(patternSelector)
.withConfiguration(config)
.withRegexReplacement(replace)
.withCharset(charset)
.withAlwaysWriteExceptions(alwaysWriteExceptions)
.withNoConsoleNoAnsi(noConsoleNoAnsi)
.withHeader(headerPattern)
.withFooter(footerPattern)
.build();
}
public String toSerializable(LogEvent event) {
//在这里处理日志内容
String message = patternLayout.toSerializable(event);
String jsonStr = new JsonLoggerInfo(projectName, message, event.getLevel().name(), logType, event.getTimeMillis()).toString();
return jsonStr + "\n";
}
public static BossJsonPatternLayout createLayout(
final String pattern,
final PatternSelector patternSelector,
final Configuration config,
final RegexReplacement replace,
// LOG4J2-783 use platform default by default, so do not specify defaultString for charset
final Charset charset,
final boolean alwaysWriteExceptions,
final boolean noConsoleNoAnsi,
final String headerPattern,
final String footerPattern,
final String projectName,
final String logType) {
return new BossJsonPatternLayout(config, replace, pattern, patternSelector, charset,
alwaysWriteExceptions, noConsoleNoAnsi, headerPattern, footerPattern, projectName, logType);
}
/**
* 输出的日志内容
*/
public static class JsonLoggerInfo {
/**
* 项目名
*/
private String projectName;
/**
* 项目目录路径
*/
private String projectPath;
/**
* 日志信息
*/
private String message;
/**
* 日志级别
*/
private String level;
/**
* 日志分类
*/
private String logType;
/**
* 日志时间
*/
private String time;
public JsonLoggerInfo(String projectName, String message, String level, String logType, long timeMillis) {
this.projectName = projectName;
this.projectPath = PROJECT_PATH;
this.message = message;
this.level = level;
this.logType = logType;
this.time = DateFormatUtils.format(timeMillis, "yyyy-MM-dd HH:mm:ss.SSS");
}
public String getProjectName() {
return projectName;
}
public String getProjectPath() {
return projectPath;
}
public String getMessage() {
return message;
}
public String getLevel() {
return level;
}
public String getLogType() {
return logType;
}
public String getTime() {
return time;
}
public String toString() {
try {
return new ObjectMapper().writeValueAsString(this);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
} - 使用自定义appender
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- monitorInterval="60"表示每60秒配置文件会动态加载一次。在程序运行过程中,如果修改配置文件,程序会随之改变。 -->
<configuration status="warn" monitorInterval="1">
<!-- 定义通用的属性 -->
<Properties>
<Property name="PROJECT_NAME">ming</Property>
<Property name="ELK_LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss} %-5p thread[%thread] %l %msg %n</Property>
</Properties>
<appenders>
<!--测试环境 elk的logstash 入口-->
<Socket name="logstash" host="<logstash-ip>" port="<logstash-port>" protocol="TCP">
<MingJsonPatternLayout pattern="${ELK_LOG_PATTERN}" projectName="${PROJECT_NAME}" logType="ming" />
</Socket>
</appenders>
<Loggers>
<!-- 配置项目的 日志等级输出 -->
<root level="DEBUG">
<!-- 通过tcp 传输到logstash-->
<appender-ref ref="logstash"/>
</root>
</Loggers>
</configuration>
总结
java 基本上使用的都是slf4j
logback 和log4j2 各有千秋 一个实践时间长 一个拥有更好的性能
具体的可以看情况 总的来说 没有默认的appender 就自定义appender来配合其他组件