demo演示如何写一个无配置格式统一的日志

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 通过代码演示开发一套统一的、少配置的日志组件,方便使用。

一、背景

大量项目在使用logback记日志,有部分项目使用日志混乱,格式不统一,多数人搞不懂配置文件,导致配置错误,现在需要开发一套统一的、少配置的日志组件,方便使用。

二、设计思路

尽量采用0配置,无logback.xml

日志格式统一,方便后续日志分析系统

只有两个日志级别,一个是正常日志,一个是异常日志

提供log4j、jcl、logback、commons-log等桥接方案及版本兼容方案

提子线程、json格式化输出、map格式化、数组格式化、请求响应参数(供耗时)等便捷日志输出方法

支持redis、db、http自动开关配置**

新增日志类型(logger)

api采用流式结构,类似StringBuffer

三、概要设计

1、零配置

调研代码

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);}

上面代码等价于下面的xml


                    %d{MMddHHmmss.SSS} [%thread] %-5level %logger{36} - %msg%n

由此可以随意把配置文件中的内容以代码形式编写,理论已经可以实现0配置。

2、输出路径

约定固定将日志输出到,相对路径log/xxx.yyyy-MM-dd-HH.log,其中xxx为logger的name

3、日志格式

格式固定:
MMddHHmmss.SSS||id||【交易名子步骤】||context ||[level][线程号]
例:
150000.311||N-XrUTQzIc1531897200311||【CiTeeFilterci拦截器】||ci拦截器 请求的完整参数为:{"merchantId":["0012444"],"userId":["13112341232"]} ||[INFO][http-8091-7]

固定格式的核心代码,拦截到日志请求,按照格式拼装,主要方法为继承ThrowableProxyConverter和MessageConverter来实现对日志的拦截,并修改为想要的格式,其中使用的例如id等放到本地变量内,核心是对MDC的使用

4、基础logger

所有日志都默认输出到这里 logger name:service 系统初始化时,定义这个Logger和appender,即这个Logger为root log

5、自定义的logger

提供addLogger方法,参数 packageName 包名,例如:com.test 必输参数 如果name未设置时,name默认为包名最后一个.后面的字符 name 名字,决定日志文件的名字 非必输 path 日志路径 非必输 additivity 是否输出到root log内

6、特殊的log

提供特殊组件的log配置,例如:redis 默认ERROR http 默认ERROR db连接池 默认ERROR kafka 默认ERROR schedul 默认ERROR spring 默认ERROR

7、异常、换行日志处理

提供exception异常栈格式打印 提供带换行的格式化打印 代码思路:继承ThrowableProxyConverter,获取异常栈,在每行的前面插入固定格式文本

8、普通日志api(VirgoLog)

方法 方法描述
setUniqKey(id) 设置当前线程id,线程开始时设置即可,后面无需设置
updateStep(trade, step) 更新当前id的步骤信息
log(msg, param) 记录普通日志,msg替换规则,普通替换为{},如果想替换为业务日志api中的格式,使用``替换
logErr(msg, e) 记录异常日志
log( trade, step, msg, param) 记录普通日志,此方法会自动更新id、trade、step,不建议使用
logErr(trade, step, msg, e) 记录异常日志
log(cid, trade, step, msg, param) 记录普通日志,此方法会自动更新id、trade、step,不建议使用
logErr(cid, trade, step, msg, e) 记录异常日志
debug(msg, param) 记录debug级别日志,不建议使用

业务日志api(VirgoLog)

平时记日志时,如果某个类没有时间toString方法,会无法正确打印出数据,此时提供替换方法,直接将object替换为json打印,核心代码思路为

MessageFormatter是处理{}替换的类,重新写个类,稍加改动即支持{}也支持`` ,并判断替换为json还是toString

api如下

方法 方法描述
begin(msg) 记录开始
end(msg) 记录完成,会打印本线程内上一个begin到现在的耗时
logJson(json, format) 记录json格式化日志,format表示是否换行
logMap(map, format) 记录map格式化日志
logCollection(list, format) 记录集合格式化日志
logArray(array, format) 记录数组格式化日志
logObjct(obj, format) 记录Object格式化日志

系统api(LoggerHelper)

方法 方法描述
getLogger() 获取logger,用于记日志
getLogger(name) 通过name获取logger
addLogger() 参考自定义Logger,如果logger已经创建,则不再创建,一般不使用,除非想自定义日志名等
consoleOpen() 打开控制台日志,系统启动时默认配置控制台日志
commonOpen(name, level) 默认的组件都是error级别,这个方法可以变更日志级别,例如redis http等

9、特殊的格式化

map:即转化为json,然后再格式化

collection:同上

array:也同上

object:同上

10、问题

  • 密码脱敏、加解密有必要单独提取方法吗
  • 提供父线程打印开关

11、maven依赖

                    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);
//        }
    }

作者:刘鹏飞

来源:宜信技术学院

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
12天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
121 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
1月前
|
网络协议 Linux Windows
Rsyslog配置不同端口收集不同设备日志
Rsyslog配置不同端口收集不同设备日志
|
1月前
|
开发工具 git
git显示开发日志+WinSW——将.exe文件注册为服务的一个工具+图床PicGo+kubeconfig 多个集群配置 如何切换
git显示开发日志+WinSW——将.exe文件注册为服务的一个工具+图床PicGo+kubeconfig 多个集群配置 如何切换
38 1
|
1月前
|
数据采集 监控 Java
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
本文是关于SpringBoot日志的详细教程,涵盖日志的定义、用途、SLF4J框架的使用、日志级别、持久化、文件分割及格式配置等内容。
131 0
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
|
3月前
|
Java 应用服务中间件 HSF
Java应用结构规范问题之配置Logback以仅记录错误级别的日志到一个滚动文件中的问题如何解决
Java应用结构规范问题之配置Logback以仅记录错误级别的日志到一个滚动文件中的问题如何解决
|
3月前
|
Java 应用服务中间件 HSF
Java应用结构规范问题之配置Logback以在控制台输出日志的问题如何解决
Java应用结构规范问题之配置Logback以在控制台输出日志的问题如何解决
|
3月前
|
存储 Ubuntu Apache
如何在 Ubuntu VPS 上配置 Apache 的日志记录和日志轮转
如何在 Ubuntu VPS 上配置 Apache 的日志记录和日志轮转
47 6
|
3月前
|
存储 Ubuntu 应用服务中间件
如何在 Ubuntu VPS 上配置 Nginx 的日志记录和日志轮转
如何在 Ubuntu VPS 上配置 Nginx 的日志记录和日志轮转
33 4
|
3月前
|
存储 容器
【Azure 事件中心】为应用程序网关(Application Gateway with WAF) 配置诊断日志,发送到事件中心
【Azure 事件中心】为应用程序网关(Application Gateway with WAF) 配置诊断日志,发送到事件中心
|
3月前
|
人工智能
【Azure Application Insights】在Azure Function中启用Application Insights后,如何配置不输出某些日志到AI 的Trace中
【Azure Application Insights】在Azure Function中启用Application Insights后,如何配置不输出某些日志到AI 的Trace中