001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 * $Id$
020 */
021package org.nuxeo.ecm.core.management.events;
022
023import java.util.Collections;
024import java.util.HashMap;
025import java.util.Map;
026
027import org.nuxeo.ecm.core.event.impl.EventListenerDescriptor;
028
029/**
030 * Helper class to store statistics about listeners calls.
031 *
032 * @author Thierry Delprat
033 */
034public class EventStatsHolder {
035
036    protected static boolean collectAsyncHandlersExecTime = false;
037
038    protected static boolean collectSyncHandlersExecTime = false;
039
040    protected static Map<String, CallStat> syncStats = new HashMap<String, CallStat>();
041
042    protected static Map<String, CallStat> aSyncStats = new HashMap<String, CallStat>();
043
044    private EventStatsHolder() {
045    }
046
047    public static boolean isCollectAsyncHandlersExecTime() {
048        return collectAsyncHandlersExecTime;
049    }
050
051    public static void setCollectAsyncHandlersExecTime(boolean collectAsyncHandlersExecTime) {
052        EventStatsHolder.collectAsyncHandlersExecTime = collectAsyncHandlersExecTime;
053    }
054
055    public static boolean isCollectSyncHandlersExecTime() {
056        return collectSyncHandlersExecTime;
057    }
058
059    public static void setCollectSyncHandlersExecTime(boolean collectSyncHandlersExecTime) {
060        EventStatsHolder.collectSyncHandlersExecTime = collectSyncHandlersExecTime;
061    }
062
063    /**
064     * @since 5.6
065     */
066    public static void clearStats() {
067        synchronized (aSyncStats) {
068            EventStatsHolder.aSyncStats.clear();
069        }
070    }
071
072    public static void logAsyncExec(EventListenerDescriptor desc, long delta) {
073        if (!collectAsyncHandlersExecTime) {
074            return;
075        }
076        String name = desc.getName();
077        synchronized (aSyncStats) {
078            CallStat stat = aSyncStats.get(name);
079            if (stat == null) {
080                String label = desc.asPostCommitListener().getClass().getSimpleName();
081                if (desc.getIsAsync()) {
082                    label += "(async)";
083                } else {
084                    label += "(sync)";
085                }
086                stat = new CallStat(label);
087                aSyncStats.put(name, stat);
088            }
089            stat.update(delta);
090        }
091    }
092
093    public static void logSyncExec(EventListenerDescriptor desc, long delta) {
094        if (!collectSyncHandlersExecTime) {
095            return;
096        }
097        String name = desc.getName();
098        synchronized (syncStats) {
099            CallStat stat = syncStats.get(name);
100            if (stat == null) {
101                String label = desc.asEventListener().getClass().getSimpleName();
102                stat = new CallStat(label);
103                syncStats.put(name, stat);
104            }
105            stat.update(delta);
106        }
107    }
108
109    public static String getAsyncHandlersExecTime() {
110        return getStringSummary(aSyncStats);
111    }
112
113    /**
114     * @since 5.6
115     */
116    public static Map<String, CallStat> getAsyncHandlersCallStats() {
117        return Collections.unmodifiableMap(aSyncStats);
118    }
119
120    public static String getSyncHandlersExecTime() {
121        return getStringSummary(syncStats);
122    }
123
124    /**
125     * @since 5.6
126     */
127    public static Map<String, CallStat> getSyncHandlersCallStats() {
128        return Collections.unmodifiableMap(syncStats);
129    }
130
131    protected static String getStringSummary(Map<String, CallStat> stats) {
132        StringBuffer sb = new StringBuffer();
133        synchronized (stats) {
134
135            long totalTime = 0;
136            for (String name : stats.keySet()) {
137                totalTime += stats.get(name).getAccumulatedTime();
138            }
139
140            for (String name : stats.keySet()) {
141                CallStat stat = stats.get(name);
142                sb.append(name);
143                sb.append(" - ");
144                sb.append(stat.getLabel());
145                sb.append(" - ");
146                sb.append(stat.getCallCount());
147                sb.append(" calls - ");
148                sb.append(stat.getAccumulatedTime());
149                sb.append("ms - ");
150                String pcent = String.format("%.2f", 100.0 * stat.getAccumulatedTime() / totalTime);
151                sb.append(pcent);
152                sb.append("%\n");
153            }
154        }
155        return sb.toString();
156    }
157
158    public static void resetHandlersExecTime() {
159        synchronized (syncStats) {
160            syncStats = new HashMap<String, CallStat>();
161        }
162        synchronized (aSyncStats) {
163            aSyncStats = new HashMap<String, CallStat>();
164        }
165    }
166
167}