The monitors are defined as Spring beans allowing Spring to be the monitor factory. The monitors are aggregated in a MonitorRegistry which is a Spring bean as well. Here is an example Spring config snippet that does that:
<bean id="monitorDB" class="com.sportex.betex.monitor.DefaultMonitor">
<property name="name" value="DB"/>
</bean>
<bean id="monitorSomethingWithErrorCountingPolicy" class="com.sportex.betex.monitor.DefaultMonitor">
<property name="errorCountingPolicy" ref="someErrorPolicy"/>
<property name="name" value="Something"/>
</bean>
<!-- The monitor registry -->
<bean id="monitorRegistry" class="com.sportex.betex.monitor.DefaultMonitorRegistry">
<property name="statusAggregator" ref="overallStatus"/>
</bean>
<!-- Status aggregator - required for webping, nagios & lus publishing -->
<bean name="overallStatus" class="com.sportex.betex.monitor.OverallStatus">
<property name="monitorRegistry" ref="monitorRegistry"/>
</bean>
<!-- Register the monitors with the registry -->
<bean class="com.sportex.betex.monitor.util.MonitorRegistration" lazy-init="false">
<property name="registry" ref="monitorRegistry"/>
<property name="monitors">
<list>
<ref bean="monitorDB"/>
<ref bean="monitorSomethingWithErrorCountingPolicy"/>
</list>
</property>
</bean>
See Monitor Configuration for more details about the monitor configuration.
To have a method invocation be tracked by a monitor a developer needs to decorate the method with the @MonitorMethod annotation, for example:
@MonitorMethod ( monitorName = "monitorDB" )
public void aDbCall() {
...
}
Note that the monitorName is the value of the “name” attribute and not the name of the spring bean.
The annotated methods are recognised by the Spring provided AOP machinery. For this to work we need a definition such as the following:
xml
<!-- <u></u>== Associate the monitor registrey with the AOP logic <u></u>== -->
<bean id="monitorAOP" class="com.sportex.betex.monitor.aop.MonitorAOP">
<property name="monitorRegistry" ref="monitorRegistry"/>
</bean>
<!-- <u></u>== Define the pointcut on @MonitorMethod and associate with th AOP logic <u></u>== -->
<aop:config proxy-target-class="true">
<aop:pointcut id="componentMonitor" expression="@annotation(com.sportex.betex.monitor.aop.MonitorMethod)"/>
<aop:aspect id="monitoring" ref="monitorAOP">
<aop:around pointcut-ref="componentMonitor" method="monitorMethod"/>
</aop:aspect>
</aop:config>
If it is difficult to annotate the classes to be monitored (generated code for example), or you want to use a different pointcut expression, you can use the FixedMonitorAOP
. This class will always use the same monitor.
This is particularly useful to monitor CXF generated clients. Note that proxy-target-class must be false for this approach to work with CXF.
Note that you will need one pointcut/FixedMonitorAOP/Aspect per monitor, as this approach doesn’t have the flexibility of the annotation parameters.
xml
<bean id="fixedMonitorAOP" class="com.sportex.betex.monitor.aop.FixedMonitorAOP">
<property name="monitor" ref="monitorDB"/>
</bean>
<!-- <u></u>== Define the pointcut on an interface (for example) and associate with th AOP logic <u></u>== -->
<aop:config proxy-target-class="false">
<aop:pointcut id="componentMonitor" expression="@this(some.interface.that.you.want.to.monitor)"/>
<aop:aspect id="monitoring" ref="fixedMonitorAOP">
<aop:around pointcut-ref="componentMonitor" method="monitorMethod"/>
</aop:aspect>
</aop:config>
It is also possible to use the monitor beans directly. You just need to inject the monitor in the class that wants to use it and then call the monitor.success() or monitor.failure() from the code.
Note that in this case the ErrorCountingPolicy will not be used. Of course you can use it programmatically if you want.
The implementation of the active monitoring mode of the framework is ActiveMonitoringService. See also Active Monitoring for further detail
The appropiate initialization for the class is:
xml
<bean class="com.sportex.betex.monitor.active.ActiveMonitorService" init-method="start" destroy-method="stop"
lazy-init="false">
<property name="monitorRegistry" ref="monitorRegistry"/>
</bean>
The webping page will be used by Netscaler and other services to check the health status of the application and make a decision about using the application or not.
The contract is very simple: An application should return ”Server OK
” or ”Server FAIL
”. The framework provides a Spring MVC implementation in PingController.
You can create a PingController with:
xml
<bean name="/webping" class="com.sportex.betex.monitor.web.PingController">
<property name="monitorRegistry" ref="monitorRegistry" />
</bean>
You also need to add the mapping in the web.xml like:
xml
<servlet>
<servlet-name>webping</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/webping-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
...
<servlet-mapping>
<servlet-name>webping</servlet-name>
<url-pattern>/webping</url-pattern>
</servlet-mapping>
This is the main interface to provide information for the monitoring tools.
To expose all the monitors through JMX we recommend using the spring tag from the jmx-util project of the service commons stack. See for more details.
xml
<jmx:jmxExport jmxDomain="YourApplicationJmxDomain" jmxInterface="com.sportex.betex.monitor.DefaultMonitorMBean"/>
If you want to expose the overall status of the application through JMX you can publish your registry’s StatusAggregator in your spring context in the same manner. For example, for the provided OverallStatus
aggregator:
xml
<jmx:jmxExport jmxDomain="YourApplicationJmxDomain" jmxInterface="com.sportex.betex.monitor.OverallStatusMBean"/>
Note that a StatusAggregator
can return a WARN status depending on the MaxImpactToOverallStatus of the monitors.
Assuming you’ve used the AOP approach covered above, here’s a complete Spring context xml file:
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jmx="http://www.betfair.com/schema/service-commons/jmx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean name="monitorRegistry" class="com.sportex.betex.monitor.DefaultMonitorRegistry">
<property name="statusAggregator" ref="overallStatus"/>
</bean>
<bean name="overallStatus" class="com.sportex.betex.monitor.OverallStatus">
<property name="monitorRegistry" ref="monitorRegistry"/>
</bean>
<bean name="dbMonitor" class="com.sportex.betex.monitor.DefaultMonitor">
<property name="name" value="DB"/>
<property name="errorCountingPolicy">
<bean class="com.sportex.betex.monitor.aop.DefaultErrorCountingPolicy"/>
</property>
<property name="activeMonitor">
<bean class="com.sportex.betex.monitor.active.db.Database">
<constructor-arg ref="datasource"/>
</bean>
</property>
</bean>
<bean class="com.sportex.betex.monitor.util.MonitorRegistration">
<property name="registry" ref="monitorRegistry"/>
<property name="monitors">
<list>
<ref bean="dbMonitor"/>
</list>
</property>
</bean>
<bean id="monitorAOP" class="com.sportex.betex.monitor.aop.MonitorAOP">
<property name="monitorRegistry" ref="monitorRegistry" />
</bean>
<aop:config proxy-target-class="false">
<aop:pointcut id="annotatedMonitor" expression="@annotation(com.sportex.betex.monitor.aop.MonitorMethod)"/>
<aop:aspect id="monitoring" ref="monitorAOP">
<aop:around pointcut-ref="annotatedMonitor" method="monitorMethod"/>
</aop:aspect>
</aop:config>
<jmx:jmxExport jmxDomain="YourApplicationJmxDomain" jmxInterface="com.sportex.betex.monitor.DefaultMonitorMBean"/>
<jmx:jmxExport jmxDomain="YourApplicationJmxDomain" jmxInterface="com.sportex.betex.monitor.OverallStatusMBean"/>
<bean name="/webping" class="com.sportex.betex.monitor.web.PingController">
<property name="monitorRegistry" ref="monitorRegistry" />
</bean>
</beans>
xml
...
<servlet>
<servlet-name>webping</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/monitor.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
...
<servlet-mapping>
<servlet-name>webping</servlet-name>
<url-pattern>/webping</url-pattern>
</servlet-mapping>
...
java
...
@MonitorMethod ( monitorName = "DB" )
public void aDbCall() {
...
}