精华内容
下载资源
问答
  • 二,代码实现 基于注解的Aop日志记录 1.Log实体类 package com.vulcan.facade.operationlog.entity; import lombok.Data; import org.springframework.data.annotation.Id; import javax.persistence....

    一,功能点

    实现管理员操作数据的记录。效果如下

    二,代码实现

    基于注解的Aop日志记录

    1.Log实体类

    package com.vulcan.facade.operationlog.entity;
    
    import lombok.Data;
    import org.springframework.data.annotation.Id;
    
    import javax.persistence.Column;
    import javax.persistence.Table;
    import java.io.Serializable;
    import java.util.Date;
    
    
    /**
     * @author lzh
     * @version 1.0
     * @describe 操作日志
     * @date 20190413
     * @copyright by lzh
     */
    @Data
    @Table(name = "*****")
    public class OperationLog implements Serializable {
    
        /**
         * 主键id
         */
        @Id
        private Long id;
    
    
        /**
         * 用户id
         */
        @Column(name = "user_id")
        private Long userId;
    
    
        /**
         * 用户名称
         */
        @Column(name = "user_name")
        private String userName;
    
    
        /**
         * 描述
         */
        @Column(name = "description")
        private String description;
        /**
         * 模块
         */
        @Column(name = "module")
        private String module;
    
        /**
         * 操作详情
         *a
         */
        @Column(name = "content")
        private String content;
    
        /**
         * 请求ip
         *
         */
        @Column(name = "ip")
        private String ip;
    
    
        /**
         * 创建时间
         */
        @Column(name = "create_time")
        private Date createTime;
    
    
    }
    

    2.定义注解

    package com.vulcan.log.annotation;
    
    import java.lang.annotation.*;
    
    
    /**
     * @author lzh
     * @date 20190413
     * 定义注解
     */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Log {
    
        /**模块*/
        String module() default "";
    
        /**描述*/
        String description() default "";
    }
    

    3.定义切面

    package com.vulcan.log.aop;
    
    import com.vulcan.base.BaseController;
    import com.vulcan.facade.permission.vo.SessionUserVO;
    import com.vulcan.log.annotation.Log;
    import com.vulcan.log.service.LogService;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    
    /**
     * 日志切面
     * @author vlzh
     * @date 20190413
     */
    
    @Aspect
    @Component
    public class LogAspect extends BaseController {
    
    
        @Autowired
        private LogService logService;
        /**
         * 日志切入点
         */
        @Pointcut("@annotation(com.vulcan.log.annotation.Log)")
        public void logPointCut(){}
    
    
        @AfterReturning(pointcut = "logPointCut()")
        public void doAfter(JoinPoint joinPoint){
            /**
             * 解析Log注解
             */
            SessionUserVO sessionUserVO = getLoginUser();
    
            String methodName = joinPoint.getSignature().getName();
            Method method = currentMethod(joinPoint,methodName);
            Log log = method.getAnnotation(Log.class);
            String module = log.module();
            String description = log.description();
    
            logService.put(joinPoint,methodName,module,description,sessionUserVO.getUserName(),sessionUserVO.getId());
        }
    
        /**
         * 获取当前执行的方法
         *
         * @param joinPoint  连接点
         * @param methodName 方法名称
         * @return 方法
         */
        private Method currentMethod(JoinPoint joinPoint, String methodName) {
            /**
             * 获取目标类的所有方法,找到当前要执行的方法
             */
            Method[] methods = joinPoint.getTarget().getClass().getMethods();
            Method resultMethod = null;
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    resultMethod = method;
                    break;
                }
            }
            return resultMethod;
        }
    
    }
    

    4.业务处理:LogService

    package com.vulcan.log.impl;
    
    import com.alibaba.dubbo.config.annotation.Reference;
    import com.alibaba.fastjson.JSONObject;
    import com.vulcan.common.util.http.IPUtil;
    import com.vulcan.facade.operationlog.entity.OperationLog;
    import com.vulcan.facade.operationlog.service.OperationLogService;
    import com.vulcan.facade.operationlog.vo.OperationLogVO;
    import com.vulcan.log.service.LogService;
    import javassist.*;
    import javassist.bytecode.CodeAttribute;
    import javassist.bytecode.LocalVariableAttribute;
    import javassist.bytecode.MethodInfo;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.springframework.stereotype.Component;
    import org.springframework.util.CollectionUtils;
    import org.springframework.util.StringUtils;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.*;
    
    @Component
    @Slf4j
    public class LogServiceImpl implements LogService {
    
        private static final String LOG_CONTENT = "[类名]:%s,[方法]:%s,[参数]:%s,[IP]:%s";
    
        private String username;
    
        @Reference(version = "1.0.0")
        private OperationLogService operationLogService;
    
    
    
    
        public String initUsername(String username) {
            if(!StringUtils.isEmpty(username)){
                this.username = username;
            }
            return this.username;
        }
    
    
        public void put(JoinPoint joinPoint, String methodName, String module, String description, String userName, Long userId) {
            try {
                HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                OperationLog log = new OperationLog();
                if (StringUtils.isEmpty(userName)) {
                    username =  "未知用户";
                }
    
                String ip = IPUtil.getIpAddress(request);
                log.setUserId(userId);
                log.setUserName(userName);
                log.setModule(module);
                log.setCreateTime(new Date());
                log.setDescription(description);
                log.setIp(ip);
                log.setContent(operateContent(joinPoint, methodName, ip, request));
                operationLogService.insert(log);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * 查询所有日志
         * @param pageNum
         * @param request
         * @return
         */
        public List<OperationLogVO> findAllLog(int pageNum, HttpServletRequest request) {
            return null;
        }
    
    
        public String operateContent(JoinPoint joinPoint, String methodName, String ip, HttpServletRequest request) throws ClassNotFoundException, NotFoundException {
            String className = joinPoint.getTarget().getClass().getName();
            Object[] params = joinPoint.getArgs();
            String classType = joinPoint.getTarget().getClass().getName();
            Class<?> clazz = Class.forName(classType);
            String clazzName = clazz.getName();
            Map<String,Object > nameAndArgs = getFieldsName(this.getClass(), clazzName, methodName,params);
            StringBuffer bf = new StringBuffer();
            if (!CollectionUtils.isEmpty(nameAndArgs)){
                Iterator it = nameAndArgs.entrySet().iterator();
                while (it.hasNext()){
                    Map.Entry entry = (Map.Entry) it.next();
                    String key = (String) entry.getKey();
                    String value = JSONObject.toJSONString(entry.getValue());
                    bf.append(key).append("=");
                    bf.append(value).append("&");
                }
            }
            if (StringUtils.isEmpty(bf.toString())){
                bf.append(request.getQueryString());
            }
            return String.format(LOG_CONTENT, className, methodName, bf.toString(), ip);
        }
    
        private Map<String,Object> getFieldsName(Class cls, String clazzName, String methodName,Object[] args) throws NotFoundException {
            Map<String,Object > map=new HashMap<String,Object>();
    
            ClassPool pool = ClassPool.getDefault();
            ClassClassPath classPath = new ClassClassPath(cls);
            pool.insertClassPath(classPath);
    
            CtClass cc = pool.get(clazzName);
            CtMethod cm = cc.getDeclaredMethod(methodName);
            MethodInfo methodInfo = cm.getMethodInfo();
            CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
            LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
            if (attr == null) {
                // exception
                return map;
            }
            int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
            for (int i = 0; i < cm.getParameterTypes().length; i++){
                map.put( attr.variableName(i + pos),args[i]);//paramNames即参数名
            }
            return map;
        }
    }
    

    5、mapper

    package com.vulcan.facade.mapper;
    
    import com.vulcan.common.core.base.BaseMapper;
    import com.vulcan.facade.operationlog.entity.OperationLog;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface LogMapper extends BaseMapper<OperationLog> {
    
    }
    

    三,使用注解在需要的地方记录日志

      /**
         * @author: lzh
         * @description:获取订单列表数据
         * @createDate: 14:06 2019/04/04
         * @param orderDTO
         * @param pagebean
         * @return: Result
         * @version: 1.0
         */
        @Log(module = "订单监控",description = "订单列表")
        @RequestMapping(value = "list", method = RequestMethod.POST)
        @ResponseBody
        public Result getOrderListPage(OrderDTO orderDTO, PageBean pagebean){
            log.info("分页查询订单参数queryOrderDTO={},pageBean={}", JSON.toJSONString(orderDTO),JSON.toJSONString(pagebean));
            Result result = this.getListOrder(orderDTO,pagebean);
            log.info("分页查询订单处理结果result={}", JSON.toJSONString(result));
            return result;
        }

     

    展开全文
  • Java 代码里的日志输出优化

    千次阅读 2019-07-01 10:59:45
    实现方式统一使用: Logback框架 打日志的正确方式 什么时候应该打日志 当你遇到问题的时候,只能通过debug功能来确定问题,你应该考虑打日志,良好的系统,是可以通过日志进行问题定为的。 当你碰到if…else 或者 ...

    使用slf4j

    1. 使用门面模式的日志框架,有利于维护和各个2类的日志处理方式统一。
    2. 实现方式统一使用: Logback框架

    打日志的正确方式

    什么时候应该打日志

    1. 当你遇到问题的时候,只能通过debug功能来确定问题,你应该考虑打日志,良好的系统,是可以通过日志进行问题定为的。
    2. 当你碰到if…else 或者 switch这样的分支时,要在分支的首行打印日志,用来确定进入了哪个分支
    3. 经常以功能为核心进行开发,你应该在提交代码前,可以确定通过日志可以看到整个流程

    基本格式

    必须使用参数化信息的方式:

    logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);
    

    对于debug日志,必须判断是否为debug级别后,才进行使用:

    if (logger.isDebugEnabled()) {
        logger.debug("Processing trade with id: " +id + " symbol: " + symbol);
    }
    

    不要进行字符串拼接,那样会产生很多String对象,占用空间,影响性能。
    反例(不要这么做):

    logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
    

    使用[]进行参数变量隔离
    如有参数变量,应该写成如下写法:

    logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);
    

    这样的格式写法,可读性更好,对于排查问题更有帮助。

    不同级别的使用

    ERROR:

    基本概念

    影响到程序正常运行、当前请求正常运行的异常情况:

    1. 打开配置文件失败
    2. 所有第三方对接的异常(包括第三方返回错误码)
    3. 所有影响功能使用的异常,包括:SQLException和除了业务异常之外的所有异常(RuntimeException和Exception)

    不应该出现的情况:

    1. 比如要使用Azure传图片,但是Azure未响应

    如果有Throwable信息,需要记录完成的堆栈信息:

    log.error("获取用户[{}]的用户信息时出错",userName,e);
    

    说明

    1. 如果进行了抛出异常操作,请不要记录error日志,由最终处理方进行处理:

    反例(不要这么做):

    try{
        ....
    }catch(Exception ex){
      String errorMessage=String.format("Error while reading information of user [%s]",userName);
      logger.error(errorMessage,ex);
      throw new UserServiceException(errorMessage,ex);
    }
    

    WARN

    基本概念

    不应该出现但是不影响程序、当前请求正常运行的异常情况:

    1. 有容错机制的时候出现的错误情况
    2. 找不到配置文件,但是系统能自动创建配置文件

    即将接近临界值的时候,例如:

    1. 缓存池占用达到警告线

    业务异常的记录,比如:

    1. 当接口抛出业务异常时,应该记录此异常

    INFO:

    基本概念

    系统运行信息

    1. Service方法中对于系统/业务状态的变更
    2. 主要逻辑中的分步骤

    外部接口部分

    1. 客户端请求参数(REST/WS)
    2. 调用第三方时的调用参数和调用结果

    说明

    1. 并不是所有的service都进行出入口打点记录,单一、简单service是没有意义的(job除外,job需要记录开始和结束,)。

    反例(不要这么做):

    public List listByBaseType(Integer baseTypeId) {
    
    
       log.info("开始查询基地");
    BaseExample ex=new BaseExample();
    BaseExample.Criteria ctr = ex.createCriteria();
    ctr.andIsDeleteEqualTo(IsDelete.USE.getValue());
    Optionals.doIfPresent(baseTypeId, ctr::andBaseTypeIdEqualTo);
       log.info("查询基地结束");
    return baseRepository.selectByExample(ex);
    
    
    }
    
    1. 对于复杂的业务逻辑,需要进行日志打点,以及埋点记录,比如电商系统中的下订单逻辑,以及OrderAction操作(业务状态变更)。

    2. 对于整个系统的提供出的接口(REST/WS),使用info记录入参

    3. 如果所有的service为SOA架构,那么可以看成是一个外部接口提供方,那么必须记录入参。

    4. 调用其他第三方服务时,所有的出参和入参是必须要记录的(因为你很难追溯第三方模块发生的问题)

    DEBUG

    基本概念

    可以填写所有的想知道的相关信息(但不代表可以随便写,debug信息要有意义,最好有相关参数)
    生产环境需要关闭DEBUG信息
    如果在生产情况下需要开启DEBUG,需要使用开关进行管理,不能一直开启。
    说明

    如果代码中出现以下代码,可以进行优化:

    //1. 获取用户基本薪资

    //2. 获取用户休假情况

    //3. 计算用户应得薪资
    优化后的代码:

    logger.debug("开始获取员工[{}] [{}]年基本薪资",employee,year);
    
    logger.debug("获取员工[{}] [{}]年的基本薪资为[{}]",employee,year,basicSalary);
    logger.debug("开始获取员工[{}] [{}]年[{}]月休假情况",employee,year,month);
    
    logger.debug("员工[{}][{}]年[{}]月年假/病假/事假为[{}]/[{}]/[{}]",employee,year,month,annualLeaveDays,sickLeaveDays,noPayLeaveDays);
    logger.debug("开始计算员工[{}][{}]年[{}]月应得薪资",employee,year,month);
    
    logger.debug("员工[{}] [{}]年[{}]月应得薪资为[{}]",employee,year,month,actualSalary);
    

    TRACE

    基本概念

    特别详细的系统运行完成信息,业务代码中,不要使用.(除非有特殊用意,否则请使用DEBUG级别替代)

    规范示例说明

    @Override
    @Transactional
    public void createUserAndBindMobile(@NotBlank String mobile, @NotNull User user) throws CreateConflictException{
        boolean debug = log.isDebugEnabled();
        if(debug){
            log.debug("开始创建用户并绑定手机号. args[mobile=[{}],user=[{}]]", mobile, LogObjects.toString(user));
        }
        try {
            user.setCreateTime(new Date());
            user.setUpdateTime(new Date());
            userRepository.insertSelective(user);
            if(debug){
                log.debug("创建用户信息成功. insertedUser=[{}]",LogObjects.toString(user));
            }
            UserMobileRelationship relationship = new UserMobileRelationship();
            relationship.setMobile(mobile);
            relationship.setOpenId(user.getOpenId());
            relationship.setCreateTime(new Date());
            relationship.setUpdateTime(new Date());
            userMobileRelationshipRepository.insertOnDuplicateKey(relationship);
            if(debug){
                log.debug("绑定手机成功. relationship=[{}]",LogObjects.toString(relationship));
            }
            log.info("创建用户并绑定手机号. userId=[{}],openId=[{}],mobile=[{}]",user.getId(),user.getOpenId(),mobile); // 如果考虑安全,手机号记得脱敏
        }catch(DuplicateKeyException e){
            log.info("创建用户并绑定手机号失败,已存在相同的用户. openId=[{}],mobile=[{}]",user.getOpenId(),mobile);
            throw new CreateConflictException("创建用户发生冲突, openid=[%s]",user.getOpenId());
        }
    }
    

    转载:别在 Java 代码里乱打日志了,这才是正确的打日志姿势!

    展开全文
  • java程序日志管理

    千次阅读 2017-02-22 19:59:06
    而从某种意义上来说,日志管理实际上也不需要初入这一行的人来管,他们只需要负责实现自己的主要业务逻辑和功能就好了。 我当初刚入行的时候就有很长一段时间完全不用去关心日志,到后来偶尔涉及到的时候,也都是从...

    初入软件开发这一行的人,可能对日志管理的概念并不是很明确,大概是由于经验所限,以至于根本还考虑不到这个问题。
    而从某种意义上来说,日志管理实际上也不需要初入这一行的人来管,他们只需要负责实现自己的主要业务逻辑和功能就好了。
    我当初刚入行的时候就有很长一段时间完全不用去关心日志,到后来偶尔涉及到的时候,也都是从其他地方采用cv大法直接搬用。
    不过,随着工作时间的变化,随着手头上任务重要程度的变化,也随着接触到的项目数量的变化,让我越来越意识到日志的重要性,它在整个系统中发挥着至关重要的作用!
    尤其是涉及到需要后期维护的项目,更是经常需要依靠日志来定位问题,可以说他是运行中的项目出问题时,找问题最好的手段。
    java中日志管理的技术有很多,像java自身的java.util.logging,apache的commons-logging,以及slf4j、log4j、logback等等。
    其中java.util.logging在日常开发中用的不是很多,用的比较多的后边四个,commons-logging和slf4j是接口,log4j和logback是具体的实现,在我所接触的项目中就用到了这几个。
    因为java推荐的就是面向接口编程,所以一般推荐使用的就是那两个接口,但是又由于commons-logging的动态绑定造成了一些问题,因此这两个里边又推荐使用slf4j。
    同样的,在两种实现中,logback和log4j是由同一个作者开发,logback出现的更晚,更好,因为也就更推荐用logback。
    那么综上而言,目前最推荐的java中的日志管理,就是使用slf4j+logback。
    实际上,说了这么多,真正用起来是很简单的,只需要导入相关jar包,写好相关配置,然后需要的地方调用就好了,学习的过程中为了比较不同,我也写了一个简单的额例子。
    因为目前大部分的项目都是maven管理,spring框架,所以这个例子中也算是顺便联系spring的最基础配置,就也用了spring。
    maven的导包配置pom.xml如下,为了比较这四项技术,所以相关的包我全都导了进来,commons-logging是其他jar依赖的,所以便没有手动再导一次:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>logTest</groupId>
      <artifactId>logTest</artifactId>
      <packaging>war</packaging>
      <version>0.0.1-SNAPSHOT</version>
      <name>logTest Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
        </dependency>
        <dependency>
        	<groupId>org.springframework</groupId>
        	<artifactId>spring-test</artifactId>
        	<version>4.0.3.RELEASE</version>
        </dependency>
        <dependency>
        	<groupId>org.springframework</groupId>
        	<artifactId>spring-context</artifactId>
        	<version>4.0.3.RELEASE</version>
        </dependency>
        <dependency>
        	<groupId>org.slf4j</groupId>
        	<artifactId>slf4j-api</artifactId>
        	<version>1.7.12</version>
        </dependency>
        <dependency>
        	<groupId>ch.qos.logback</groupId>
        	<artifactId>logback-core</artifactId>
        	<version>1.1.2</version>
        </dependency>
        <dependency>
        	<groupId>ch.qos.logback</groupId>
        	<artifactId>logback-classic</artifactId>
        	<version>1.1.2</version>
        </dependency>
        <dependency>
        	<groupId>org.slf4j</groupId>
        	<artifactId>slf4j-log4j12</artifactId>
        	<version>1.7.7</version>
        </dependency>
        <dependency>
        	<groupId>org.slf4j</groupId>
        	<artifactId>jcl-over-slf4j</artifactId>
        	<version>1.7.12</version>
        </dependency>
      </dependencies>
      <build>
        <finalName>logTest</finalName>
      </build>
    </project>
    

    然后写了简单的spring.xml配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	 xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd"  >
    
    	<!-- 引入属性文件 -->
    	<!-- --> 
    	<context:property-placeholder location="classpath:log4j.properties" ignore-unresolvable="true" />
    	
    	<!-- 配置spring注解扫描 -->
      <context:component-scan base-package="logService.service.impl" />
    </beans>
    

    很简单,就是配置引入配置文件和spring装配扫描路径,然后是两个不同的日志配置文件,从命名就很容易知道哪个对应的是哪个,首先是log4j.properties:

    `log4j.properties:
    log4j.rootLogger=WARN, CONSOLE, FILE  
    ## for console  
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender  
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout  
    log4j.appender.CONSOLE.layout.ConversionPattern=%d{MM-ddHH:mm:ss}[%c-%L][%t][%-4r] - %m%n  
    log4j.appender.CONSOLE.Encoding=utf-8
    ## for file  
    log4j.appender.FILE=org.apache.log4j.RollingFileAppender  
    log4j.appender.FILE.File=C:/Users/Think/Desktop/log4j.log 
    log4j.appender.FILE.MaxFileSize=1MB  
    log4j.appender.FILE.Append = true  
    log4j.appender.FILE.layout=org.apache.log4j.PatternLayout  
    log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-ddHH\:mm\:ss} [%t] %-5p  %-4r %x - %m%n
    log4j.appender.FILE.Encoding=utf-8`
    

    然后是logback.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="C:/Users/Think/Desktop" />
    <!-- 控制台输出 -->
    <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>${LOG_HOME}/logback.%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>
    </encoder>
    <!--日志文件最大的大小-->
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
    <MaxFileSize>10MB</MaxFileSize>
    </triggeringPolicy>
    </appender>
    
    <!-- 日志输出级别 -->
    <root level="WARN">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE"/>
    </root>
    </configuration>
    

    这些配置基本上都是最最基础的配置,具体的代表什么意思,网上也有很多很多的说明。
    然后分别写了两个使用了common-logging和slf4j的接口:

    package logService.service;
    
    /**
     * 使用common-logger
     * 
     * @author tuzongxun
     * @date 2017年2月20日 下午3:36:19
     */
    public interface CommonLogService {
    
    	public void printLog(String msg);
    
    }
    
    package logService.service;
    
    /***
     * Slf4j日志打印
     * 
     * @author tuzongxun
     * 
     * @date 2017年2月20日 下午3:39:11
     */
    public interface Slf4jLogService {
    	public void printLog(String msg);
    }
    

    还有对应的实现类,实现类实际上什么都没做,就是调用日志接口随便打印一条日志而已:

    package logService.service.impl;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.stereotype.Component;
    
    import logService.service.CommonLogService;
    
    /**
     * 使用commons-logger和log4j打印日志
     * 
     * @author tuzongxun
     * @date 2017年2月20日 下午3:36:33
     */
    @Component
    public class CommonLogServiceImp implements CommonLogService {
    	private Log logger = LogFactory.getLog(CommonLogServiceImp.class);
    
    	public void printLog(String msg) {
    		logger.warn("Commonlogger日志打印:" + msg);
    
    	}
    }
    
    package logService.service.impl;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import logService.service.Slf4jLogService;
    
    /***
     * Slf4j日志打印
     * 
     * @author tuzongxun
     * @date 2017年2月20日 下午3:38:55
     */
    @Component
    public class Slf4jLogServiceImpl implements Slf4jLogService {
    
    	private Logger log = LoggerFactory.getLogger(Slf4jLogServiceImpl.class);
    
    	@Override
    	public void printLog(String msg) {
    		log.warn("slf4j日志打印:" + msg);
    
    	}
    }
    

    从上边的代码中,实际上根本看不出什么问题,只看到调用了两个接口而已,方法几乎都是一模一样,至于具体用了哪个实现,有什么区别呢,完全不知道,所以我写了对应的test类:

    package logTest;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import logService.service.CommonLogService;
    import logService.service.Slf4jLogService;
    
    /**
     * 日志管理测试
     * 
     * @author tuzongxun
     * @date 2017年2月22日 下午3:40:17
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:spring.xml")
    public class LogTest {
    	@Autowired
    	private CommonLogService commonLogService;
    
    	@Autowired
    	private Slf4jLogService slf4jLogService;
    
    	@Test
    	public void commonLogTest() {
    		commonLogService.printLog("commonlog日志打印");
    	}
    
    	@Test
    	public void slf4jLogTest() {
    		slf4jLogService.printLog("slf4j日志打印");
    	}
    
    }
    

    那么现在有了代码,我就可以说一说区别了,实际上一开始我说的pom.xml并不是一次导入的,可能有的项目中只有其中几个,而有的项目中我刚才导入的jar包他们也全都导入了。
    经过我的测试发现,当使用common-logging的时候,是只能使用log4j的,如果去掉log4j的jar包,那么结果就是运行junit后没有生成对应的日志文件。
    而如果用slf4j就可以使用两个实现,只不过和common-logging不同的是,使用slf4j时除开log4j的包,还需要slf4j连接log4j的包。
    使用slf4j和logback要导入logback的包自然就不必说了,但是同时到如log4j和logback的包就导致了另一个问题存在,就是使用slf4j的时候不仅会用log4j,还会用logback,导致结果每次都会有两份日志文件。
    因此呢,在这种情况下就需要导入另一个包,也就是我导入的

    <dependency>
        	<groupId>org.slf4j</groupId>
        	<artifactId>jcl-over-slf4j</artifactId>
        	<version>1.7.12</version>
        </dependency>
    

    有了这个包以后,便不会再有log4j的日志文件出现。
    本例子已经上传到csdn下载:
    http://download.csdn.net/user/tuzongxun

    展开全文
  • Java系统日志管理

    万次阅读 2018-07-06 15:24:06
    在一个系统中日志管理是一个很重要的部分,因为当系统发布到线网后出了问题只能看系统日志了,这个时候系统日志起到了一个错误排查功能,同时也可以通过系统日志统计用户吞吐量等等,总之系统日志是系统管理一个重点...
    在一个系统中日志管理是一个很重要的部分,因为当系统发布到线网后出了问题只能看系统日志了,这个时候系统日志起到了一个错误排查功能,同时也可以通过系统日志统计用户吞吐量等等,总之系统日志是系统管理一个重点。
    
    本系统架构为SpringMVC,myBatis,Shrio等等。

    1.SpringMVC异常处理
    SpringMVC负责接收用户请求并进行处理然后将结果返回给用户,那么为了不让异常抛给用户,我们一般在Controller类下每个方法都加上一个try{}catch(Exception e){},实例代码如下:
    /**
    	 * pengweikang 20170220 用户登陆
    	 * 
    	 * @param cgbUser
    	 *            用户信息
    	 * @param session
    	 * @return
    	 */
    	@RequestMapping(value = "/login", method = RequestMethod.POST)
    	public @ResponseBody String userLogin(HttpServletRequest request) {
    		try {
    		     .....	 //Service方法调用
    		} catch (Exception e) {
    		     .....      //异常处理
    		} 
    		return null;
    	}

    该方法的缺点是代码冗余,不利于维护,一看就不想是一个专业的软件工程师应该写的,优化办法如下:

    其实SpringMVC给我们提供了一个控制器增强标签,名称为@ControllerAdvice,通过这个标签就可以统一实现异常处理,代码如下:
    创建统一的异常处理类CGBExceptionHandler.java

    import javax.servlet.http.HttpServletRequest;
    import org.apache.commons.lang.exception.ExceptionUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    
    import ch.qos.logback.classic.Level;
    import net.sf.json.JSONObject;
    
    /**
    *@author		create by pengweikang
    *@date		2018年6月27日--下午12:49:23
    *@problem
    *@answer
    *@action
    */
    @ControllerAdvice
    public class CGBExceptionHandler {
    	ch.qos.logback.classic.Logger loggerback = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger("error");
    	{
    		loggerback.setLevel(Level.ERROR);
    	}
        @ExceptionHandler(Exception.class)
        @ResponseBody
        public Object handleException(Exception e,HttpServletRequest rquest) {
        	loggerback.error("错误日志记录");
        	Map dataMap  = rquest.getParameterMap();
            Set<String> keySet = 	dataMap.keySet();
            for(String key : keySet) {
                String [] datas = (String[])dataMap.get(key);
                String value = new String();
                for(String data : datas) {
        	        value +=data+",";
                }
        	    loggerback.error("Param:"+key+" = "+ value.substring(0, value.length() - 1));//将请求参数保存在日志中
            }
        	loggerback.error(ExceptionUtils.getFullStackTrace(e));  // 记录错误信息
            String msg = e.getMessage();
            if (msg == null || msg.equals("")) {
                msg = "服务器出错";
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("message", msg);
            jsonObject.put("state", 0);
            return jsonObject.toString();
        }
    }

    这个时候你的Controller就不用在添加try-catch异常捕获了, 一但方法出了异常就会跳转到CGBExceptionHandler.java这个类的handleException方法。

    2.logback日志管理

    在这个方法中我们将方法调用的的错误消息都记录在日志中,并且将方法调用的参数也报错在错误日志中,logback配置内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://www.padual.com/java/logback.xsd"
        debug="false" scan="true" scanPeriod="30 second">
    
        <property name="PROJECT" value="recognizeSystem" /> 
        <property name="ROOT" value="/opt/apache-tomcat-7.0.82/logs/${PROJECT}/" />
        <property name="FILESIZE" value="50MB" />
        <property name="MAXHISTORY" value="100" />
        <timestamp key="DATETIME" datePattern="yyyy-MM-dd HH:mm:ss" />
        <!-- 控制台打印 -->
         <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
         	
         	<filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
         
            <encoder charset="utf-8">
                <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
                </pattern>
            </encoder>
        </appender>
        <!-- ERROR 输入到文件,按日期和文件大小 -->
        <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <encoder charset="utf-8">
                <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
                </pattern>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${ROOT}%d/error.%i.log</fileNamePattern>
                <maxHistory>${MAXHISTORY}</maxHistory>
                <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${FILESIZE}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
        </appender>
        
        <!-- WARN 输入到文件,按日期和文件大小 -->
        <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <encoder charset="utf-8">
                <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
                </pattern>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>WARN</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${ROOT}%d/warn.%i.log</fileNamePattern>
                <maxHistory>${MAXHISTORY}</maxHistory>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${FILESIZE}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
        </appender>
        
        <!-- INFO 输入到文件,按日期和文件大小 -->
        <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <encoder charset="utf-8">
                <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
                </pattern>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>INFO</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${ROOT}%d/info.%i.log</fileNamePattern>
                <maxHistory>${MAXHISTORY}</maxHistory>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${FILESIZE}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
        </appender>
        <!-- DEBUG 输入到文件,按日期和文件大小 -->
        <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <encoder charset="utf-8">
                <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
                </pattern>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>DEBUG</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${ROOT}%d/debug.%i.log</fileNamePattern>
                <maxHistory>${MAXHISTORY}</maxHistory>
                <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${FILESIZE}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
        </appender>
        <!-- TRACE 输入到文件,按日期和文件大小 -->
        <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <encoder charset="utf-8">
                <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
                </pattern>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>TRACE</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${ROOT}%d/trace.%i.log</fileNamePattern>
                <maxHistory>${MAXHISTORY}</maxHistory>
                <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${FILESIZE}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
        </appender>
        
        <!-- SQL相关日志输出-->
        <logger name="org.apache.ibatis" level="INFO" additivity="false" />
        <logger name="org.mybatis.spring" level="INFO" additivity="false" />
        <logger name="com.github.miemiedev.mybatis.paginator" level="INFO" additivity="false" />
        
        <!-- Logger 根目录 -->
        <root level="DEBUG">
             <appender-ref ref="STDOUT" />
             <appender-ref ref="DEBUG" /> 
            <appender-ref ref="ERROR" />
            <appender-ref ref="WARN" />
            <appender-ref ref="INFO" /> 
            <appender-ref ref="TRACE" />
        </root>
    </configuration>

    该配置文件内容为将不同类型的日志按不同文件进行报错,并且每天记录不同的日志,文件夹按日期进行命名,儿控制台只打印错误日志。

    3.测试

    测试代码如下:

    @Controller
    @RequestMapping(value="/test")
    public class TestController {
    @RequestMapping(value="/exception")
    	public @ResponseBody String throwexcep(int data) throws Exception {
    		int a = data/0;// 一定会抛出 java.lang.ArithmeticException: / by zero		
    		return null;
    	}
    }
    请求 http://localhost:8080/logSystem/test/exception?data=100

    首先看tomcat的log文件夹如下图所示:



    error.0.log日志记录如下:

    [ERROR] 2018-07-06 15:05:39 [http-bio-8080-exec-3] error - 错误日志记录
    [ERROR] 2018-07-06 15:09:30 [http-bio-8080-exec-2] error - 错误日志记录
    [ERROR] 2018-07-06 15:09:30 [http-bio-8080-exec-2] error - Param:data = 100
    [ERROR] 2018-07-06 15:09:30 [http-bio-8080-exec-2] error - ParameterMap:org.apache.catalina.util.ParameterMap@c7832d1
    [ERROR] 2018-07-06 15:09:30 [http-bio-8080-exec-2] error - java.lang.ArithmeticException: / by zero
    	at com.goldenbridge.recognizesystem.controller.ActivitiController.throwexcep(ActivitiController.java:137)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
    	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
    	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
    	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
    	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
    	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
    	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
    	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
    	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
    	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
    	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
    	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
    	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at com.goldenbridge.recognizesystem.utils.SimpleCORSFilter.doFilter(SimpleCORSFilter.java:34)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110)
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
    	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1115)
    	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    	at java.lang.Thread.run(Thread.java:748)
    
    

    到此系统日志管理配置完成!


    展开全文
  • Java日志管理最佳实践

    千次阅读 2016-03-02 23:10:53
    原文出处:http://www.ibm.com/developerworks/cn/java/j-lo-practicelog/。 感谢原作者,感谢ibm网站,里面有好多的精华帖。 日志记录是应用程序运行中必不可少的一部分。具有良好格式和完备信息的日志记录...
  • java 项目日志管理设计方案

    万次阅读 多人点赞 2017-05-27 16:00:00
    java 项目日志管理设计方案 因项目需要记录整个系统的操作记录,考虑到系统操作日志的数据量,单表很容易达到瓶颈,导致查询效率低下,顾使用分表方案,减小数据库的负担,缩短查询时间。目前对于分表的解决方案有...
  • 2.java 中 配合redis主从备份的方法 【实现目标】: master redis 正常运行 slaver redis 自动备份 master 的所有数据 当master redis 冗掉 slaver 自动升级为master 接替原来master 的工作 当原master 重启后
  • 上一篇文章简单介绍了java如何调用ffmpeg的命令:http://blog.csdn.net/eguid_1/article/details/51777716 上上一篇介绍了nginx-rtmp服务器的... 这一篇将进一步深挖java对ffmepg命令的控制并最终实现服务接口化...
  • Java 日志管理最佳实践

    千次阅读 2016-01-14 18:03:16
    日志记录是应用程序运行中必不可少的一部分。...本文介绍了在Java程序中记录日志的最佳实践,同时也 介绍了如何使用开源软件对日志进行聚合和分析。 概述 对于现在的应用程序来说,日志的重要性是不言而喻
  • java slf4j日志管理

    千次阅读 2016-08-09 16:00:27
    SLF4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所...
  • 基于java springboot博客管理系统设计和实现

    千次阅读 多人点赞 2021-08-19 10:54:34
    博客,又译为网络日志、 部落格或部落阁等,是一种通常由个人管理、不定期张贴新的文章的网站。 博客上的文章通常根据张贴时间, 以倒序方式由新到旧排列。 许多博客专注在特定的课题上提供评论或新闻, 其他则被...
  • 执行java代码的一个方法,这个动作触发提交spark任务到运行在yarn上的spark 集群 开始 Spark任务介绍 执行spark读取Hive中的一个表,这个表是用Hive来管理的HBASE表。统计这个表的总记录数。 具体代码如下: ...
  • Spring AOP实现后台管理系统日志管理

    万次阅读 多人点赞 2017-02-08 15:31:52
    AOP+注解 实现后台管理系统日志管理
  • 日志管理最好的是Aop,有的人也喜欢用拦截器。都可以,在此我重点介绍我的实现方式。 Aop有的人说拦截不到Controller。有的人说想拦AnnotationMethodHandlerAdapter截到Controller必须得拦截org.springframework....
  • JAVA代码优化

    千次阅读 2018-10-21 23:27:45
    一、类、方法、变量尽量指定final修饰 public static void test(){ final String x=&amp;amp;quot;1&amp;amp;...二、字符串拼接背后不一定是StringBuilder、上面代码没有用StringBuilde
  • JAVA 代码

    千次阅读 2015-01-27 18:02:39
    这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 ...
  • JAVA代码Review

    千次阅读 2018-03-28 11:08:45
    代码review是指在软件开发过程中,通过对源代码进行系统性检查来确认代码实现的质量保证机制 为什么不做代码Review? ​业务需求大,工作时间紧张 项目小,协作的人少,没必要 为什么要做代码Review? 提高...
  • 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里,你想解决的问题,在这专栏都能解决
  • springboot 基于Aop实现自定义日志管理

    千次阅读 2020-02-27 16:39:50
    springboot 基于Aop实现自定义日志管理一、相关依赖(maven)二、代码实现1. 添加自定义定义注解2. 定义日志实体3. 定义日志AOP切面类(环绕通知)AOP其他通知模式* @Before 前置通知* @After 后置通知* @After...
  • 基于Spring Cloud实现日志管理模块

    千次阅读 2020-04-11 20:43:00
    无论在什么系统中,日志管理模块都属于十分重要的部分,接下来会通过注解+AOP+MQ的方式实现一个简易的日志管理系统 思路: 注解:标记需要记录日志的方法 AOP:通过AOP增强代码,利用后置/异常通知的方式...
  • 目录 项目背景: 文档目录 主要技术: 主要功能: 功能截图: ...管理后主要功能模块:用户管理、角色管理、承菜管理、权限管理、竞赛报名管理、经费申请和审核管理、...系统日志监控:aop切面编程实现日志记录操作...
  • 1、开发需求 需要实现在服务端发起HTTP/HTTPS请求,访问其他程序资源。... DefaultHttpClient和它的兄弟AndroidHttpClient都是HttpClient具体的实现类,它们都拥有众多的API,而且实现比较稳定,b
  • 基于ssh社团管理系统的...用户个人信息管理模块主要包括:个人资料管理、照片信息管理、密码管理、日志管理,照片信息管理,心情信息管理六个子模块。管理员信息管理模块主要包括:系统公告管理、密码管理、日志信息...
  • JAVA代码规范

    万次阅读 2016-06-08 15:19:46
    为统一Java项目编码规范,提高可读性,特制定本规范。 本规范同样适用于Android项目。 本规范基于Google Java Style,主要的区别如下: 保留了原有规范的4空格缩进和120字符列宽限制 放松了对import语句的...
  • 四、动态代理的JDK实现原理 4.1核心类/接口 4.2 代理类$Proxy0解析 4.3 动态代理的经典使用五、手写代码模拟JDK动态代理六、参考资料项目源码已经上传,欢迎点击下载~先将自己总结的Java动态代理UML图放在前面,...
  • Spring Boot 整合 logback 实现日志管理

    千次阅读 2017-11-06 16:10:40
    摘要:前面两篇介绍了Spring Boot 整合 log4j,log4j2 实现日志管理,这篇介绍下Spring Boot 整合 logback实现日志管理,其实很简单,因为Spring Boot 默认实现日志管理就是使用的logback。 一:新建java工程,...
  • Java代码优化提点

    万次阅读 多人点赞 2013-10-30 11:04:16
    程序代码可以是中间代码,也可以是目标代码。等价的含义是使得变换后的代码运行结果与变换前代码运行结果相同。优化的含义是最终生成的目标代码更加轻松自如(运行时间更短、占用空间更小)地工作,时空效率优化。 ...
  • MySQL+java: 实现学生成绩管理系统(1.0版本)

    千次阅读 多人点赞 2020-09-23 22:30:51
    准备 1.Java 下载 最新版Java安装教程 ...实现 使用MySQL生成表 包括 学号,姓名,成绩,班级四个字段。 USE students; DROP TABLE IF EXISTS stu_score; CREATE TABLE IF NOT EXISTS stu_score( NO VARCHAR(10),.
  • aop注解方式实现全局日志管理

    千次阅读 2017-04-01 17:41:43
    1:日志实体类 public class SysLog { /** */ private Integer id; /** 日志描述*/ private String description; /** 执行的方法*/ private String method; /** 日志类型 0:操作日志;1:异常日志*/ ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 213,728
精华内容 85,491
关键字:

日志管理java代码实现

java 订阅