Java知识点整理正在进行中,关注我,持续给您带来简单,实用的Java编程技巧。 最近在做一个接口项目,需要一个能够记录接口运行情况的监控日志。想在日志中记录:接口的输入参数,返回结果调用接口的IP地址,调用的是那个接口接口运行时的异常信息接口的响应时间 结合具体的使用环境,还需要:希望记录日志能以统一的方式运行,记录日志的代码不写在具体的业务逻辑中可以方便的设置是否记录日志在设置时可以灵活地确定记录在那个日志文件中 针对以上要求,结合前阵子做过的一个自定义注解记录接口运行时间的例子,发现这个需求可以认为是之前例子的升级版。整体思路梳理了下:使用AOP来截取调用接口的相关信息,包括请求的IP,请求的是那个接口,调用的参数和返回结果,还有异常信息使用自定义注解来确定是否记录日志使用注解的参数来确定日志记录到那个文件中 这样做就可以实现:业务代码与日志代码的解耦监控日志业务的灵活运用,可以方便的决定那个业务进行监控,同时可以灵活的调整日志记录在那个文件中 好,说干就干,代码开撸。1。引入依赖!AOP依赖dependencygroupIdorg。springframework。bootgroupIdspringbootstarteraopartifactIddependency!获取运行时长dependencygroupIdcom。google。guavagroupIdguavaartifactIdversion23。0versiondependency!转义JSONdependencygroupIdcom。alibabagroupIdfastjsonartifactIdversion1。2。75versiondependency2。编写自定义注解MonitorLogpackagecom。bbzd。mws。importjava。lang。annotation。ElementTimportjava。lang。annotation。Rimportjava。lang。annotation。RetentionPimportjava。lang。annotation。T用于监控日志的注解authormilldate2022101411:54Target(ElementType。METHOD)Retention(RetentionPolicy。RUNTIME)publicinterfaceMonitorLog{Stringvalue();}3。AOP的实现类packagecom。bbzd。mws。importcom。alibaba。fastjson。JSON;importcom。bbzd。mws。annotation。MonitorLimportcom。google。common。base。Simportorg。aspectj。lang。ProceedingJoinPimportorg。aspectj。lang。Simportorg。aspectj。lang。annotation。Aimportorg。aspectj。lang。annotation。Aimportorg。aspectj。lang。annotation。Pimportorg。aspectj。lang。reflect。MethodSimportorg。slf4j。Limportorg。slf4j。LoggerFimportorg。springframework。stereotype。Cimportorg。springframework。web。context。request。RequestContextHimportorg。springframework。web。context。request。ServletRequestAimportjavax。servlet。http。HttpServletRimportjavax。servlet。http。HttpServletRimportjava。util。ArrayLimportjava。util。Limportjava。util。concurrent。TimeU业务监控日志记录内容:请求IP,请求URI,业务类名,方法名,输入参数,返回值,异常信息date2022101210:12ComponentAspectpublicclassRequestParameterAOP{以注解MonitorLog标记的方法为切入点Pointcut(annotation(com。bbzd。mws。annotation。MonitorLog))publicvoidmethodArgs(){}Around(methodArgs())publicObjectinvoke(ProceedingJoinPointjoinPoint)throwsThrowable{StringBufferstringBuffernewStringBuffer();OStopwatchstopwatchStopwatch。createStarted();HttpServletRequesthttpServletRequest((ServletRequestAttributes)RequestContextHolder。getRequestAttributes())。getRequest();StringipAddrgetRemoteHost(httpServletRequest);StringrequestUrlhttpServletRequest。getRequestURI();stringBuffer。append(请求源IP〔ipAddr〕;);stringBuffer。append(请求URL〔requestUrl〕;);SignaturesignaturejoinPoint。getSignature();MethodSignaturemethodSignature(MethodSignature)类名String〔〕sourceNamesignature。getDeclaringTypeName()。split(。);StringfullNamesignature。getDeclaringTypeName();StringclassNamesourceName〔sourceName。length1〕;方法名StringmethodNamesignature。getName();stringBuffer。append(className。methodN);参数名数组String〔〕parameterNamesmethodSignature。getParameterNames();Class〔〕parameterTypesmethodSignature。getParameterTypes();构造参数组集合ListObjectargListnewArrayList();for(Objectarg:joinPoint。getArgs()){requestresponse无法使用toJSONif(arginstanceofHttpServletRequest){argList。add(request);}elseif(arginstanceofHttpServletResponse){argList。add(response);}else{argList。add(JSON。toJSON(arg));}}stringBuffer。append(请求参数:JSON。toJSON(parameterNames)JSON。toJSON(argList));try{resultjoinPoint。proceed();}catch(Exceptione){stringBuffer。append(异常:e。getMessage());log。info(获取参数失败:{},e。getMessage());}stopwatch。stop();longtimeConsumingstopwatch。elapsed(TimeUnit。MILLISECONDS);if(result!null){stringBuffer。append(请求结果:JSON。toJSON(result));}else{stringBuffer。append(请求结果:无);}stringBuffer。append(请求耗时:timeConsuming毫秒);LoggerloggergetLogger(fullName,methodName,parameterTypes);logger。info(stringBuffer。toString());}从请求中获取请求源IPparamrequestreturn请求源IPprivateStringgetRemoteHost(HttpServletRequestrequest){Stringiprequest。getHeader(xforwardedfor);if(ipnullip。length()0unknown。equalsIgnoreCase(ip)){iprequest。getHeader(ProxyClientIP);}if(ipnullip。length()0unknown。equalsIgnoreCase(ip)){iprequest。getHeader(WLProxyClientIP);}if(ipnullip。length()0unknown。equalsIgnoreCase(ip)){iprequest。getRemoteAddr();}returnip。contains(0:0:0:0:0:0:0:1)?127。0。0。1:}根据MonitorLog注解中的值,返回LoggerparamclassNameMonitorLog所在方法对应的类名parammethodNameMonitorLog所在方法对应的方法名paramparamTypesMonitorLog所在方法对应的参数名returnprivateLoggergetLogger(StringclassName,StringmethodName,Class〔〕paramTypes){StringlogNamecom。bbzd。mws。try{ClassclazzClass。forName(className);logNameclazz。getDeclaredMethod(methodName,paramTypes)。getAnnotation(MonitorLog。class)。value();}catch(Exceptione){e。printStackTrace();}LoggerloggerLoggerFactory。getLogger(logName);}}4。业务逻辑方法Overridecom。bbzd。mws。aop是logger的名称,需要在日志文件中进行对应的配置MonitorLog(valuecom。bbzd。mws。aop)publicUsergetUserName(ValidRequestBodyWebParam(nameUserVo)UserVovo)throwsConstraintViolationException{UserusernewUser(vo。getName(),vo。getAge());try{模拟异常情况,测试异常信息的记录inti10;}catch(NullPointerExceptionexception){exception。printStackTrace();}}5。日志配置文件!name属性值需要与注解的value属性值一样loggernamecom。bbzd。mws。aoplevelDEBUGadditivityfalselogger6。日志记录内容示例〔11:11:59。266〕〔INFO〕〔com。bbzd。mws。aop〕〔httpnio8889exec1〕请求源IP〔127。0。0。1〕;请求URL〔mwswsuser〕;UserServiceImpl。getUserN请求参数:〔vo〕〔{name:powerful,age:10}〕请求结果:{name:powerful,age:10}请求耗时:56毫秒 总结POM文件是代码片段配置文件是logback的代码片段其它文件是完整的代码关于logback日志框架及logback配置文件的使用方法,后面会整理一篇文章详细介绍下,想了解的小伙伴可以关注我。