# nicelog **Repository Path**: knifeedge/nicelog ## Basic Information - **Project Name**: nicelog - **Description**: Nicelog,强大的Java日志组件。支持:手动打印日志;自动收集Controller、XXL-JOB、Feign、RabbitMQ、RocketMQ、Kafka的日志等等。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-01-07 - **Last Updated**: 2026-01-18 ## Categories & Tags **Categories**: logging **Tags**: 开源项目 ## README # nicelog ## 1.介绍 nicelog:功能强大的Java日志组件。 ## 2.功能 **1. 手动打印** 手动打印日志。 **2. 自动收集日志** 在三处收集日志:进入时、返回时、报异常时。 默认情况下,只要你的项目里有相关的组件,比如XXL-JOB,就会自动收集其日志。 当前支持的组件有: 1. Controller 2. XXL-JOB 3. Feign 4. RabbitMQ 5. RocketMQ 6. Kafka 7. Scheduled 8. Bean的类或方法上加@NiceLog注解 9. 接管logback日志 **3. 更多功能** 准备支持:暂时没有。如果有需求请提issue **4. 版本信息** 1. JDK8及以上 2. SpringBoot2、SpringBoot3 3. Swagger、Swagger(V3) ## 3.快速开始 **1. 引入依赖** ```xml com.suchtool nicelog-spring-boot-starter {newest-version} ``` **2.使用示例** ``` @Api(tags = "用户管理") @RequestMapping("user") @RestController public class UserController { @ApiOperation(value = "注册") @PostMapping("register") public String register(@RequestBody UserBO userBO) { NiceLogUtil.createBuilder() .mark("我的打印") .info(); return "成功"; } } ``` 日志输出结果: ``` 2025-07-20 20:18:30.696 INFO 11920 --- [nio-8080-exec-1] c.s.n.p.impl.NiceLogProcessDefaultImpl : nicelog日志:{"mark":null,"businessNo":null,"message":null,"errorInfo":null,"errorDetailInfo":null,"recordStackTrace":null,"stackTraceDepth":null,"param":"{\"username\":\"Tony\",\"email\":\"aa@bb.com\"}","returnValue":null,"originReturnValue":null,"operatorId":null,"operatorName":null,"other1":null,"other2":null,"other3":null,"other4":null,"other5":null,"other6":null,"other7":null,"other8":null,"other9":null,"other10":null,"traceId":"9ecf5e0590514922b4add810012097cd","logTime":"2025-07-20T20:18:30.690","level":"INFO","directionType":"IN","entryType":"CONTROLLER","entry":"/user/register","entryClassTag":"用户管理","entryMethodTag":"注册","className":"com.knife.example.controller.UserController","classTag":"用户管理","methodName":"register","methodTag":"注册","methodDetail":"com.knife.example.controller.UserController.register(com.knife.example.bo.UserBO)","lineNumber":null,"classNameAndLineNumber":null,"callerStackTrace":null,"errorStackTrace":null,"appName":"","groupName":null,"clientIp":"11.11.11.11","callerIp":"11.11.11.11","hostIp":"11.11.11.11"} 2025-07-20 20:18:30.710 INFO 11920 --- [nio-8080-exec-1] c.s.n.p.impl.NiceLogProcessDefaultImpl : nicelog日志:{"mark":"我的打印","businessNo":null,"message":null,"errorInfo":null,"errorDetailInfo":null,"recordStackTrace":null,"stackTraceDepth":null,"param":null,"returnValue":null,"originReturnValue":null,"operatorId":null,"operatorName":null,"other1":null,"other2":null,"other3":null,"other4":null,"other5":null,"other6":null,"other7":null,"other8":null,"other9":null,"other10":null,"traceId":"9ecf5e0590514922b4add810012097cd","logTime":"2025-07-20T20:18:30.709","level":"INFO","directionType":"INNER","entryType":"MANUAL","entry":"/user/register","entryClassTag":"用户管理","entryMethodTag":"注册","className":"com.knife.example.controller.UserController","classTag":null,"methodName":"register","methodTag":null,"methodDetail":null,"lineNumber":"21","classNameAndLineNumber":"com.knife.example.controller.UserController:21","callerStackTrace":null,"errorStackTrace":null,"appName":"","groupName":null,"clientIp":null,"callerIp":null,"hostIp":"11.11.11.11"} 2025-07-20 20:18:30.713 INFO 11920 --- [nio-8080-exec-1] c.s.n.p.impl.NiceLogProcessDefaultImpl : nicelog日志:{"mark":null,"businessNo":null,"message":null,"errorInfo":null,"errorDetailInfo":null,"recordStackTrace":null,"stackTraceDepth":null,"param":null,"returnValue":"\"成功\"","originReturnValue":null,"operatorId":null,"operatorName":null,"other1":null,"other2":null,"other3":null,"other4":null,"other5":null,"other6":null,"other7":null,"other8":null,"other9":null,"other10":null,"traceId":"9ecf5e0590514922b4add810012097cd","logTime":"2025-07-20T20:18:30.713","level":"INFO","directionType":"OUT","entryType":"CONTROLLER","entry":"/user/register","entryClassTag":"用户管理","entryMethodTag":"注册","className":"com.knife.example.controller.UserController","classTag":"用户管理","methodName":"register","methodTag":"注册","methodDetail":"com.knife.example.controller.UserController.register(com.knife.example.bo.UserBO)","lineNumber":null,"classNameAndLineNumber":null,"callerStackTrace":null,"errorStackTrace":null,"appName":"","groupName":null,"clientIp":"11.11.11.11","callerIp":"11.11.11.11","hostIp":"11.11.11.11"} ``` ## 4 使用说明 ### 1. 打印日志 默认情况下,会通过logback输出(默认实现为:NiceLogProcessDefaultImpl)。 支持自定义处理日志,有两个方法。 #### 法1:继承NiceLogDetailProcessDefaultImpl类 部分接管日志处理(此方法自定义程度低,有默认的异步队列:自动捕获异常、队列数据维护、动态改变队列大小等)。 方法是:提供一个Bean,继承com.suchtool.nicelog.process.impl.NiceLogDetailProcessDefaultImpl,选择性地覆写以下方法: ```java /** * 预处理。默认是空逻辑 */ void preProcess(NiceLogInnerBO logInnerBO); /** * 同步记录。 * 默认: * 1. 若没启用logback接管,用logback输出; * 2. 若启用了logback接管 * 2.1 如果不是通过logback调用过来的,则用logback的控制台输出器输出 * 2.2 如果是通过logback调用过来的,就不再输出(防止重复记录)。 */ void recordSync(NiceLogInnerBO logInnerBO); /** * 异步记录。默认是空逻辑 */ void recordAsync(NiceLogInnerBO logInnerBO); ``` 示例: ```java import com.suchtool.nicelog.util.log.inner.bo.NiceLogInnerBO; import com.suchtool.nicetool.util.base.JsonUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; @Component public class CustomDetailProcessImpl extends NiceLogDetailProcessDefaultImpl { private final String KAFKA_LOG_TOPIC_PREFIX = "applog_"; @Autowired private KafkaTemplate kafkaTemplate; @Value("${spring.profiles.active}") private String env; /** * 预处理 */ @Override public void preProcess(NiceLogInnerBO logInnerBO) { // 这里可以修改字段,比如: // UserDTO userDTO = UserUtil.currentUser(); // if (userDTO != null) { // logInnerBO.setOperatorId(userDTO.getUserId()); // logInnerBO.setOperatorName(userDTO.getUserName()); // } } // 同步记录。这里不重写,用默认的即可 // @Override // public void recordSync(NiceLogInnerBO logInnerBO) { // if (!Boolean.TRUE.equals(niceLogProperty.getLogbackEnabled())) { // print(logInnerBO); // } else { // if (!EnhanceTypeEnum.LOGBACK.name().equals(logInnerBO.getEnhanceType())) { // printByLogbackConsole(logInnerBO); // } // } // } /** * 异步记录。这里发送到Kafka */ @Override public void recordAsync(NiceLogInnerBO logInnerBO) { kafkaTemplate.send(KAFKA_LOG_TOPIC_PREFIX + env, JsonUtil.toJsonString(logInnerBO)); } } ``` 注意:这里对应suchtool.nicelog.process配置: - 如果要启用异步记录,除了覆写recordAsync方法,还需要将suchtool.nicelog.process.enable-record-async配置为true。 #### 法2:实现NiceLogProcess接口 完全接管日志处理(此方法自定义程度最高) 方法是:提供一个Bean,实现com.suchtool.nicelog.process.NiceLogProcess接口,覆写void process(NiceLogInnerBO niceLogInnerBO)方法即可。 例如: ``` @Component public class CustomLogProcessor extends NiceLogProcess { @Override public void process(NiceLogInnerBO logInnerBO) { // 这里可以这么做: // 1.取出logInnerBO的字段值 // 2.打印到控制台或者上传到ES等 } } ``` ### 2. 自动收集日志 自动收集相关组件的日志。原理:使用AOP。 备注:AOP内部已捕获异常,如果有问题,不会影响正常业务执行。 ### 3. 手动打印日志 支持手动打印日志: ``` NiceLogUtil.createBuilder() .mark("创建订单") .info(); ``` 此工具支持通过链式构造参数并打印,每次输入.都会有代码提示y。 ### 4. 手动收集日志 在类或者方法上加@NiceLog,即可收集出入参、返回值、异常信息。 ### 5. 注解大全 | 注解 | 使用位置 | 作用 | 示例 | | ---- | --------- | ---- | ---- | | @NiceLog | 类/方法 | 自动收集某个类/方法的日志。如果配置了suchtool.nicelog.collect-all为false,可以使用此注解单独收集日志。 | @NiceLog(value = "用户注册", businessNoSpEL = "#userBO.username") | | @NiceLogIgnore | 类/方法 | 不自动收集此类/方法的日志 | @NiceLogIgnore | | @NiceLogIgnoreData | 类/方法 | 不自动收集此类/方法的数据(入参、返回值) | @NiceLogIgnoreData(ignorePram = true, ignoreReturnValue = false) | @NiceLog | 字段 | 描述 | 默认值 | |-----------|-----------------------|------| | value | 代表当前类或方法,用于classTag、methodTag字段。 | 空字符串 | | businessNoSpEL | 指定业务单号(SpEL),用于businessNo字段。如果参数是对象,这样写:#对象名.字段名,例如:#user.userName;如果参数不是对象,这样写:#字段名。例如:#orderNo | 空字符串 | @NiceLogIgnore 此注解无字段。 @NiceLogIgnoreData | 字段 | 描述 | 默认值 | |-----------|-----------------------|------| | ignoreParam| 忽略参数(不收集参数) | true | | ignoreReturnValue | 忽略返回值(不收集返回值) |true | ## 5.详细配置 ### 5.1 yml配置 支持SpringBoot的配置文件进行配置,比如:application.yml。 | 配置 | 描述 | 默认值 | 是否支持动态配置 | |------|------|--------|------------------| | suchtool.nicelog.enabled | 启用日志 | true | 否 | | suchtool.nicelog.log-level | 日志收集级别。支持:debug、info、warn、error | info | 是 | | suchtool.nicelog.stack-trace-package-name | 收集栈日志的包名(前缀)。为空则全部收集 | 空 | 是 | | suchtool.nicelog.caller-stack-trace-depth | 调用栈的深度。 | 6 | 是 | | suchtool.nicelog.auto-collect | 自动收集日志(Controller、XXL-JOB等) | true | 是 | | suchtool.nicelog.auto-collect-package-name | 自动收集的包名(前缀)。为空则全部收集 | 空 | 是 | | suchtool.nicelog.enable-controller-log | 启用Controller日志 | true | 否 | | suchtool.nicelog.enable-xxl-job-log| 启用XXL-JOB日志 | true | 否 | | suchtool.nicelog.enable-scheduled-log | 启用@Scheduled日志 | true | 否 | | suchtool.nicelog.enable-nice-log-annotation-log | 启用@NiceLog日志 | true | 否 | | suchtool.nicelog.enable-rabbit-mq-log | 启用RabbitMQ日志 | true | 否 | | suchtool.nicelog.enable-rocket-mq-log | 启用RocketMQ日志 | true | 否 | | suchtool.nicelog.enable-kafka-log | 启用Kafka日志 | true | 否 | | suchtool.nicelog.enable-feign-log | 启用Feign日志 | true | 否 | | suchtool.nicelog.ignore-feign-log-package-name | 不收集Feign日志的包名(前缀)。为空则全部收集 | 空 | 是 | | suchtool.nicelog.feign-trace-id-request-header | Feign的TraceId的请求Header名字 | Nice-Log-Trace-Id | 是 | | suchtool.nicelog.enable-controller-header-log | 启用Controller的Header日志 | false | 是 | | suchtool.nicelog.string-max-length | 字符串字段最大保留长度(数字类型) | null(不截断) | 是 | | suchtool.nicelog.logback-enabled | 启用logback的接管 | false | 否 | | suchtool.nicelog.logback-record-caller-stack-trace | 记录logback的调用栈 | false | 是 | | suchtool.nicelog.log-time-pattern | 日志时间模式 | yyyy-MM-dd'T'HH:mm:ss.SSS | 是 | | suchtool.nicelog.enable-ip-record | 启用IP记录 | true | 是 | | suchtool.nicelog.ignore-log-urls | 不记录日志的URL。支持通配符(AntPathMatcher) | 空 | 是 | | suchtool.nicelog.ignore-class-names | 忽略的类名(记录日志,但不序列化此类) | "org.springframework.validation.Errors"(比如:BindingResult),"org.springframework.core.io.InputStreamSource"(比如:MultipartFile), "javax.servlet.ServletResponse", "javax.servlet.ServletRequest", "jakarta.servlet.ServletResponse","jakarta.servlet.ServletRequest", "reactor.core.publisher.Flux" | 是 | | suchtool.nicelog.process.enable-record-sync | 启用同步记录。 | true | 是 | | suchtool.nicelog.process.enable-record-async | 启用异步记录。 | false | 是 | | suchtool.nicelog.process.record-async-queue-capacity | 异步记录的队列容量。 | 5000 | 是 | ### 5.2 设置优先级 可以用SpringBoot的配置文件指定它们的优先级,优先级越低,则执行顺序越靠前。 比如:一个@XxlJob方法,它的类上有@RestController,则哪个数值小,就优先调用其日志记录逻辑。 注意: 1. AOP是环状执行 1. 即:如果A比B的优先级的值小,则顺序为: 2. A的前置日志=> B的前置日志=> B的后置日志=> A的后置日志 2. @NiceLog例外,它不会与其他AOP都执行。 1. 比如:一个Controller上有@NiceLog注解,只会执行一次日志记录。 2. 原因:在设计上,@NiceLog是一个收集日志的标记,并不是一个程序入口类型。 ```yaml suchtool: nicelog: order: controller-log-order: 10000 # Controller接口日志的顺序。默认值: 10000 xxl-job-log-order: 10001 # XxlJob日志的顺序。默认值: 10001 rabbit-mq-log-order: 10002 # RabbitMQ日志的顺序。默认值: 10002 rocket-mq-log-order: 10003 # RocketMQ日志的顺序。默认值: 10003 kafka-log-order: 10004 # Kafka日志的顺序。默认值: 10004 feign-log-order: 10005 # Feign日志的顺序。默认值: 10005 feign-request-interceptor-order: 10006 # Feign请求拦截器的顺序。默认值: 10006 scheduled-log-order: 10007 # Scheduled日志的顺序。默认值: 10007 nice-log-annotation-log-order: 10008 # NiceLog注解日志的顺序。默认值: 10008 ``` ### 5.3 日志开关 默认会自动收集所有支持组件的日志。可以自由的开关: **场景1:不收集某个组件** 假如不收集Kafka的日志,就这样配置yml:suchtool.nicelog.enable-kafka-log=false **场景2:关闭所有组件,只收集标有@NiceLog的类或方法** 配置yml:suchtool.nicelog.collect-all=false **场景3:不收集某个类或方法** 在类或者方法上加注解:@NiceLogIgnore ### 5.4 收集Feign原始响应body 如果你没有自定义Feign的Decoder,是能够收集到原始响应body的。 如果你自定义了Feign的Decoder,则需要手动保存一下body,这样后边就能打印出来,例如: ``` @Configuration public class FeignLogResponseDecoder extends SpringDecoder { public FeignLogResponseDecoder(ObjectFactory messageConverters) { super(messageConverters); } @Override public Object decode(final Response response, Type type) throws IOException, FeignException { Response.Body body = response.body(); String bodyString = StreamUtils.copyToString(body.asInputStream(), StandardCharsets.UTF_8); // 这里将body保存下来 NiceLogFeignContextThreadLocal.saveOriginFeignResponseBody(bodyString); // body流只能读一次,必须重新封装一下 Response newResponse = response.toBuilder().body(bodyString, StandardCharsets.UTF_8).build(); return super.decode(newResponse, type); } } ``` ## 6. 字段的含义 | Key | 含义 | 备注 | |-----|-----|--------| | traceId | 链路id | 作为上下文传递 | | mark | 标记 | 手动时可自定义 | | logTime | 日志时间 | | | level | 级别 | DEBUG、INFO、WARN、ERROR | | directionType | 方向 | IN:方法进入;OUT:方法退出;INNER:方法内部执行 | | businessNo | 业务单号 | 手动时可自定义 | | message | 信息 | 手动时可自定义 | | errorInfo | 错误信息 | 手动时可自定义 | | errorDetailInfo | 错误详细信息 | 手动时可自定义 | | throwable | Throwable异常类 | 手动时可自定义。错误的栈追踪字符串会自动保存到NiceLogInnerBO.errorStackTrace | | stackTrace | 调用的栈追踪数组| 手动时可自定义。调用的栈追踪字符串会自动保存到NiceLogInnerBO.callerStackTrace | | recordStackTrace | 是否记录调用栈追踪 | 手动时可自定义。用于非异常时主动获得栈追踪,会将栈追踪字符串会保存到NiceLogInnerBO.callerStackTrace。若throwable不为空,则使用throwable的栈数据 | | stackTraceDepth | 手动时可自定义。调用栈追踪的深度 | 默认为null | | callerStackTrace | 调用的栈追踪字符串 | | | errorStackTrace | 错误的栈追踪字符串 | | | entryType | 入口类型 | MANUAL:手动;CONTROLLER:接口;RABBIT_MQ:RabbitMQ;XXL_JOB:XXL-JOB;NICE_LOG_ANNOTATION:NiceLog注解;FEIGN:Feign; ROCKETMQ:RocketMQ;KAFKA:Kafka | | entry | 入口 | 对于Controller,是URL;对于RabbitMQ,是@RabbitListener的queues;对于XXL-JOB,是@XxlJob的value;对于Feign,是URL;对于RocketMQ,是@RocketMQMessageListener的topic字段;对于Kafka,是@KafkaListener的topics字段。作为上下文传递。 | | entryClassTag | 入口类的tag | 取值优先级为:先取@NiceLog的value,若为空则取:对于Controller:Controller类上的@Api的tags > Controller类上的@Api的value;对于Feign:@FeignClient的value字段。作为上下文传递。 | | entryMethodTag | 入口方法的tag | 取值优先级为:@NiceLogOperation的value > @NiceLog的value > Controller方法上的@ApiOperation的value。作为上下文传递。 | | className | 类名 | | | classTag | 当前类的tag | 取值同entryClassTag,但不作为上下文传递。 | | methodName | 方法名 | | | methodTag | 当前方法的tag | 取值同entryMethodTag,但不作为上下文传递。 | | methodDetail | 方法详情 | 全限定类名+方法名+全限定参数 | | lineNumber | 代码行号 | 只在手动输出时有值。 | | classNameAndLineNumber | 类名及代码行号,中间用:隔开 | 只在手动输出时有值。 | | param | 入参 | 手动时可自定义 | | returnValue | 返回值 | 手动时可自定义 | | originReturnValue | 原始返回值 | 手动时可自定义 | | requestHeader | 请求头 | 支持Controller | | responseHeader | 响应头 | 支持Controller。注意:只能获取Controller内设置的Header。 | | operatorId | 操作人ID | 手动时可自定义 | | operatorName | 操作人名字 | 手动时可自定义 | | enhanceType | 增强类型 | 手动时可自定义。比如:LOGBACK | | appName | 应用名字 | 取spring.application.name配置 | | groupName | 组名字 | 用于区分应用所在的组,建议放到公共组件里指定 | | clientIp | 客户端IP | | | callerIp | 调用方IP | | | hostIp | 主机IP | | | other1~other10 | 其他 | 手动时可自定义 | ## 7. ES语句 如果想将日志存储到ES,以下是推荐使用的建索引语句。 ### ES 待补充