com.opensymphony.xwork2.util.profiling
public class: UtilTimerStack [javadoc |
source]
java.lang.Object
com.opensymphony.xwork2.util.profiling.UtilTimerStack
A timer stack.
Struts2 profiling aspects involves the following :-
- ActionContextCleanUp
- FreemarkerPageFilter
- DispatcherFilter
- Dispatcher
- creation of DefaultActionProxy
- creation of DefaultActionInvocation
- execution of DefaultActionProxy
- invocation of DefaultActionInvocation
- invocation of Interceptors
- invocation of Action
- invocation of PreResultListener
- invocation of Result
XWork2 profiling aspects involves the following :-
- creation of DefaultActionProxy
- creation of DefaultActionInvocation
- execution of DefaultActionProxy
- invocation of DefaultActionInvocation
- invocation of Interceptors
- invocation of Action
- invocation of PreResultListener
- invocation of Result
Activating / Deactivating of the profiling feature could be done through:-
System properties:-
-Dxwork.profile.activate=true
This could be done in the container startup script eg. CATALINA_OPTS in catalina.sh
(tomcat) or using "java -Dxwork.profile.activate=true -jar start.jar" (jetty)
Code :-
UtilTimerStack.setActivate(true);
This could be done in a static block, in a Spring bean with lazy-init="false",
in a Servlet with init-on-startup as some numeric value, in a Filter or
Listener's init method etc.
Parameter:-
<action ... >
...
<interceptor-ref name="profiling">
<param name="profilingKey">profiling</param>
</interceptor-ref>
...
</action>
or
<action .... >
...
<interceptor-ref name="profiling" />
...
</action>
through url
http://host:port/context/namespace/someAction.action?profiling=true
through code
ActionContext.getContext().getParameters().put("profiling", "true);
To use profiling activation through parameter, one will need to pass in through
the 'profiling' parameter (which is the default) and could be changed through
the param tag in the interceptor-ref.
Warning:
Profiling activation through a parameter requires the following:
- Profiling interceptor in interceptor stack
- dev mode on (struts.devMode=true in struts.properties)
One could filter out the profile logging by having a System property as follows. With this
'xwork.profile.mintime' property, one could only log profile information when its execution time
exceed those specified in 'xwork.profile.mintime' system property. If no such property is specified,
it will be assumed to be 0, hence all profile information will be logged.
-Dxwork.profile.mintime=10000
One could extend the profiling feature provided by Struts2 in their web application as well.
String logMessage = "Log message";
UtilTimerStack.push(logMessage);
try {
// do some code
}
finally {
UtilTimerStack.pop(logMessage); // this needs to be the same text as above
}
or
String result = UtilTimerStack.profile("purchaseItem: ",
new UtilTimerStack.ProfilingBlock() {
public String doProfiling() {
// do some code
return "Ok";
}
});
Profiled result is logged using commons-logging under the logger named
'com.opensymphony.xwork2.util.profiling.UtilTimerStack'. Depending on the underlying logging implementation
say if it is Log4j, one could direct the log to appear in a different file, being emailed to someone or have
it stored in the db.
| Nested Class Summary: |
|---|
| public static interface | UtilTimerStack.ProfilingBlock | 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. |
| Field Summary |
|---|
| protected static ThreadLocal<ProfilingTimerBean> | current | |
| public static final String | ACTIVATE_PROPERTY | System property that controls whether this timer should be used or not. Set to "true" activates
the timer. Set to "false" to disactivate. |
| public static final String | MIN_TIME | System property that controls the min time, that if exceeded will cause a log (at INFO level) to be
created. |
| Methods from java.lang.Object: |
|---|
|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Method from com.opensymphony.xwork2.util.profiling.UtilTimerStack Detail: |
public static boolean isActive() {
return active;
}
Determine if profiling is being activated, by searching for a system property
'xwork.profile.activate', default to false (profiling is off). |
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
{
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
LOG.warn("Unmatched Timer. Was expecting " + currentTimer.getResource() + ", instead got " + name);
}
}
}
End a preformance profiling with the name given. Deal with
profile hierarchy automatically, so caller don't have to be concern about it. |
public static T profile(String name,
ProfilingBlock<T> block) throws Exception {
UtilTimerStack.push(name);
try {
return block.doProfiling();
}
finally {
UtilTimerStack.pop(name);
}
}
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;
}
});
|
public static void push(String name) {
if (!isActive())
return;
//create a new timer and start it
ProfilingTimerBean newTimer = new ProfilingTimerBean(name);
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);
}
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. |
public static void setActive(boolean active) {
if (active)
System.setProperty(ACTIVATE_PROPERTY, "true");
else
System.clearProperty(ACTIVATE_PROPERTY);
UtilTimerStack.active = active;
}
Turn profiling on or off. |