com.prussia.play.spring.service.aop.ServiceMonitor.java Source code

Java tutorial

Introduction

Here is the source code for com.prussia.play.spring.service.aop.ServiceMonitor.java

Source

/*
 * Copyright 2012-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.prussia.play.spring.service.aop;

import java.util.concurrent.ConcurrentHashMap;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class ServiceMonitor {

    private static final Logger logger = LoggerFactory.getLogger(ServiceMonitor.class);

    private static ConcurrentHashMap<String, MethodStats> methodStats = new ConcurrentHashMap<String, MethodStats>();
    private static long statLogFrequency = 10;
    private static long methodWarningThreshold = 1000;

    /*
    2016-03-29 21:43:19.596  WARN 1608 --- [nio-8080-exec-1] c.p.t.p.s.service.aop.ServiceMonitor     : around start.., execution(void com.prussia.test.play.spring.service.AccountService.createAcctount(String,String)) 
    2016-03-29 21:43:19.596  WARN 1608 --- [nio-8080-exec-1] c.p.t.p.s.service.aop.ServiceMonitor     : before aspect executing, execution(void com.prussia.test.play.spring.service.AccountService.createAcctount(String,String))
    2016-03-29 21:43:19.596  WARN 1608 --- [nio-8080-exec-1] c.p.t.p.s.service.aop.ServiceMonitor     : around end, execution(void com.prussia.test.play.spring.service.AccountService.createAcctount(String,String)) 
    2016-03-29 21:43:19.596  WARN 1608 --- [nio-8080-exec-1] c.p.t.p.s.service.aop.ServiceMonitor     : after aspect executed, execution(void com.prussia.test.play.spring.service.AccountService.createAcctount(String,String))
    2016-03-29 21:43:19.596  WARN 1608 --- [nio-8080-exec-1] c.p.t.p.s.service.aop.ServiceMonitor     : afterReturning executed, execution(void com.prussia.test.play.spring.service.AccountService.createAcctount(String,String)), return result is null 
        
     */

    @Pointcut("execution(* com.prussia.test.play..*ServiceBean.*(..))")
    public void pointCut() {
        logger.warn("I am pointCut: ", this);
    }

    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        logger.warn("after aspect executed, {}", joinPoint);
    }

    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        // ?????
        // Object[] args = joinPoint.getArgs();
        logger.warn("before aspect executing, {}", joinPoint);
    }

    @AfterReturning(pointcut = "pointCut()", returning = "returnVal")
    public void afterReturning(JoinPoint joinPoint, Object returnVal) {
        logger.warn("afterReturning executed, {}, return result is {} ", joinPoint, returnVal);
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.warn("around start.., {} ", joinPoint);
        long start = System.currentTimeMillis();
        Object o = null;
        try {
            o = joinPoint.proceed();
        } catch (Throwable ex) {
            throw ex;
        } finally {
            logger.warn("ServiceMonitor:" + joinPoint.getSignature().getName() + " takes "
                    + (System.currentTimeMillis() - start) + "ms");

            updateStats(joinPoint.getSignature().getName(), (System.currentTimeMillis() - start));
        }
        return o;
    }

    @AfterThrowing(pointcut = "pointCut()", throwing = "error")
    public void afterThrowing(JoinPoint jp, Throwable error) {
        logger.warn("error:" + error);
    }

    private void updateStats(String methodName, long elapsedTime) {
        MethodStats stats = methodStats.get(methodName);
        if (stats == null) {
            stats = new MethodStats(methodName);
            methodStats.put(methodName, stats);
        }
        stats.count++;
        stats.totalTime += elapsedTime;
        if (elapsedTime > stats.maxTime) {
            stats.maxTime = elapsedTime;
        }

        if (elapsedTime > methodWarningThreshold) {
            logger.warn("method warning: " + methodName + "(), count = " + stats.count + ", lastTime = "
                    + elapsedTime + ", maxTime = " + stats.maxTime);
        }

        if (logger.isDebugEnabled()) {
            if (stats.count % statLogFrequency == 0) {
                long avgTime = stats.totalTime / stats.count;
                long runningAvg = (stats.totalTime - stats.lastTotalTime) / statLogFrequency;
                logger.debug("method: " + methodName + "(), count = " + stats.count + ", lastTime = " + elapsedTime
                        + ", avgTime = " + avgTime + ", runningAvg = " + runningAvg + ", maxTime = "
                        + stats.maxTime);

                //reset the last total time
                stats.lastTotalTime = stats.totalTime;
            }
        }
    }

    class MethodStats {
        public String methodName;
        public long count;
        public long totalTime;
        public long lastTotalTime;
        public long maxTime;

        public MethodStats(String methodName) {
            this.methodName = methodName;
        }
    }

}