One, background
Logback large number of projects in the use of the diary, with some items using the log confusion, the format is not uniform, most people do not understand the configuration file, configuration error, and now need to develop a unified, less logging component configuration, easy to use.
Second, the design ideas
0 arranged as far as possible, no logback.xml
Log format unified, easy to follow log analysis system
Only two log level, one normal log, a log is abnormal
Provide log4j, jcl, logback, commons-log bridge and other programs and compatible version of the program
Grapes thread, JSON formatted output, map format, array format, the request response parameters (for time consuming) log output convenient method, etc.
Support redis, db, http automatically switch configurations * *
New log type (logger)
api using flow structure, similar to StringBuffer
Third, outline design
1, zero-configuration
Research Code
java
static LoggerContext lc;
static {
lc = (LoggerContext) LoggerFactory.getILoggerFactory();
// 对应配置中的appender
ConsoleAppender ca = new ConsoleAppender();
ca.setContext(lc);
ca.setName("console");
// 格式
PatternLayoutEncoder pl = new PatternLayoutEncoder();
pl.setContext(lc);
pl.setPattern("%d{MMddHHmmss.SSS} [%thread] %-5level %logger{36} - %msg%n");
pl.start();
ca.setEncoder(pl);
ca.start();
// 对应配置中的logger
ch.qos.logback.classic.Logger rootLogger = lc.getLogger("com.test");
rootLogger.addAppender(ca);}
The above code is equivalent to the following xml
%d{MMddHHmmss.SSS} [%thread] %-5level %logger{36} - %msg%n
It can be free to the contents of the configuration file is written in code form, the theory may have been achieved 0 configuration.
2, output path
Fixing the logs to convention, the relative path log / xxx.yyyy-MM-dd-HH.log, where xxx is the logger name
3, log format
格式固定:
MMddHHmmss.SSS||id||【交易名子步骤】||context ||[level][线程号]
例:
150000.311||N-XrUTQzIc1531897200311||【CiTeeFilterci拦截器】||ci拦截器 请求的完整参数为:{"merchantId":["0012444"],"userId":["13112341232"]} ||[INFO][http-8091-7]
Core code fixed format, intercepting a request to the log, assembled according to the format, and the main method to inherit ThrowableProxyConverter achieved MessageConverter log intercept and modify the desired format, for example, the id and the like into the local variables used therein, the core It is the use of the MDC
4, the base logger
All logs are the default output here logger name: when the service system initialization, define the Logger and appender, namely the Logger to root log
5, custom logger
Provided addLogger methods, parameters packageName package name, for example: com.test will lose if the name parameter is not set, the default name for the package name last name name behind a character, decided the name of the log file path log path to a non-losing non-essential. whether the output to the input additivity root log
6, a special log
Special log component configuration, for example: redis Default Default HTTP ERROR ERROR ERROR Kafka DB Connection Pool Default Default Default ERROR ERROR schedul Spring default ERROR
7, abnormal, log processing line feed
Providing a print format exception exception stack offers a new line of code formatted print ideas: Inheritance ThrowableProxyConverter, obtain exception stack, the fixed format text is inserted in front of every line
8, ordinary log api (VirgoLog)
method | The method described |
---|---|
setUniqKey(id) | Set current thread id, you can set when the thread starts, without setting back |
updateStep(trade, step) | Updated information about the current step of id |
log(msg, param) | Normal log record, MSG substitution rule, replace the ordinary {}, if you want to replace the service log api format, using the `` replacement |
logErr(msg, e) | Exception log records |
log( trade, step, msg, param) | Record ordinary log, this method will automatically update the id, trade, step, not recommended |
logErr(trade, step, msg, e) | Exception log records |
log(cid, trade, step, msg, param) | Record ordinary log, this method will automatically update the id, trade, step, not recommended |
logErr(cid, trade, step, msg, e) | Exception log records |
debug(msg, param) | Record debug-level logging is not recommended |
Business logging api (VirgoLog)
Usually when the diary, if a class does not have time to toString method, the data will not be printed out correctly, this time to provide an alternative method, the object directly replaced json print, ideas for the core code
MessageFormatter {} is a process based Alternatively, re-write type, i.e., little change support also supports `{}, and determines json or replaced toString
api follows
method | The method described |
---|---|
begin(msg) | Record start |
end(msg) | Recording is complete, it will print in this thread to begin now on a time-consuming |
logJson(json, format) | Json log recording format, format indicates whether the line feed |
logMap(map, format) | Formatting log records map |
logCollection(list, format) | Formatting log record set |
logArray(array, format) | An array of records formatted log |
logObjct(obj, format) | Object formatting log records |
System api (LoggerHelper)
method | The method described |
---|---|
getLogger() | Acquisition logger, for the diary |
getLogger(name) | Get logger by name |
addLogger () | Reference Custom Logger, if the logger has been created, it is no longer created, generally do not use, unless you want to customize the log name, etc. |
consoleOpen() | Open the console log, the default configuration console log when the system starts |
commonOpen(name, level) | The default components are error level, this method can change the log level, for example redis http, etc. |
9, special formatting
map: i.e. into json, then format
collection: ditto
array: also ibid.
object: ditto
10, issue
- Desensitization password, encryption method it is necessary to separate extraction
- Print switch provides parent thread
11, maven dependence
com.cdc.ecliptic virgo 1.5_1.6-SNAPSHOT
12、demo
public static void main(String[] args) throws InterruptedException {
// 启动
VirgoLancher.start("hahaha", "com.cdc.virgo", "D:/test/hahah.log");
LoggerHelper.commonOpen("hahaha", LogLevel.DEBUG);
Logger logger1 = LoggerFactory.getLogger("druid");
// VirgoLancher.commonStart("abc", "com.cdc.virgo");
// 打开控制台
LoggerHelper.consoleOpen();
// 设置cid
VirgoLog.setUniqKey(null);
// 设置步骤名和交易名
VirgoLog.updateStep("adfa", "saf");
// 获取Logger
VirgoLog logger = VirgoLog.getLogger();
// 打开debug级别(只有在开发阶段可以打开)
// logger.changeLevel(LogLevel.DEBUG);
// 记录换行
logger.log("a");
logger1.info("dddddddddd");
logger1.error("dddddddddd");
// logger1.info("sfdasfaf" +
// "\nafafdasfd" +
// "\nasfdasf");
logger.log("sfdasfaf" +
"\nafafdasfd" +
"\nasfdasf");
// logger1.info("b");
// 正常日志
// logger.log("我只有一行");
Map map = new HashMap();
map.put("asdf", "1");
map.put("asdf2", "2");
map.put("asdf3", "13");
map.put("asdf4", "14");
map.put("asdf5", "15");
map.put("asdf6", "16");
// // 异常日志也支持格式化
// logger.logErr("我错了:{},你没错:~~", new Exception("asdfsaflk"), "啊", map);
// logger.log("----------------------------------------------");
// // {}替换普通对象,调用toString() ~~把对象转换为json并且格式化输出 ``把对象转换为json不格式化输出
logger.log("你好{},你是谁~~``,sd~xx {}", map, map, map, "tttt");
VirgoLog.updateStep("saf2");
// // 把对象转换为json输出
// logger.logJson(map, false);
// // 更新步骤名和交易名
// VirgoLog.updateStep("bbbbb", "ccccc");
// // 耗时日志打印
logger.begin("处理内容");
logger.begin("处理第二个");
logger.begin("处理第三个");
Thread.sleep(3000L);
logger.end();
Thread.sleep(1000L);
logger.end();
VirgoLog.updateStep("saf3");
logger.end();
// // 记录debug日志,一般调试用
// logger.logDebug("jajajajaja");
// List l = new ArrayList();
// B b = new B();
// try {
// b.b();
// } catch (Exception e) {
// logger.logErr("woqu", e);
// }
}
Author: Pengfei
Source: CreditEase Institute of Technology