log4j控制日志输出文件名称的两种方式小结

 更新时间:2021年12月27日 10:47:42   作者:生活不只*眼前的苟且  
这篇文章主要介绍了log4j控制日志输出文件名称的两种方式小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

log4j控制日志输出文件名称

1. 第一种方式

在类对象中用如下方式定义logger变量

private static Logger logger = Logger.getLogger("lemmaXml");

这样通过名称的方式获取logger,需要在log4j.properties文件中定义一个名称为lemmaXml的appender,配置如下:

log4j.logger.lemmaXml=INFO,lemmaXml
log4j.appender.lemmaXml=org.apache.log4j.DailyRollingFileAppender
log4j.appender.lemmaXml.Threshold=DEBUG
log4j.appender.lemmaXml.File=${catalina.home}/logs/lemmaXml.log
log4j.appender.lemmaXml.layout=org.apache.log4j.PatternLayout
log4j.appender.lemmaXml.layout.ConversionPattern=%5p %d{yyyy-MM-dd HH:mm:ss} %m %n

上述配置说明,名称为lemmaXml的appender,是每天形成一个日志文件,日志文件的名称为

${catalina.home}/logs/lemmaXml.log

日志的格式为

%5p %d{yyyy-MM-dd HH:mm:ss} %m %n

2. 第二种方式(这种方式亲测正确)

在类对象中用如下方式定义logger变量

import org.apache.log4j.Logger;
private static Logger logger = Logger.getLogger(ExportLemmaManagerService.class);

即,通过类的参数来获取logger变量,此时必然也需要在log4j.properties文件有关于该对象日志文件的输出配置,当然这里的配置不是针对每个类专门配置,而是针对一个路径整体配置,即,你可以配置某个目录下的所有类方式的输出文件的文件名称,如下

log4j.rootLogger=info,stdout 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Threshold=DEBUG
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d{yyyy-MM-dd HH:mm:ss} %c %m %n
  
log4j.logger.com.soso.baike.service=DEBUG,ServiceLog
log4j.appender.ServiceLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.ServiceLog.Threshold=DEBUG
log4j.appender.ServiceLog.File=${catalina.home}/logs/service.log
log4j.appender.ServiceLog.MaxBackupIndex=10
log4j.appender.ServiceLog.layout=org.apache.log4j.PatternLayout
log4j.appender.ServiceLog.layout.ConversionPattern=%5p %d{yyyy-MM-dd HH:mm:ss} %c %m %n

上述配置了目录com.soso.baike.service下的输出文件方式,上述ExportLemmaManagerService类就是在该包下,所以用该包下的类方式来定义logger的话,输出的文件就都在service.log文件中,每天生成一个新的日志文件。

如何随心所欲地自定义log4j输出格式

在某种情况下,我们需要在不影响原有代码的基础上自定义log4j的输出格式。

例如这样的需求,硬性规定了项目的日志格式为:

日期 日志等级 ClassName:line - [版本号] [请求ip地址] [项目应用名称] [服务接口模块] [模块方法] [业务参数1] [业务参数2] [业务参数3] 日志详细内容(必须为json格式)

示例:

2018-05-10 14:04:50,972 INFO ViolationService:51 - [v1.0.0] [192.168.137.47] [merchant-service.cx580.com] [OrderController] [messageList] [null] [] [] {"body":"订单状态消息列表resp:{\"code\":1000,\"msg\":\"成功\"}"}

其中:

  • 版本号是指当前服务接口实际的版本信息,例如V1.0.1;
  • 请求ip地址为用户真实的请求ip;
  • 项目应用名称为项目的名称或者标识,例如支付服务定义应用名称为payService;
  • 服务接口模块是指请求接口对应的模块代码,例如请求订单接口,则接口模块为OrderControlller;
  • 模块方法是指接口对应的请求方法,例如下单接口对应模块方法为createOrder;
  • 业务参数1可根据实际情况写入相应的业务数据,录入订单号orderId,该参数可为空;
  • 业务参数2同上;
  • 业务参数3同上;
  • 日志详细内容是指请求接口时需打印出来的描述信息,例如创建订单异常时,在异常捕捉方法体中描述异常详细信息,日志内容需定义到一个json结构中。

以上是我遇到的场景,这时在不影响原有项目代码的基础上,我们做出日志格式的调整,使用如下方案:

1.通过log4j的占位替换符%X{}配合MDC格式化日志,使用AOP切面在请求线程开始处填充替换符变量

2.继承log4j的具体appender类,重写subAppend方法,修改日志输出的内容格式。

此时log4j文件如下

log4j.rootCategory=INFO, stdout, file, errorfile
#log4j.category.com.cx=DEBUG
log4j.logger.error=errorfile
 
log4j.appender.stdout=com.test.common.GrayLogConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L%X{log_version}%X{log_ip}%X{log_item}%X{log_module}%X{log_method}%X{log_req_params} %m%n
 
log4j.appender.file=com.test.common.GrayLogDailyRollingFileAppender
log4j.appender.file.file=${log.dir}/${spring.application.name}.log
log4j.appender.file.DatePattern='.'yyyy-MM-dd
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L%X{log_version}%X{log_ip}%X{log_item}%X{log_module}%X{log_method}%X{log_req_params} %m%n
 
log4j.appender.errorfile=com.test.common.GrayLogDailyRollingFileAppender
log4j.appender.errorfile.file=${log.dir}/${spring.application.name}_error.log
log4j.appender.errorfile.DatePattern='.'yyyy-MM-dd
log4j.appender.errorfile.Threshold = ERROR
log4j.appender.errorfile.layout=org.apache.log4j.PatternLayout
log4j.appender.errorfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L%X{log_version}%X{log_ip}%X{log_item}%X{log_module}%X{log_method}%X{log_req_params} %m%n

在log4j.properties文件,我们做了两个变动,一个是添加了%X{value}的变量,另一个则是将原本的DailyRollingFileAppender修改成了com.test.common.GrayLogConsoleAppender。

处理log4j的变量,对代码进行controller切面,在一个http请求java的入口中放入线程变量,该线程变量在当次http请求生命周期内生效。

切面代码如下:

@Around("execution(public * com.test.controller..*.*(..))")
    public Object aroundController(ProceedingJoinPoint joinPoint) {
        ServletRequestAttributes attributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request =attributes.getRequest();
        String execIp = request.getHeader("X-Real-IP");
        if(StringUtils.isBlank(execIp)){
            execIp=request.getRemoteAddr();
        }
        String execClass= joinPoint.getTarget().getClass().getSimpleName();
        String execMethod = joinPoint.getSignature().getName();
        Map<String,String[]> map = request.getParameterMap();
        List<String> paramsList = new ArrayList<>();
        for(Map.Entry<String,String []> m : map.entrySet()){
            String [] value = m.getValue();
            paramsList.add( m.getKey() + "=" + StringUtils.join(value,","));
        }
 
        String execParams = "[" + StringUtils.join(paramsList,"&") + "] [] []";
        MDC.put("log_version"," - [V1.0.0]");
        MDC.put("log_item"," [violation-mini]");
        MDC.put("log_module"," [" + execClass + "]");
        MDC.put("log_method"," [" + execMethod+ "]");
        MDC.put("log_req_params"," " + execParams);
        MDC.put("log_ip"," [" + execIp+ "]");
        Object result= null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            LOGGER.error("方法异常:",throwable);
        }
        return result;
    }

至此,格式中的MDC变量都已被放入成功。

下一步,将原本的日志内容套上json外套。

新建GrayLogConsoleAppender类继承具体的appender类

代码如下:

package com.test.common; 
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation; 
import java.lang.reflect.Field;
 
/**
 * @Author: Lxx
 * @Description:
 * @Date: Created in 17:29 2018/5/30
 */
public class GrayLogConsoleAppender extends ConsoleAppender {
    @Override
    protected void subAppend(LoggingEvent event) {
        try {
            Class<LoggingEvent> clazz = LoggingEvent.class;
            Field filed = clazz.getDeclaredField("throwableInfo");
            filed.setAccessible(true);
            Object exception = filed.get(event);
            JSONObject json = new JSONObject();
            if(exception != null){
                if(exception instanceof ThrowableInformation){
                    ThrowableInformation throwableInformation = (ThrowableInformation) exception;
                    String [] details = throwableInformation.getThrowableStrRep();
                    String error_msg = StringUtils.join(details,"\r\n");
                    json.put("exception",error_msg);
                }
            }
            filed.set(event,null);
            boolean flag = false;
            Field filed1 = clazz.getDeclaredField("message");
            filed1.setAccessible(true);
            Object message = filed1.get(event);
            if (message instanceof String) {
                String msg = (String) message;
                if (message != null) {
                    flag = true;
                }
                json.put("body", msg);
                filed1.set(event, json.toString());
            }
            if(!flag){
                Field filed2 = clazz.getDeclaredField("renderedMessage");
                filed2.setAccessible(true);
                Object message2 = filed2.get(event);
                if (message2 instanceof String) {
                    String msg = (String) message2;
                    json.put("body", msg);
                    filed2.set(event, json.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        super.subAppend(event);
    }
}

至此,已为日志内容套上json外套,并且当有异常日志时,将异常的堆栈信息放入json的exception中输出出来,不打印堆栈信息。

最终结果:

2018-06-09 00:48:31,849 INFO LogAspect:65 - [V1.0.0] [223.88.53.135] [violation-mini] [TestController] [queryList] [appName=abc&authType=test&avatar=&nickName=&token=asdfasdfadsfasdf&userId=asdfasdfasdfasdf&userType=aaaaa] [] [] {"body":"结果为:ResponseResult{code='0', msg='null', errormsg='查询成功', data={}, successFlag=false}"}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • springCloud中的Sidecar多语言支持详解

    springCloud中的Sidecar多语言支持详解

    这篇文章主要介绍了springCloud中的Sidecar多语言支持详解,Sidecar是将一组紧密结合的任务与主应用程序共同放在一台主机Host中,但会将它们部署在各自的进程或容器中,需要的朋友可以参考下
    2024-01-01
  • Linux系统卸载重装JDK的完整流程

    Linux系统卸载重装JDK的完整流程

    Linux系统有时候会默认使用OpenJDK版本,需要卸载后重新安装自己需要的JDK版本,下面这篇文章主要给大家介绍了关于Linux系统卸载重装JDK的完整流程,需要的朋友可以参考下
    2024-02-02
  • Java通过JsApi方式实现微信支付

    Java通过JsApi方式实现微信支付

    本文讲解了Java如何实现JsApi方式的微信支付,代码内容详细,文章思路清晰,需要的朋友可以参考下
    2015-07-07
  • spring设置拦截器代码实例

    spring设置拦截器代码实例

    这篇文章主要介绍了spring设置拦截器代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Java正则表达式匹配不到结果的解决

    Java正则表达式匹配不到结果的解决

    这篇文章主要介绍了Java正则表达式匹配不到结果的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • Java集合ArrayDeque类实例分析

    Java集合ArrayDeque类实例分析

    这篇文章主要介绍了Java集合ArrayDeque类实例分析的相关资料,需要的朋友可以参考下
    2017-04-04
  • 浅谈Java slf4j日志简单理解

    浅谈Java slf4j日志简单理解

    这篇文章主要介绍了浅谈Java日志简单理解,详细的介绍了slf4j的概念和使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • idea中git提交的代码如何回退到指定版本

    idea中git提交的代码如何回退到指定版本

    文章详细介绍了如何在本地和远程仓库中回退到指定的Git版本,通过步骤说明了如何使用Git命令和右键菜单选项来实现这一操作
    2024-11-11
  • SpringBoot密码加密的实现示例

    SpringBoot密码加密的实现示例

    本文主要介绍了SpringBoot密码加密的实现示例,包括引入依赖、配置加密工具、生成加密密钥、加密密码、配置解密,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • java基础的详细了解第五天

    java基础的详细了解第五天

    这篇文章对Java编程语言的基础知识作了一个较为全面的汇总,在这里给大家分享一下。需要的朋友可以参考,希望能给你带来帮助
    2021-08-08

最新评论