精华内容
下载资源
问答
  • 2020-09-07 19:30:09

    场景:

    看日志是后端常用的操作,但是日志过于多的时候,很难分清日志打印的是不是同一个调用里面的。所以在controller的方法的开始和结尾的地方,打印日志,并且打印入参和出参,这样就能够很好的分析日志的逻辑了。

    1、引入依赖

    由于每一个controller层的方法都需要打印进入和返回的日志,所以使用AOP的思想可以很好的解决,我们这边使用静态代理AspectJ。

            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.5</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.73</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.9</version>
            </dependency>
    

    2、自定义注解

    一个自定义的注解:用于描述该接口的作用

    /**
     * @author qsm
     * @date 2020/9/3 14:20
     * @description controller层的方法上,给该方法取一个名字。作用是给LogAspect打印进入方法退出方法的日志
     */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ControllerMethodTitle {
    
        String value() default "";
    }
    

    3、日志切面代码LogAspect

    下面直接给出代码,修改一下Pointcut的路径,便可以直接使用:

    package com.xxx.ins.qsm.demo.web.commom.aspact;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.ObjectUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    @Component
    @Aspect
    @Slf4j
    @Order(-98)
    public class LogAspect {
    
        @Autowired
        HttpServletRequest request;
        /**
         * 【注意】 修改为你自己项目中controller层路径
         */
        @Pointcut("execution(public * com.qsm.xxx.xx.xxxx.controller..*.*(..))")
        public void pointcut() {
        }
    
    
        @Around("pointcut()")
        public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
    
            //请求controller名称,使用@ControllerMethodTitle注解
            String controllerTitle = getControllerMethodTitle(joinPoint);
            //方法路径
            String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
            //IP地址
            String iP = getIp(request);
            //请求入参
            String requestParam = JSON.toJSONString(Arrays.stream(joinPoint.getArgs())
              .filter(param -> !(param instanceof HttpServletRequest)
                              && !(param instanceof HttpServletResponse)
                              && !(param instanceof MultipartFile)
                              && !(param instanceof MultipartFile[])
              ).collect(Collectors.toList()));
              
            log.info("\n    [Controller start], {}, methodName->{}, IP->{}, requestParam->{},", controllerTitle, methodName, iP, requestParam);
    
            long begin = System.currentTimeMillis();
            Object result = joinPoint.proceed();
    
            log.info("\n    [Controller end], {}, 耗时->{}ms, result->{}", controllerTitle, System.currentTimeMillis() - begin, JSONObject.toJSONString(result));
            return result;
        }
    
        /**
         * 获取Controller的方法名
         */
    
        private String getControllerMethodTitle(ProceedingJoinPoint joinPoint) {
            Method[] methods = joinPoint.getSignature().getDeclaringType().getMethods();
            for (Method method : methods) {
                if (StringUtils.equalsIgnoreCase(method.getName(), joinPoint.getSignature().getName())) {
                    ControllerMethodTitle annotation = method.getAnnotation(ControllerMethodTitle.class);
                    if (ObjectUtils.isNotEmpty(annotation)) {
                        return annotation.value();
                    }
                }
            }
            return "该Controller的方法使用未使用注解@ControllerMethodTitle,请使用该注解说明方法作用";
        }
    
        /**
         * 获取目标主机的ip
         *
         * @param request
         * @return
         */
        private String getIp(HttpServletRequest request) {
            List<String> ipHeadList = Stream.of("X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "X-Real-IP").collect(Collectors.toList());
            for (String ipHead : ipHeadList) {
                if (checkIP(request.getHeader(ipHead))) {
                    return request.getHeader(ipHead).split(",")[0];
                }
            }
            return "0:0:0:0:0:0:0:1".equals(request.getRemoteAddr()) ? "127.0.0.1" : request.getRemoteAddr();
        }
    
        /**
         * 检查ip存在
         */
        private boolean checkIP(String ip) {
            return !(null == ip || 0 == ip.length() || "unknown".equalsIgnoreCase(ip));
        }
    
    
    }
    

    4、使用方法

    使用方法非常的简单,直接在controller的方法上面直接使用自定义的注解@ControllerMethodTitle即可。

    @RestController
    @RequestMapping("/log")
    @Slf4j
    public class LogController {
    
        @PostMapping("/qsm")
        @ControllerMethodTitle("我是一个可爱的测试获取qsm的接口")
        public Qsm2 http(@RequestBody @Valid Qsm2 qsm2, HttpServletRequest request) {
            log.info("\n    [处理中], 程序正在处理请求逻辑");
            return qsm2;
        }
    }
    

    打印的日志

    2020-09-07 19:25:14.773  INFO 13276 --- [nio-8080-exec-3] c.j.i.q.d.web.commom.aspact.LogAspect    : 
        [开始], 我是一个可爱的测试获取qsm的接口, methodName->com.xxx.ins.qsm.demo.web.controller.LogController.http, IP->127.0.0.1, reqParam->[{"name":"demoData","status":"123"}],
    2020-09-07 19:25:14.783  INFO 13276 --- [nio-8080-exec-3] c.j.i.q.d.web.controller.LogController   : 
        [处理中], 程序正在处理请求逻辑
    2020-09-07 19:25:14.784  INFO 13276 --- [nio-8080-exec-3] c.j.i.q.d.web.commom.aspact.LogAspect    : 
        [结束], 我是一个可爱的测试获取qsm的接口, 耗时->10ms, result->{"name":"demoData","status":"123"} 
    

    到此,非常优雅简单的打印请求和返回的日志就好了,还是非常有用的。喜欢就点个赞吧~~~

    【续】

    程序中有时候使用了swagger,而对于controller里面的接口,会使用@ApiOperation注解,该注解本身就有描述该方法,所以若使用了该注解,就不需要使用我们自定义的注解@ControllerMethodTitle显得有点冗余。但是,若没有使用swagger,依然推荐使用我们的自定义注解。

    使用swagger时的操作:

    1、引入依赖

            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.6.0</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>2.6.0</version>
            </dependency>
    

    2、替换日志切面代码LogAspect类中的getControllerMethodTitle方法为

        /**
         * 获取Controller的方法名
         * 可以使用我们自定义的@ControllerMethodTitle。若使用了swagger,就优先使用swagger的@ApiOperation的value
         */
        private String getControllerMethodTitle(ProceedingJoinPoint joinPoint) {
            Method[] methods = joinPoint.getSignature().getDeclaringType().getMethods();
            for (Method method : methods) {
                if (StringUtils.equalsIgnoreCase(method.getName(), joinPoint.getSignature().getName())) {
                    ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
                    ControllerMethodTitle controllerMethodTitle = method.getAnnotation(ControllerMethodTitle.class);
                    if (ObjectUtils.isNotEmpty(apiOperation) && StringUtils.isNotBlank(apiOperation.value())) {
                        return apiOperation.value();
                    }
                    if (ObjectUtils.isNotEmpty(controllerMethodTitle)) {
                        return controllerMethodTitle.value();
                    }
                }
            }
            return "该Controller的方法使用未使用注解@ControllerMethodTitle,请使用该注解说明方法作用";
        }
    

    3、使用,在controller方法中使用

        @GetMapping("/dataBinder")
        @ApiOperation(value = "我是一个可爱的测试获取dataBinder的接口")
        public Qsm2 dataBinder(DataBinder dataBinder, HttpServletRequest request) {
            log.info("\n    [处理中], 程序正在处理请求逻辑2222{},{},{}", env, env2, env3);
            return null;
        }
    

    【完】


    正在去BAT的路上修行

    更多相关内容
  • 主要介绍了bat脚本输出日志方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • python打印日志方法的使用

    千次阅读 2021-12-23 11:06:44
    python的官方库,打印日志用的,无需安装,使用时直接调用 1、logging的基本使用 1.1、日志的五个等级(DEBUG/INFO/WARNING/ERROR/CRITICAL) (1)DEBUG:调试模式下的日志,只给程序员看的日志 (2)INFO:...

    一、必备技能

    1、logging模块的使用

    (1)5个日志等级/以及5个输出日志的内置函数

    (2)日志收集器、日志输出渠道的概念

    (3)如何自定义日志收集器

    (4)如何封装自定义的日志收集器

    二、logging

    python的官方库,打印日志用的,无需安装,使用时直接调用

    1、logging的基本使用

    1.1、日志的五个等级(DEBUG/INFO/WARNING/ERROR/CRITICAL)

    (1)DEBUG:调试模式下的日志,只给程序员看的日志

    (2)INFO:程序正常运行的时候输出的日志

    (3)WARN/WARNING:警告信息,当前程序还可以运行,后面有可能出现问题

    (4)ERROR:程序执行过程总的错误信息

    (5)CRITICAL:发生严重错误,阻塞流程,程序可能无法继续运行

    1.2、打印不同日志等级的方法:

    (1)logging.debug("调试日志信息")

    (2)logging.info("重要日志信息")

    (3)logging.warning("警告日志信息")

    (4)logging.error("错误日志信息")

    (5)logging.critical("致命日志信息")

    1.3、日志收集器和日志输出渠道:

            日志收集器:

                    默认收集器的名字为root,默认收集等级为WARNING,通过如下步骤设置收集器的等级

                    log = logging.getLogger() # 获取日志收集器,默认为root

                    log.setLevel("等级")  # 等级必须大写

                    logging.basicConfig(level=logging.DEBUG)  # 设置收集器的等级

            日志输出渠道:

                    默认输出等级为WARNING

                    输出渠道支持:输出到文件夹和输出到控制台

    Demo实例1——默认WARNING等级

    import logging
    # 打印不同等级的日志(debug、info、warning、error、critical)
    # 如下5条日志,只会打印WARNING等级以后的日志
    logging.debug("这是一条debug级别的日志")
    logging.info("这是一条info级别的日志")
    logging.warning("这是一条warning级别的日志")
    logging.error("这是一条error级别的日志")
    logging.critical("这是一条critical级别的日志")

    运行结果 :(只会打印WARNING级别以上的日志)

    WARNING:root:这是一条warning级别的日志
    ERROR:root:这是一条error级别的日志
    CRITICAL:root:这是一条critical级别的日志

    Demo实例2——默认的日志收集器

    import logging
    # # logging.basicConfig(level=logging.DEBUG) 设置日志级别
    # 未指定name,默认返回自带的默认的root收集器
    # 默认输出WARN级别以上的等级日志
    # 如果设置了WARNING以下的等级,则输出WARNING等级以上的日志
    # 如果设置了WARNING以上的等级,比如设置了ERROR,则输出ERROR等级以上的日志
    log = logging.getLogger()
    # log.setLevel("DEBUG")
    # log.setLevel("INFO")
    # log.setLevel("WARNING")
    log.setLevel("ERROR")
    # log.setLevel("CRITICAL")
    
    
    logging.debug("这是一条debug级别的日志")
    logging.info("这是一条info级别的日志")
    logging.warning("这是一条warning级别的日志")
    logging.error("这是一条error级别的日志")
    logging.critical("这是一条critical级别的日志")

     运行结果:

    ERROR:root:这是一条error级别的日志
    CRITICAL:root:这是一条critical级别的日志

    2、自定义日志收集器

    2.1、创建日志收集器

          log = logging.getLogger(name="rose_logger")

            不传name参数时,默认返回收集器名字为“root”

            传了name参数时,会创建一个新的日志收集器

    2.2、创建日志收集渠道

    (1)输出到控制台:

            pycharm = logging.StreamHandler()

    (2)输出到文件:    

            file = logging.FileHandler(os.getcwd()+r"\rose.log",encoding="utf-8")

            file=handlers.TimedRotatingFileHandler(filename="test.log",when="D",interval=1,backupCount=10,encoding="utf-8")

            注意点(参数):

            filename, 日志的文件名称(包含路径)

            when= 'h', 日志的切割单位

            # S - Seconds 秒

            # M - Minutes 分钟

            # H - Hours 小时

            # D - Days 天(24小时)

            # midnight - roll over at midnight 日切

            # W{0-6} - roll over on a certain day; 0 - Monday 周

            interval=1, 滚动周期,与when='h'连动,1-表示以时间为周期

            backupCount=0 保留日志文件的个数,设置为10,永远只保存最近的10个文件

    2.3、创建日志的输出格式

    (1)创建日志格式对象

            pycharm_fmt = logging.Formatter(fmt=fmt1)

    (2)将日志输出格式绑定到日志输出渠道

            pycharm.setFormatter(fmt=pycharm_fmt)  ——设置到控制台日志渠道

            file.setFormatter(fmt=pycharm_fmt1)——设置到文件日志渠道

    (3)常用的格式模板(也可以自己定义)

            fmt1 = "%(asctime)s - [%(funcName)s-->line:%(lineno)d] - %(levelname)s:%(message)s"

            fmt2 = '[%(asctime)s-%(name)s-%(levelname)s-%(filename)s-%(lineno)d]:%(message)s'

    (4)格式必须按照指定的格式格式化。常用的如下:

            %(asctime)s——当前时间

            %(funcName)s——模块名

            %(lineno)d——行号

            %(levelname)s——日志等级名称

             %(message)s——具体的日志内容 

       Demo实例3——自定义日志收集器和日志格式

    import logging,os
    from logging import handlers
    # 1、创建日志收集器
    log = logging.getLogger(name="rose_logger")
    
    # 2、创建日志收集渠道
    # 输出控制台
    pycharm = logging.StreamHandler()
    # 输出文件夹
    file = logging.FileHandler(os.getcwd()+r"\rose.log",encoding="utf-8")
    # file = handlers.TimedRotatingFileHandler(filename="test.log",when="D",interval=1,backupCount=10,encoding="utf-8")
    
    # 3、创建日志的输出格式
    fmt1 = "%(asctime)s - [%(funcName)s-->line:%(lineno)d] - %(levelname)s:%(message)s"
    # 创建一个日志输出对象
    pycharm_fmt = logging.Formatter(fmt=fmt1)
    fmt2 = '[%(asctime)s-%(name)s-%(levelname)s-%(filename)s-%(lineno)d]:%(message)s'
    pycharm_fmt1 = logging.Formatter(fmt=fmt2)
    
    # 4、日志输出格式绑定到日志输出渠道
    pycharm.setFormatter(fmt=pycharm_fmt)
    file.setFormatter(fmt=pycharm_fmt1)
    
    # 5、直接给收集器设置日志级别就可以了,渠道会继承收集器的日志级别
    log.setLevel(level=logging.DEBUG)
    # 5、给收集渠道设置日志级别,文件渠道,控制台输出的级别不会一样
    # pycharm.setLevel(logging.DEBUG)
    
    # 6、将日志收集渠道绑定到日志收集器
    log.addHandler(pycharm)
    log.addHandler(file)
    
    log.info(msg="测试")

    输出结果:

        Demo实例4——封装自定义日志收集器

    import logging
    from logging import handlers
    def create_log(name,level,filename,sh_level,fh_level):
        """
    
        :param name:  日志收集器名字
        :param level: 日志收集器的等级
        :param filename:  日志文件的名称
        :param sh_level:  控制台输出日志的等级
        :param fh_level:    文件输出日志的等级
        :return: 返回创建好的日志收集器
        """
    
        # 1、创建日志收集器
        log = logging.getLogger(name)
    
        # 2、创建日志收集器的等级
        log.setLevel(level=level)
    
        # 3、创建日志收集渠道和等级
        sh = logging.StreamHandler()
        sh.setLevel(level=sh_level)
        log.addHandler(sh)
        fh = logging.FileHandler(filename=filename,encoding="utf-8")
        # fh1 = handlers.TimedRotatingFileHandler(filename=filename,when="D",interval=1,backupCount=10,encoding="utf-8")
        fh.setLevel(level=fh_level)
        log.addHandler(fh)
    
        # 4、设置日志的输出格式
        formats = "%(asctime)s - [%(funcName)s-->line:%(lineno)d] - %(levelname)s:%(message)s"
        log_format = logging.Formatter(fmt=formats)
        sh.setFormatter(log_format)
        fh.setFormatter(log_format)
        return log
    
    if __name__ == '__main__':
        log = create_log(name="rose_log",level=logging.DEBUG,filename="test_log.log",sh_level=logging.DEBUG,fh_level=logging.DEBUG)
        log.info(msg="--------debug--------")
        log.info(msg="--------info--------")
        log.info(msg="--------warning--------")
        log.info(msg="--------error--------")
        log.info(msg="--------critical--------")

    输出结果:

     

    展开全文
  • 线程池执行异常不打印日志

    千次阅读 2020-06-07 16:43:07
    平时自己在使用的ThreadPoolExecutor的时候,提交任务用submit和execute方法用的比较随意,知道当需要获取返回结果的时候用submit。但当并不需要结果的时候submit和execute用得比较随意。在一次使用submit的时候并...

    背景


    平时自己在使用的ThreadPoolExecutor的时候,提交任务用submit和execute方法用的比较随意,知道当需要获取返回结果的时候用submit。但当并不需要结果的时候submit和execute用得比较随意。在一次使用submit的时候并没有获得预期结果,但也没有异常日志输出。在进行一波调试之后,任务在线程中出现异常了,但也并未出现异常抛出的情况。

    代码测试


    1、先用execute 查看当出现异常的情况

    public class ThreadPoolTest {
    
    
    
        private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(500),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r);
                        thread.setName("submit-execute-test");
                        return thread;
                    }
    
    
                }
        );
    
        private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
    
        public static void main(String[] args) {
            Random random = new Random();
            for (int i = 0; i < 10; i++) {
                int j = i;
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            TimeUnit.SECONDS.sleep(2 + random.nextInt(5));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if (j % 2 != 0) {
                            throw new RuntimeException("线程错误");
                        }
                        LinkedBlockingQueue<Runnable> queue = (LinkedBlockingQueue) executor.getQueue();
                        System.out.println(formatter.format(LocalDateTime.now()) + "::" + Thread.currentThread().getName() + "::" +
                                "核心线程数 :" + executor.getCorePoolSize() +
                                "::最大线程数 :" + executor.getMaximumPoolSize() +
                                "::活动线程数 :" + executor.getActiveCount() +
                                "::任务完成数" + executor.getCompletedTaskCount() +
                                "::队列使用 :" + queue.size() + "::队列未使用 :" + queue.remainingCapacity() + "::队列总共大小 :" + (queue.size() + queue.remainingCapacity()));
    
    
                    }
                });
    
            }
        }
    }
    

    在这里插入图片描述
    从打印中可以看到当execute提交runable的时候异常会输出。

    2、我们将execute 换成submit ,其他都不变,再次查看运行情况
    在这里插入图片描述

    可以看出除了我们在代码里面输出内容并未抛出异常。

    原因


    查看ThreadPoolExecutor 的submit方法,是将Runable方法进行封装,再交给Executor去execute,这个方法和ThreadPoolExecutor 的execute方法一样

      public Future<?> submit(Runnable task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<Void> ftask = newTaskFor(task, null);
            execute(ftask);
            return ftask;
        }
    

    newTaskFor 方法是创建FutureTask 对象,那么具体不抛异常应该就在FutureTask的run方法了。

      protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
            return new FutureTask<T>(runnable, value);
        }
    

    FutureTask 的run方法,在run方法中对Throwable 异常进行捕获,错误的时候将异常设置到返回结果。执行正常结束,将返回结果set到结果中

     public void run() {
            if (state != NEW ||
                !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                             null, Thread.currentThread()))
                return;
            try {
                Callable<V> c = callable;
                if (c != null && state == NEW) {
                    V result;
                    boolean ran;
                    try {
                        result = c.call();
                        ran = true;
                    } catch (Throwable ex) {
                        result = null;
                        ran = false;
                        //设置异常到返回结构中
                        setException(ex);
                    }
                    //执行正确结束设置返回结果
                    if (ran)
                        set(result);
                }
            } finally {
                // runner must be non-null until state is settled to
                // prevent concurrent calls to run()
                runner = null;
                // state must be re-read after nulling runner to prevent
                // leaked interrupts
                int s = state;
                if (s >= INTERRUPTING)
                    handlePossibleCancellationInterrupt(s);
            }
        }
    

    建议


    根据上面的分析,如果ThreadPoolExecutor 提交任务的时候如果并不关心返回结果最好直接使用ThreadPoolExecutor.execute() 方法。

    展开全文
  • Java调试技巧 打印代码执行时间方法

    万次阅读 2019-11-13 16:03:39
      在调试代码时,我们想知道代码的执行时间,废话不多说,上代码,毫秒级检测 // 放在要检测的代码段前,取开始前的时间戳 Long startTime = System.currentTimeMillis(); // 放在要检测的代码段前,取结束...

      在调试代码时,我们想知道代码段的执行时间,废话不多说,上代码,毫秒级检测

    // 放在要检测的代码段前,取开始前的时间戳
    Long startTime = System.currentTimeMillis();
    
    // 放在要检测的代码段后,取结束后的时间戳
    Long endTime = System.currentTimeMillis();
    
    // 计算并打印耗时
    Long tempTime = (endTime - startTime);
    System.out.println("花费时间:"+
    	(((tempTime/86400000)>0)?((tempTime/86400000)+"d"):"")+
    	((((tempTime/86400000)>0)||((tempTime%86400000/3600000)>0))?((tempTime%86400000/3600000)+"h"):(""))+
    	((((tempTime/3600000)>0)||((tempTime%3600000/60000)>0))?((tempTime%3600000/60000)+"m"):(""))+
    	((((tempTime/60000)>0)||((tempTime%60000/1000)>0))?((tempTime%60000/1000)+"s"):(""))+
    	((tempTime%1000)+"ms"));
    

    执行结果(举例):
    在这里插入图片描述


    更新一下,这次直接提供一个工具类
    分别提供了三个静态方法和三个实例方法
    在只需要一次取值的时候,直接调用静态方法即可,
    在需要多次分段打印的时候,需要创建对象然后调用实例方法。
    多次调用实例打印方法时,同时输出每次打印之间的时间间隔。
    打印方法提供了有参和无参两种,更灵活的使用。
    (初始方法和打印方法自身执行时间基本在1ms以内)

    /**
     * @author 散场前的温柔
     * @Description: 输出代码执行时间的工具类
     * @date 2020/11/20 13:45
     */
    public class CodeRunningTimeUtils {
        private static Long startTimes;
        private static Long endTimes;
        private Long startTime;
        private Long endTime;
        private Long tempTimes;
    
        /**
         * 获取初始时间戳,静态方法
         */
        public static void initRunTimes(){
            startTimes = System.currentTimeMillis();
        }
        
    	/**
         * 获取结束时间戳并打印代码执行时间,静态方法,无参
         */
        public static void printRunTimes(){
            printRunTimes(null);
        }
    
        /**
         * 获取结束时间戳并打印代码执行时间,静态方法,有参
         * @param str 字符串会在打印前输出
         */
        public static void printRunTimes(String str){
            if(str != null)
                str += " => ";
            else
                str = "";
            endTimes = System.currentTimeMillis();
            String classname = new Exception().getStackTrace()[1].getClassName(); //获取调用者的类名
            String method_name = new Exception().getStackTrace()[1].getMethodName(); //获取调用者的方法名
            if(startTimes != null) {
            Long tempTime = (endTimes - startTimes);
            System.out.println(str + classname + " > " + method_name + ":花费时间"+
                    (((tempTime/86400000)>0)?((tempTime/86400000)+"d"):"")+
                    ((((tempTime/86400000)>0)||((tempTime%86400000/3600000)>0))?((tempTime%86400000/3600000)+"h"):(""))+
                    ((((tempTime/3600000)>0)||((tempTime%3600000/60000)>0))?((tempTime%3600000/60000)+"m"):(""))+
                    ((((tempTime/60000)>0)||((tempTime%60000/1000)>0))?((tempTime%60000/1000)+"s"):(""))+
                    ((tempTime%1000)+"ms"));
            }else{
                System.out.println("你忘记了放置静态初始方法了");
            }
        }
    
        /**
         * 获取初始时间戳
         */
        public void initRunTime(){
            startTime = System.currentTimeMillis();
        }
    
    	/**
         * 获取结束时间戳并打印代码执行时间,无参
         */
        public void printRunTime(){
            printRunTime(null);
        }
    
       /**
         * 获取结束时间戳并打印代码执行时间,有参
         * 同时打印上次输出与本次输出之间的间隔时间
         */
        public void printRunTime(String str){
            if(str != null)
                str += " => ";
            else
                str = "";
            endTime = System.currentTimeMillis();
            String classname = new Exception().getStackTrace()[1].getClassName(); //获取调用者的类名
            String method_name = new Exception().getStackTrace()[1].getMethodName(); //获取调用者的方法名
            if(startTime != null) {
                Long tempTime = (endTime - startTime);
                System.out.print(str + classname + " > " + method_name + ":花费时间" +
                        (((tempTime / 86400000) > 0) ? ((tempTime / 86400000) + "d") : "") +
                        ((((tempTime / 86400000) > 0) || ((tempTime % 86400000 / 3600000) > 0)) ? ((tempTime % 86400000 / 3600000) + "h") : ("")) +
                        ((((tempTime / 3600000) > 0) || ((tempTime % 3600000 / 60000) > 0)) ? ((tempTime % 3600000 / 60000) + "m") : ("")) +
                        ((((tempTime / 60000) > 0) || ((tempTime % 60000 / 1000) > 0)) ? ((tempTime % 60000 / 1000) + "s") : ("")) +
                        ((tempTime % 1000) + "ms"));
                if(tempTimes != null){
                    tempTime = (endTime - tempTimes);
                    System.out.print(" \t间隔时间" +
                            (((tempTime / 86400000) > 0) ? ((tempTime / 86400000) + "d") : "") +
                            ((((tempTime / 86400000) > 0) || ((tempTime % 86400000 / 3600000) > 0)) ? ((tempTime % 86400000 / 3600000) + "h") : ("")) +
                            ((((tempTime / 3600000) > 0) || ((tempTime % 3600000 / 60000) > 0)) ? ((tempTime % 3600000 / 60000) + "m") : ("")) +
                            ((((tempTime / 60000) > 0) || ((tempTime % 60000 / 1000) > 0)) ? ((tempTime % 60000 / 1000) + "s") : ("")) +
                            ((tempTime % 1000) + "ms"));
                }
                System.out.println();
                tempTimes = System.currentTimeMillis();
            }else{
                System.out.println("你忘记了放置初始方法了");
            }
        }
    }
    

    调用示例:

    public class Test {
    	public static void main (String[] agrs) {
    		CodeRunningTimeUtils.initRunTimes();
    		测试代码块a
    		CodeRunningTimeUtils.printRunTimes();
    		//或者
    		//CodeRunningTimeUtils.printRunTimes("测试代码块a");
    		
    		CodeRunningTimeUtils crtu = new CodeRunningTimeUtils();
    		crtu.initRunTime();
    		// 测试代码1
    		crtu.printRunTime();
    		// 测试代码2
    		crtu.printRunTime("测试代码2");
    	}
    }
    
    展开全文
  • 终极解决方案: 1、File-settings-Editor-File Encodings-Global Encodings设置为UTF-8 2、File-settings-Editor-File Encodings-Project Encodings设置为UTF-8 3、File-settings-Build,Execution,Deployment-...
  • 执行后,无任何反应,无log日志生成,代码: sqluldr2 user=用户名/密码@oracle数据库:1521/client query="select sysdate from dual" head=no file=/home/ioc/SourceQulifier_0_54bb0764b57548d78c51ee...
  • springboot项目大量打印debug日志问题

    千次阅读 2021-01-12 20:32:27
    目前,java下应用最广泛的日志系统主要就是两个系列: log4j和slf4j+logback 。其中,slf4j只包含日志的接口,logback只包括日志的具体实现,两者加起来才是一个完整的日志系统。Log4j则同时包含了日志接口和实现。这...
  • 通过AOP 实现打印全局日志

    千次阅读 2021-12-09 08:34:36
    常用注解 1、@Before 修饰一个方法时,该方法将作为Before增强处理 ...表示在切入点执行后,进行哪些操作 通常用于资源释放 3、 @Around Around增强处理是功能比较强大的增强处理; 近似等于Before增强处理和AfterRe
  • 记录目的:java main 方法使用HttpClients发送请求不打印debug日志 记录背景: 使用java main方法测试接口响应时间 发现问题: 控制台打印巨多debug日志 解决方法: resources目录下增加logback.xml 备注说明: ...
  • 在SQL执行过程前后进行打印SQL执行时间、SQL信息、Mapper信息进行日志打印如下图所示: SqlStatementInterceptor : 实现Interceptor接口,在SQL执行过程前后进行打印SQL实行时间、SQL信息、Mapper信息进行...
  • java打印日志的几种方式

    千次阅读 2021-01-25 11:06:33
    最简单的方式,就是system.println.out(error) ,这样直接在控制台打印消息了; Java.util.logging ; 在JDK 1.4 版本之后,提供了日志的API ,可以往文件中写日志了; log4j , 最强大的记录日志的方式。 可以通过配置...
  • Linux nohup不输出日志文件的方法

    千次阅读 2021-05-13 04:08:17
    最近在Linux上部署视频流推送应用时,由于网络不稳定等原因程序会不断的输出错误信息,结果导致程序运行一天下来日志文件直接占满磁盘,解决方法就是不再输出日志文件,命令如下:只输出错误信息到日志文件:nohup ....
  • 通过AOP实现全局日志打印

    万次阅读 多人点赞 2021-12-06 20:45:38
    本文系统的阐述了如何在项目中统一的、全局的处理日志
  • shell脚本打印日志方法

    千次阅读 2016-05-30 20:01:13
    在Shell脚本执行过程中如果没有日志记录,特别...下面介绍日志打印方法 example 1  调用log_info函数,如果希望只记录相关信息,不对命令执行结果进行判断  判断/etc/passwd是否存在,如果存在就记录一条日志
  • springboot使用AOP打印日志信息

    千次阅读 2017-12-24 17:03:02
    随着项目功能的一点点增加,打印日志信息就非常必要了,可以帮助我们很快确定哪里出现了问题,这里使用slf4j来打印日志。AOP即面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。如果...
  • 在进行Android程序的逆向分析的时候,经常需要Android程序的静态分析和动态调试的结合,尤其是对一些加固的Android类方法被调用的确认,需要Hook java类方法打印java类方法的调用堆栈。有幸在网上看到了这篇文章...
  • 最近接口ab压测,发现写接口比较慢,所以需要在日志打印一些sql的执行时间,排查问题。 @Aspect @Component @Log4j2 public class MapperAspect { @AfterReturning("execution(* com.lsj.xcjfs.dao.*Mapper.*...
  • Logger的打印日志

    千次阅读 2020-11-08 17:10:34
    这里写自定义目录标题为什么要使用日志日志的级别在springboot项目中实现日志控制1.在pom文件中导入相关jar包2.在application.yml文件下日志级别控制:3.测试:4. 测试结果 为什么要使用日志 在开发的时候需要输出...
  • 我们经常使用xxljob来做微服务的任务调度,但是在服务中,我们的执行器可能就是一个方法,这个方法中可能层层嵌套有大量的logback(log4j没有试)的logger打印日志的代码,我们怎么让xxljob的web管理端可以看到这些...
  • 打印java代码执行时间

    千次阅读 2022-03-22 14:59:42
    // 代码运行开始时间 Long startTime = ...// 计算并打印耗时 Long tempTime = (endTime - startTime); log.info("开支单列表查询花费时间:"+ (((tempTime/86400000)>0)?((tempTime/86400000)+"d"):
  • AOP切面实现方法日志打印耗时计算

    千次阅读 2018-04-12 17:40:57
    很简单,通过AOP实现每个方法访问时候统一进行日志打印和耗时计算,相关配置:1、spring配置在spring配置xml文件中设置启用aop &lt;aop:aspectj-autoproxy proxy-target-class="true" /&gt;2、aop...
  • 日志打印的规范以及实现方式

    千次阅读 多人点赞 2019-01-08 18:00:16
    原因3:跟踪性能下降的问题范围,产品所反映出来的性能问题,很难在开发过程中暴露出来,这需要进行全方位的测试跟踪,而通过日志提供的详细执行时间记录可以很方便的找出应用的性能瓶颈 原因...
  • 日志打印规范

    千次阅读 2020-11-28 13:31:55
    文章目录打印日志的目的日志级别ERRORWARNINFODEBUG如何打印日志打印日志的位置打印输出哪些内容告警告警分级谁来处理告警拾遗空指针异常入参校验分布式链路追踪 灵魂之问:撸了那么多年代码,你真的会打日志吗? ...
  • FeignClient日志打印

    千次阅读 2021-03-22 19:13:03
    一、使用feign原生的配置方式 ... * BASIC:只记录请求方法和 url 以及响应状态代码和执行时间。 * HEADERS:记录请求和响应头的基本信息。 * FULL:记录请求和响应的头、正文和元数据。 * * @retur
  • Java程序日志打印规范

    千次阅读 2020-05-02 11:17:04
    日志技术框架一览 JUL:JDK中的日志记录工具,也常称为JDKLog、jdk-logging。 LOG4J1:一个具体的日志实现框架。 LOG4J2:一个具体的日志实现框架,是LOG4J1的下一个版本。 LOGBACK:一个具体的日志实现框架...
  • 类/接口/方法 都支持AOP都是连接点 Joint point 连接点 程序中支持AOP的位置 Pointcut 切点 要增加功能的一组Joint point(连接点) Advice 增强 要添加的新功能 ...
  • 关于logback日志的详解见这位仁兄的博客:Spring Boot-日志配置(超详细)我在这就开门见山直接介绍我们项目日志的配置使用吧!~1、基本介绍默认情况下,Spring Boot项目就会用Logback来记录日志,并用INFO级别输出到...
  • pom文件 < ? xml version ... * 加入注解自动记录方法日志 ...// 获取执行方法的类的名称(包名加类名) ...// 获取实例和方法 ..."() 执行" ...打印日志: 2019 - 05 - 09 16 : 58 : 29.208 INFO ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 194,801
精华内容 77,920
关键字:

方法执行后如何打印日志