作用
可应用于埋点、日志处理、异常处理的通用需求。日志生成json格式,可通过ELK、EFK等框架采集日志,进行用户行为相关分析,对异常日志进行压缩,根据异常代码等方式,进行异常级别定义,分类告警等。研发人员毋须关注业务日志,兼备日志需关注的request入参与出参,也可对特定业务进行自定义日志打印。灵活度很高。
日志处理logback
1.目前针对日志可动态修改logback级别,日志等级可根据需要修改,便于定位和查找问题。
2.可动态修改整个xml,以文件形式装载。如修改日志个数,清空周期等。
异常统一处理
1.异常分类处理,针对数据库异常,返回数据库代码及解释,便于定位问题。
2.针对内部其他异常,可根据异常类型,进行相应提示。
3.提示内容根据用户自定义,可进行相应配置。
demo
demo地址:
链接:https://pan.baidu.com/s/1rdtrF0l5-DIMaRiYQlheCA
提取码:sd68
因未提交到中央库,settings需添加:
<repository>
<id>snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
pom.xml添加
<dependency>
<groupId>com.github.ywm130.itg</groupId>
<artifactId>ywm-itg-core</artifactId>
<version>0.0.2-SNAPSHOT</version>
</dependency>
代码示例:
package com.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.demo")
@ComponentScan("com.github.ywm.itg.core.*")
public class SpringBootdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootdemoApplication.class, args);
}
}
package com.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.github.ywm.itg.core.annotation.OperLog;
import com.github.ywm.itg.core.log.service.LogConfigService;
/**
* @Author: ywm
* @Date: 2021/1/1
*/
@RequestMapping("/log")
@RestController
public class LogController {
@Autowired
LogConfigService logConfigService;
@RequestMapping("/changeLevel")
@OperLog(operModul = "日志模块", operType = "更改日志级别", operDesc = "添加日志", operLevel = "info")
public String changeLevel(String name, String level) throws Exception {
logConfigService.changeLevel(name, level);
return "success";
}
// @ParamValidate
@RequestMapping("/updateLogByXml")
@OperLog(operModul = "日志模块", operType = "日志配置", operDesc = "更新日志配置", operLevel = "info")
public String updateLogByXml(@RequestBody() @PathVariable("file") MultipartFile file) throws Exception {
if (file.isEmpty()) {
return "{msg:文件不存在!请重新上传}";
}
logConfigService.updateLogByXml(file);
return "success";
}
}
package com.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.github.ywm.itg.core.annotation.OperLog;
@Controller
@RequestMapping("/app")
public class TestController {
@RequestMapping("/test")
@ResponseBody
@OperLog(operModul = "测试模块", operType = "测试日志", operDesc = "添加日志", operLevel = "info")
public String testDemo() {
return "Hello World!";
}
@RequestMapping("/test1")
@ResponseBody
public String test1() {
try {
int i = 1 / 0;
} catch (Exception e) {
throw e;
}
return "Hello World!";
}
}
新建logback.xml在resource目录
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="/home" />
<!--控制台日志, 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--文件日志, 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>./TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>-->
<pattern>%msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- show parameters for hibernate sql 专为 Hibernate 定制
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
<logger name="org.hibernate.SQL" level="DEBUG" />
<logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
<logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />
-->
<!--myibatis log configure
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
-->
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE"/>
</root>
</configuration>
最后在resouce目录,添加两个配置文件。
errorCode.properties
PARAMETER_ERROR=400,参数错误
NEED_LOGIN_ERROR=401,未登录,无权操作
URI_NOT_EXIST_ERROR=404,资源不存在
SERVER_ERROR=500,系统内部错误
CLASS_CAST_ERROR=10009, 系统发生转型异常!
METHOD_ARGUMENT_NOTVALID_ERROR=10010, 访问方法参数不正确!
NO_VALUE_SPECIFIED_FOR_DATE=10012, 复制JavaBean的时候Date对象没有值!
LOGIN_VERIFICATION_CODE_IS_WRONG=3001,验证码错误
LOGIN_LOGIN_NAME_OR_PASSWORD_IS_WRONG=3002,用户名或密码错误
LOGIN_LOGIN_TIME_IS_TOO_MUCH=3003,登录失败次数过多,请稍后再试
LOGIN_ACCOUNT_IS_LOCKED=3004,账号已被锁定
LOGIN_ACCOUNT_IS_DISABLED=3005,账号已被禁用
LOGIN_ACCOUNT_IS_EXPIRED=3006,账号已过期
FILE_TOO_LARGE=4001,文件太大
FILETYPE_ERROR=4002,文件类型错误
NO_HAVE_FILE=4003,文件不存在
sqlErrorCode.properties 该实例只包含mysql,其他数据库错误代码自行添加。
1005=创建表失败!
1006=创建数据库失败!
1007=数据库已存在,创建数据库失败!
1008=数据库不存在,删除数据库失败!
1009=不能删除数据库文件导致删除数据库失败!
1010=不能删除数据目录导致删除数据库失败!
1011=删除数据库文件失败!
1012=不能读取系统表中的记录!
1016=文件无法打开,使用后台修复或者联系管理员进行修复。!
1020=记录已被其他用户修改!
1021=硬盘剩余空间不足,请加大硬盘可用空间!
1022=关键字重复,更改记录失败!
1023=关闭时发生错误!
1024=读文件错误!
1025=更改名字时发生错误!
1026=写文件错误!
1032=记录不存在!
1036=数据表是只读的,不能对它进行修改!
1037=系统内存不足,请重启数据库或重启服务器!
1038=用于排序的内存不足,请增大排序缓冲区!
1040=已到达数据库的最大连接数,请加大数据库可用连接数!
1041=系统内存不足!
1042=无效的主机名!
1043=无效连接!
1044=当前用户没有访问数据库的权限!
1045=不能连接数据库,用户名或密码错误!
1048=字段不能为空!
1049=数据库不存在!
1050=数据表已存在!
1051=数据表不存在!
1054=字段不存在!
1064=数据库SQL语法出现错误!
1065=无效的SQL语句,SQL语句为空!
1081=不能建立Socket连接!
1114=数据表已满,不能容纳任何记录!
1116=打开的数据表太多!
1129=数据库出现异常,请重启数据库!
1130=连接数据库失败,没有连接数据库的权限!
1133=数据库用户不存在!
1141=当前用户无权访问数据库!
1142=当前用户无权访问数据表!
1143=当前用户无权访问数据表中的字段!
1146=数据表不存在!
1147=未定义用户对数据表的访问权限!
1149=SQL语句语法错误!
1158=网络错误,出现读错误,请检查网络连接状况!
1159=网络错误,读超时,请检查网络连接状况!
1160=网络错误,出现写错误,请检查网络连接状况!
1161=网络错误,写超时,请检查网络连接状况!
1062=字段值重复,入库失败!
1169=字段值重复,更新记录失败!
1177=打开数据表失败!
1180=提交事务失败!
1181=回滚事务失败!
1203=当前用户和数据库建立的连接已到达数据库的最大连接数,请增大可用的数据库连接数或重启数据库!
1205=加锁超时!
1211=当前用户没有创建用户的权限!
1216=外键约束检查失败,更新子表记录失败!
1217=外键约束检查失败,删除或修改主表记录失败!
1226=当前用户使用的资源已超过所允许的资源,请重启数据库或重启服务器!
1227=权限不足,您无权进行此操作!
1235=MySQL版本过低,不具有本功能!
1406=您输入的值过长!
注意:1.在springboot启动类,需添加注解@ComponentScan(“com.github.ywm.itg.core.*”)
2.logcontroller是简单的对日志动态修改的rest接口。
3.testcontroller测试日志与异常的测试类。
可应用postman进行测试。
生成日志格式日下:
{"excId":"141215799367696384","excRequParam":"{}","excName":"java.lang.ArithmeticException","excMessage":"java.lang.ArithmeticException:/ by zero\n\tcom.demo.controller.TestController.test1(TestController.java:24)\ncom.demo.controller.TestController$$FastClassBySpringCGLIB$$5b73dc42.invoke(<generated>)\norg.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)\norg.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)\norg.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\norg.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)\norg.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)\norg.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)\ncom.demo.controller.TestController$$EnhancerBySpringCGLIB$$80192328.test1(<generated>)\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\norg.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)\norg.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)\norg.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)\norg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)\norg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)\norg.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\norg.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)\norg.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)\n","operUri":"/app/test1","operIp":"127.0.0.1","operVer":"2.0","operCreateTime":"2021-02-24 16:21:05.107"}
{"operId":"141215809996062720","operModul":"测试模块","operType":"测试日志","operDesc":"添加日志","operMethod":"com.demo.controller.TestController.testDemo","operRequParam":"{}","operRespParam":"\"Hello World!\"","operIp":"127.0.0.1","operUri":"/app/test","operCreateTime":"2021-02-24 16:21:11.741","operVer":"2.0","sessionid":"95A4E40FB646FCD4AD36A3A07AE5AAFA"}