To handle manually the interception you need to import sirona-aop. Then you can rely on org.apache.sirona.aop.SironaProxyFactory.
org.apache.commons.proxy.ProxyFactory key defines the proxy factory to use to create proxies For instance to use javassist you set it to org.apache.commons.proxy.factory.javassist.JavassistProxyFactory (and you’ll include javassist in your application).
Then the API is quite simple:
final MyClient client = SironaProxyFactory.monitor(MyClient.class, getMyClientInstance());
You just need to decorate your CDI bean/method with the interceptor binding org.apache.sirona.cdi.Monitored.
For instance:
@Monitored @ApplicationScoped public class MyMonitoredBean { public void myMethod() { // ... } }
Note: in some (old) CDI implementation you’ll need to activate the monitoring interceptor: org.apache.sirona.cdi.SironaInterceptor.
You can configure it (without adding the @Monitored annotation) using org.apache.sirona.cdi.performance key. The value is a list of predicate (regex:<regex>, prefix:<prefix>, suffix:<suffix>).
For instance:
org.apache.sirona.cdi.performance = prefix:org.superbiz.MyService,regex:.*Bean
Using org.apache.sirona.spring.BeanNameMonitoringAutoProxyCreator you can automatically add monitoring to selected beans.
<bean class="org.apache.sirona.spring.BeanNameMonitoringAutoProxyCreator"> <property name="beanNames"> <list> <value>*Service</value> </list> </property> </bean>
An alternative is to use org.apache.sirona.spring.PointcutMonitoringAutoProxyCreator which uses a org.springframework.aop.Pointcut to select beans to monitor.
To use AspectJ weaver (it works with build time enhancement too but it is often less relevant) just configure a custom concrete aspect defining the pointcut to monitor:
<aspectj> <aspects> <concrete-aspect name="org.apache.commons.aspectj.MyMonitoringAspectJ" extends="org.apache.sirona.aspectj.SironaAspect"> <pointcut name="pointcut" expression="execution(* org.apache.sirona.aspectj.AspectJMonitoringTest$MonitorMe.*(..))"/> </concrete-aspect> </aspects> <weaver> <include within="org.apache.sirona.aspectj.AspectJMonitoringTest$MonitorMe"/> </weaver> </aspectj>
See AspectJ documentation for more information.
Few global configuration (sirona.properties) is available for all interceptors:
Note: threshold and forced-iteration parameters can be specialized appending to org.apache.sirona. the method qualified name.
Here a sample of the behavior associated with these properties. Let say you configured forced-iteration to 5 and threshold to 100 milliseconds. If xxx ms represent an invocation of xxx milliseconds and * represent a call which was measured, here is an invocation sequence:
500 ms* 5 ms* 500 ms 500 ms 500 ms 500 ms 500 ms 20 ms* 200 ms 200 ms 200 ms 200 ms 200 ms 500 ms* 500 ms*
Note: the idea is to reduce the overhead of the interception. This is pretty efficient in general but particularly with AspectJ. Note 2: if your invocations are pretty unstable this is not really usable since since you’ll not get a good threshold value.
First add to your JVM the sirona javaagent:
-javaagent:/path/to/sirona-javaagent.jar
Note: ensuring sirona-core and sirona-aop are no more delivered in your binaries or the container is not mandatory but better.
The javaagent supports “include” configuration:
-javaagent:/path/to/sirona-javaagent.jar=includes=XXX
The value of includes (XXX in previous example) is a comma separated list of predicates (prefix:org.superbix, regex:org.superbiz.*Service).
Symmetrically excludes is supported.
Adding others jars with libs=paths to a directory containing jars
It basically convert the following code:
public class Foo { public void run() { } public void run2() { System.out.println("hello"); } public String out() { return "output"; } public void npe() { try { throw new NullPointerException(); } catch (final NullPointerException npe) { npe.printStackTrace(); } } }
in
package org.apache.test.sirona.javaagent; import org.apache.sirona.aop.AbstractPerformanceInterceptor; import org.apache.sirona.counters.Counter; import org.apache.sirona.javaagent.AgentPerformanceInterceptor; public class Foo { private static final String out_$_$IRONA_$_INTERNAL_$_KEY; private static final String npe_$_$IRONA_$_INTERNAL_$_KEY; private static final String run_$_$IRONA_$_INTERNAL_$_KEY; private static final String run2_$_$IRONA_$_INTERNAL_$_KEY; public void run() { AbstractPerformanceInterceptor.Context localContext = AgentPerformanceInterceptor.start(run_$_$IRONA_$_INTERNAL_$_KEY, this); try { run_$_$irona_$_internal_$_original_$_(); localContext.stop(); } catch (Throwable localThrowable) { localContext.stopWithException(localThrowable); throw localThrowable; } } private void run_$_$irona_$_internal_$_original_$_() { } public void run2() { AbstractPerformanceInterceptor.Context localContext = AgentPerformanceInterceptor.start(run2_$_$IRONA_$_INTERNAL_$_KEY, this); try { run2_$_$irona_$_internal_$_original_$_(); localContext.stop(); } catch (Throwable localThrowable) { localContext.stopWithException(localThrowable); throw localThrowable; } } private void run2_$_$irona_$_internal_$_original_$_() { System.out.println("hello"); } public String out() { AbstractPerformanceInterceptor.Context localContext = AgentPerformanceInterceptor.start(out_$_$IRONA_$_INTERNAL_$_KEY, this); try { String str = out_$_$irona_$_internal_$_original_$_(); localContext.stop(); return str; } catch (Throwable localThrowable) { localContext.stopWithException(localThrowable); throw localThrowable; } } private String out_$_$irona_$_internal_$_original_$_() { return "output"; } public void npe() { AbstractPerformanceInterceptor.Context localContext = AgentPerformanceInterceptor.start(npe_$_$IRONA_$_INTERNAL_$_KEY, this); try { npe_$_$irona_$_internal_$_original_$_(); localContext.stop(); } catch (Throwable localThrowable) { localContext.stopWithException(localThrowable); throw localThrowable; } } private void npe_$_$irona_$_internal_$_original_$_() { try { throw new NullPointerException(); } catch (NullPointerException npe) { npe.printStackTrace(); } } private static void _$_$irona_static_merge0() { out_$_$IRONA_$_INTERNAL_$_KEY = "org.apache.test.sirona.javaagent.Foo.out"; npe_$_$IRONA_$_INTERNAL_$_KEY = "org.apache.test.sirona.javaagent.Foo.npe"; run_$_$IRONA_$_INTERNAL_$_KEY = "org.apache.test.sirona.javaagent.Foo.run"; run2_$_$IRONA_$_INTERNAL_$_KEY = "org.apache.test.sirona.javaagent.Foo.run2"; } static { _$_$irona_static_merge0(); // if other static blocks it will be added here as _$_$irona_static_merge1(), _$_$irona_static_merge2()... } }
Javaagent is extensible using InvocationListener API:
public interface InvocationListener { void before(AgentContext context); void after(AgentContext context, Object result, Throwable error); boolean accept(String key); }
Note on contextual data: key is an int for performances reasons, ensure you don’t conflict with another listener. Prefer to use negative int if possible.
InvocationListeners can be sorted using @Order annotation.
org.apache.sirona.javaagent.listener.ConfigurableListener is an utility class to simplify the writing of InvocationListener classes.
They are picked using a plain old service provider interface (META-INF/services/org.apache.sirona.javaagent.spi.InvocationListener).