zoukankan      html  css  js  c++  java
  • 利用Perf4j 对java项目进行性能监控

    Perf4j 可以对自定义监控范围的java代码进行日志记录,再经统计分析生成所需性能数据。Perf4j 提供了对常用日志工具log4j的扩展以方便与产品集成,它产生的性能数据可被用于生成可视化的性能图表。
    Perf4j是一款专门用于java服务器端代码计时,记录日志和监控结果的开源工具包。Per4j对常用日志工具包进行了扩展,能够将得到的原始性能数据进行统计并发布到可定制的输出源,如控制台、日志文件、JMX等。
    本文主要面向JAVA EE项目,来说明Perf4j集成log4j来进行性能的的分析。
    首先要在项目中加入perf4j和log4j的jar包。
    然后修改log4j.xml,使得支持perf4j
        <!-- perf4j的Logger及Appender -->
        <!-- Perf4J appenders -->
        <!-- AsyncCoalescingStatisticsAppender收集StopWatch的日志信息并传送到下游的文件appenders。 -->
        <appender name="CoalescingStatistics"
            class="org.perf4j.log4j.AsyncCoalescingStatisticsAppender">
            <!-- TimeSlice配置多少时间间隔去做一次汇总写入文件中 默认值是 30000 ms ,设置为10分钟-->
            <param name="TimeSlice" value="3600000" />
            <appender-ref ref="performanceAppenderCSV" /><appender-ref ref="performanceAppenderLOG" />
        </appender>
        <!-- 把汇总的perf4j的日志信息写到${web.XxxWeb.root}/WEB-INF/logs/perfmance/perfmance.log文件中去 -->
        <appender name="performanceAppenderLOG" class="org.apache.log4j.FileAppender">
            <param name="File" value="${web.XxxWeb.root}/WEB-INF/logs/perfmance/perfmance.log" />
            <param name="Append" value="true" />                                              <!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
            <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%m%n" />
            </layout>
        </appender>
        <appender name="performanceAppenderCSV" class="org.apache.log4j.FileAppender">
            <param name="File" value="${web.XxxWeb.root}/WEB-INF/logs/perfmance/perfmance.csv" />
            <param name="Append" value="true" />                                              <!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
            <param name="DatePattern" value="'.'yyyy-MM-dd'.csv'" />
            <layout class="org.perf4j.log4j.StatisticsCsvLayout">
                <param name="ConversionPattern" value="%m%n" />
            </layout>
        </appender>
        <!-- 11、perf4j日志记录器org.perf4j.TimingLogger 日志记录在${web.XxxWeb.root}/WEB-INF/logs/performance/目录下 -->
        <logger name="org.perf4j.TimingLogger" additivity="false">
            <level value="INFO" />
            <appender-ref ref="CoalescingStatistics" />
        </logger>
    简单的测试代码如下:
        public long add(DmModel dmModel) {
            StopWatch stopWatch = new Slf4JStopWatch("dmService.add",
                    "textArgs");
            long maxbh = fydmbDao.getMaxDmbh();
            maxbh++;
            dmModel.setDqbs("1");
            dmModel.setXgsj(new Date());
            dmModel.setBh(maxbh);
     
            dmbDao.addFyDm(DmConvertor.modelToFydm(dmModel));
            stopWatch.stop();
            return dmModel.getBh();
        }
    运行junit测试即可看到如下结果:
    Performance Statistics   2013-09-06 19:00:00 - 2013-09-06 20:00:00
    Tag                                                          Avg(ms)         Min         Max     Std Dev       Count
    FydmService.addFy                                      181.0         181         181         0.0             1
    最后,介绍perf4j在实战中的应用----借助于aop,实现对服务性能的批量记录
    1、配置log4j,如上
     
    2、编写 Perf4jInterceptor代码
    package nju.software.XxxWeb.performance;
     
    import java.lang.reflect.Method;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    import org.perf4j.StopWatch;
    import org.perf4j.slf4j.Slf4JStopWatch;
    import org.springframework.aop.AfterReturningAdvice;
    import org.springframework.aop.MethodBeforeAdvice;
     
    /**
     * @author typ
     * 
     */
    public class Perf4jInterceptor implements MethodBeforeAdvice,
            AfterReturningAdvice {
        /**
         * 用于存放不同服务的不同方法的stopWatch
         */
        private Map<String, StopWatch> watches = new HashMap<String, StopWatch>();
     
     
        // 在服务中得方法执行之前加入before方法中得如下逻辑,stopWatch开始统计
        public void before(Method method, Object[] args, Object target)
                throws Throwable {
            String completeMethodName = getCompleteMethodName(target, method);
            StopWatch stopWatch;
            if (watches.containsKey(completeMethodName)) {
                stopWatch = watches.get(completeMethodName);
                stopWatch.start();
            } else {
                stopWatch = new Slf4JStopWatch(completeMethodName,
                        Arrays.toString(args));
                watches.put(completeMethodName, stopWatch);
            }
     
        }
     
     
        // 在服务执行完毕,返回值之前加入如下afterReturning逻辑,stopWatch结束统计
        public void afterReturning(Object returnValue, Method method,
                Object[] args, Object target) throws Throwable {
            String completeMethodName = getCompleteMethodName(target, method);
     
            // logger.info("After:"+completeMethodName);
            // 记录性能
            if (watches.containsKey(completeMethodName)) {
                StopWatch stopWatch = watches.get(completeMethodName);
                stopWatch.stop();
            }
        }
     
     
        /**
         * 根据目标对象与方法获取方法完整名称.
         * 
         * @param target
         *            目标对象
         * @param method
         *            方法
         * @return 方法完整名称
         */
        private String getCompleteMethodName(Object target, Method method) {
            String className = "";
            if (target != null) {
                className = target.toString();
                int loc = className.indexOf("@");
                if (loc >= 0) {
                    className = className.substring(0, loc);
                }
            }
     
            return className + "." + method.getName();
        }
    }
    以上类是附加逻辑,用于对拦截器拦截下的服务添加before和after逻辑。即对所有的服务进行拦截,在服务方法执行之前加入before方法内的逻辑,在服务返回之后加入afterReturning方法逻辑。
     
    3、配置applicationContext.xml
        <!-- 定义Perf4jInterceptor的bean -->
        <bean id="perf4jInterceptor" class="nju.software.XxxWeb.performance.Perf4jInterceptor">
        </bean>
        <!-- 定义拦截器,定义拦截的服务的列表,以及拦截器的名字,在服务执行之前和之后加入该拦截器中代码 -->
        <bean id="perf4jProxy"
            class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="beanNames">
                <list>
                    <!--<value>fydmbService</value> -->
                    <value>dmService</value>
                    <value>xzqdmbService</value>
                    <value>gjService</value>
                    <value>xxxService</value>
                    <value>gjXxxGxService</value>
                    <value>gzService</value>
                    <value>sxgzService</value>
                    <value>xtyhService</value>
                    <value>xtjsService</value>
                    <value>qxService</value>
                    <value>xtdxService</value>
                    <value>bmbService</value>
                    <value>gzbwlService</value>
                    <value>executionService</value>
                    <value>repositoryService</value>
                    <value>taskService</value>
                    <value>aydmbService</value>
                    <value>hytglService</value>
                    <value>hytcyService</value>
                    <value>sftjPzxxbService</value>
                </list>
            </property>
            <property name="interceptorNames">
                <list>
                    <value>perf4jInterceptor</value>
                </list>
            </property>
        </bean>
    至此为止,java EE的项目中就可以使用perf4j来统计各种service的性能了
     
     
  • 相关阅读:
    react-echarts之折线图的显示
    Log4j2
    测试驱动开发Junit4
    JavaWeb基础: Cookie
    JavaWeb前端:Bootstrap基础
    JavaWeb前端:CSS
    JavaWeb前端:JQuery
    Android基础:Activity
    JavaWeb前端: JavaScript 简介
    JavaWeb前端:HTML5 简介
  • 原文地址:https://www.cnblogs.com/riskyer/p/3306323.html
Copyright © 2011-2022 走看看