org.onetwo.common.profiling.UtilTimerStack Maven / Gradle / Ivy
package org.onetwo.common.profiling;
import org.onetwo.common.log.JFishLoggerFactory;
import org.slf4j.Logger;
/****
* copy from struts 2
*
*/
public class UtilTimerStack
{
// A reference to the current ProfilingTimerBean
protected static ThreadLocal current = new ThreadLocal();
// public static final String PROFILE_LOGGER = "profileLogger";
public static final String PROFILE_LOGGER = "time.profile";
public static final String ACTIVATE_PROPERTY = "onetwo.profile.activate";
/**
* System property that controls the min time, that if exceeded will cause a log (at INFO level) to be
* created.
*/
public static final String MIN_TIME = "onetwo.profile.mintime";
/**
* Initialized in a static block, it can be changed at runtime by calling setActive(...)
*/
private static boolean active;
private static boolean nanoTime;
private static TimeLogger timeLogger;
static {
final Logger logger = JFishLoggerFactory.getLogger(PROFILE_LOGGER);
active = "true".equalsIgnoreCase(System.getProperty(ACTIVATE_PROPERTY));
timeLogger = new Slf4jTimeLogger(logger);
}
public static TimeLogger getOuputer() {
return timeLogger;
}
public static void setOuputer(TimeLogger ouputer) {
UtilTimerStack.timeLogger = ouputer;
}
public static void setNanoTime(boolean nanoTime) {
UtilTimerStack.nanoTime = nanoTime;
}
/**
* Create and start a performance profiling with the name
given. Deal with
* profile hierarchy automatically, so caller don't have to be concern about it.
*
* @param name profile name
*/
public static void push(String name)
{
if (!isActive())
return;
//create a new timer and start it
ProfilingTimerBean newTimer = new ProfilingTimerBean(name, nanoTime);
newTimer.setStartTime();
//if there is a current timer - add the new timer as a child of it
ProfilingTimerBean currentTimer = (ProfilingTimerBean) current.get();
if (currentTimer != null)
{
currentTimer.addChild(newTimer);
}
//set the new timer to be the current timer
current.set(newTimer);
}
/**
* End a preformance profiling with the name
given. Deal with
* profile hierarchy automatically, so caller don't have to be concern about it.
*
* @param name profile name
*/
public static void pop(String name)
{
if (!isActive())
return;
ProfilingTimerBean currentTimer = (ProfilingTimerBean) current.get();
//if the timers are matched up with each other (ie push("a"); pop("a"));
if (currentTimer != null && name != null && name.equals(currentTimer.getResource()))
{
currentTimer.setEndTime();
ProfilingTimerBean parent = currentTimer.getParent();
//if we are the root timer, then print out the times
if (parent == null)
{
printTimes(currentTimer);
current.set(null); //for those servers that use thread pooling
}
else
{
// printTimes(currentTimer);
current.set(parent);
}
}
else
{
//if timers are not matched up, then print what we have, and then print warning.
if (currentTimer != null)
{
printTimes(currentTimer);
current.set(null); //prevent printing multiple times
getOuputer().log(UtilTimerStack.class, "Unmatched Timer. Was expecting " + currentTimer.getResource() + ", instead got " + name);
}
}
}
/**
* Do a log (at INFO level) of the time taken for this particular profiling.
*
* @param currentTimer profiling timer bean
*/
private static void printTimes(ProfilingTimerBean currentTimer)
{
getOuputer().log(UtilTimerStack.class, currentTimer.getPrintable(getMinTime()));
}
/**
* Get the min time for this profiling, it searches for a System property
*
* @return long
*/
private static long getMinTime()
{
try
{
return Long.parseLong(System.getProperty(MIN_TIME, "0"));
}
catch (NumberFormatException e)
{
return -1;
}
}
/**
* Determine if profiling is being activated, by searching for a system property
* 'xwork.profile.activate', default to false (profiling is off).
*
* @return true, if active, false otherwise.
*/
public static boolean isActive()
{
return active;
}
/****
* @see #active()
* @param active
*/
public static void setActive(boolean active) {
active(active);
}
/**
* Turn profiling on or off.
*
* @param active
*/
public static void active(boolean active) {
if (active)
System.setProperty(ACTIVATE_PROPERTY, "true");
else
System.clearProperty(ACTIVATE_PROPERTY);
UtilTimerStack.active = active;
}
/**
* A convenience method that allows block
of code subjected to profiling to be executed
* and avoid the need of coding boiler code that does pushing (UtilTimeBean.push(...)) and
* poping (UtilTimerBean.pop(...)) in a try ... finally ... block.
*
*
*
* Example of usage:
*
* // we need a returning result
* String result = UtilTimerStack.profile("purchaseItem: ",
* new UtilTimerStack.ProfilingBlock() {
* public String doProfiling() {
* getMyService().purchaseItem(....)
* return "Ok";
* }
* });
*
* or
*
* // we don't need a returning result
* UtilTimerStack.profile("purchaseItem: ",
* new UtilTimerStack.ProfilingBlock() {
* public String doProfiling() {
* getMyService().purchaseItem(....)
* return null;
* }
* });
*
*
* @param any return value if there's one.
* @param name profile name
* @param block code block subjected to profiling
* @return T
* @throws Exception
*/
public static T profile(String name, ProfilingBlock block) throws Exception {
UtilTimerStack.push(name);
try {
return block.doProfiling();
}
finally {
UtilTimerStack.pop(name);
}
}
/**
* A callback interface where code subjected to profile is to be executed. This eliminates the need
* of coding boiler code that does pushing (UtilTimerBean.push(...)) and poping (UtilTimerBean.pop(...))
* in a try ... finally ... block.
*
* @version $Date: 2009-12-27 19:00:13 +0100 (Sun, 27 Dec 2009) $ $Id: UtilTimerStack.java 894087 2009-12-27 18:00:13Z martinc $
*
* @param
*/
public static interface ProfilingBlock {
/**
* Method that execute the code subjected to profiling.
*
* @return profiles Type
* @throws Exception
*/
T doProfiling() throws Exception;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy