在某些情况下,您需要自定义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] [merc] [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.ca
- log4j.logger.error=errorfile
- log4j.a
- log4j.a
- 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.a
- log4j.a${log.dir}/${}.log
- log4j.a;.'yyyy-MM-dd
- log4j.a
- 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.a
- log4j.a${log.dir}/${}_error.log
- log4j.a;.'yyyy-MM-dd
- log4j.a = ERROR
- log4j.a
- 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.。
处理log4j的变量,对代码进行controller切面,在一个http请求java的入口中放入线程变量,该线程变量在当次http请求生命周期内生效。
切面代码如下:
- @Around("execution(public * com…*.*(..))")
- public Object aroundController(ProceedingJoinPoint joinPoint) {
- ServletrequestAttributes attributes =(ServletRequestAttributes) Reque();
- HttpServletRequest request =a();
- String execIp = reque("X-Real-IP");
- i(execIp)){
- execIp=reque();
- }
- String execClass= joinPoint.getTarget().getClass().getSimpleName();
- String execMethod = joinPoint.getSignature().getName();
- Map<String,String[]> map = reque();
- List<String> paramsList = new ArrayList<>();
- for;String,String []> m : map.entrySet()){
- String [] value = m.getValue();
- ( m.getKey() + "=" + S(value,","));
- }
- String execParams = "[" + S(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.;
- import net.;
- import org.a;
- import org.a;
- import org.a;
- import org.a;
- import java.lang.re;
- /**
- * @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");
- (true);
- Object exception = (event);
- JSONObject json = new JSONObject();
- if(exception != null){
- if(exception instanceof ThrowableInformation){
- ThrowableInformation throwableInformation = (ThrowableInformation) exception;
- String [] details = ();
- String error_msg = S(details,"rn");
- j("exception",error_msg);
- }
- }
- (event,null);
- boolean flag = false;
- Field filed1 = clazz.getDeclaredField("message");
- (true);
- Object message = (event);
- if (message instanceof String) {
- String msg = (String) message;
- if (message != null) {
- flag = true;
- }
- j("body", msg);
- (event, j());
- }
- if(!flag){
- Field filed2 = clazz.getDeclaredField("renderedMessage");
- (true);
- Object message2 = (event);
- if (message2 instanceof String) {
- String msg = (String) message2;
- j("body", msg);
- (event, j());
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- (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}"}
1.文章《log4j如何加载、log4j如何使用…》援引自互联网,为网友投稿收集整理,仅供学习和研究使用,内容仅代表作者本人观点,与本网站无关,侵删请点击页脚联系方式。
2.文章《log4j如何加载、log4j如何使用…》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
相关推荐
- . 现代买票为什么带上携程保险
- . 潮阳怎么去广州南站
- . 湖南马拉河怎么样
- . 烧纸为什么到三岔路口
- . 百色为什么这么热
- . 神州租车怎么样
- . 芜湖方特哪个适合儿童
- . 护肤品保养液是什么类目
- . 早晚的护肤保养有哪些项目
- . 女孩护肤品怎么保养的最好