jMonit

1.0-alpha-1


Table of Contents

1. Preface
Introduction
License Information
2. Reference
High level architecture
Instrumentation
Aggregators
Features
Formatting

Chapter 1. Preface

Introduction

License Information

Copyright © 2006-2007 Nicolas De Loof.

Licensed under the Apache License, Version 2.0 (the "License") you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

You can get the latest version of this reference documentation as PDF at http://www.jmonit.org/pdf/Reference.pdf

Chapter 2. Reference

High level architecture

jMonit is composed by three architectural layers :

  • The instrumentation layer is included in the application code to extract the datas. To avoid too much intrusion in your code, the required classes are limited to the org.jmonit package, and many of them are simple interfaces.

  • The computation layer gathers those datas ands builds indicators, like statistics, history, or threshold warnings. The instrumentation and computation layers can collaborate using the feature API, that enable jMonit to accept custom code plugged at runtime.

  • The formating layer renders the indicators into a user interface. jMonit provides a web UI and a simple way to programmatically collect datas if you need to format them by yourself. The formating layer is based on the Visitor pattern, so the data may be formatted in any format (XML, CSV, PDF...) by simply creating the adequate renderer.

Instrumentation

The org.jmonit package provides all required classes to instrument you application code.

The Monitor class is used by application to expose state to the monitoring infrastructure. A Monitor accepts new datas via the add(long) method. jMonit does not know the unit used by such data, so be aware not to mix inconsistent values.

A monitor is identified by a name, that MUST be unique in the application. A recommended usage is to use the full qualified class name + some local name to identify a monitor. For example, the monitor "com.mycompany.ws.MyServiceEndPoint.doSomeBusiness()" could be used to monitor the MyService web service endpoint "doSomeBusiness" method execution. To also monitor SOAP message weight, you can create another monitor "com.mycompany.ws.MyServiceEndPoint.doSomeBusiness()-soap" .

The Monitoring class is a utility class to acces jMonit classes. It provides finders methods to retrieve a monitor by name, tag it, or create a new Probe for performance computation. All Monitors are attched to a repository. You can acces the repository from the Monitoring class, or set a new instance if you want to use a custom repository implementation.

The monitor can be tagged. A tag is used by the application to group monitors and refine the type of data that is monitored. Tags can reflect data type and units, component that uses the monitor, or whatever you need. For example, a monitor attached to a web service endpoint to gather incomming messages size can be tagged "soap", "ws", "bytes" and "received".

Performance is a main part of monitoring. For this purpose, jMonit provides the dedicated Probe class. A new Probe is created by calling Probe.start( monitor ) . The convenience static method Monitoring.start( name ) can be used to get a starter probe in one line. The probe will compute elapsed time until it gets stopped, after the monitored code fragmentends. Using a probe automatically tags the monitor as "perf".

Aggregators

Monitor is an interface, an the implementation may provide many advanced features. The default Monitor implementation is built as a composite : it uses a set of sub-components to compute indicators about the application state.

Those components MUST implement the interface org.jmonit.spi.Aggregator (or extend org.jmonit.monitors.AbstractAggregator ). Before being used by the composite monitor, they receive the composite via the setComposite initialization method. This method will be called any time a new aggregator is added or removed to the monitor. The aggregator may use the composite to acces other aggregators.

Each aggregator receives datas from the composite monitor in the added(long) method. They can use this data to compute any indicator or run any process that can be usefull to monitor the application state. The clear() method is used to reset the aggregator from a management console. Be aware that some counters may not be set to null in this method : for example, the Concurrency aggregator manages a counter of concurrent active threads that use the monitor. Also be aware when creating custom aggreagtors that they are used in a concurrent context. synchronize the required methods or use java.util.concurrent classes to assume thread-safety and data consistency.

Custom aggregators are managed by a org.jmonit.spi.FeatureManager implementation (see later section about features). The default-one uses a properties files in classpath root : jmonit-features.properties . This file lists class name of Factories used to create the aggregators instances. The factory ( org.jmonit.spi.Factory ) is used by jMonit to create new aggregators instance for monitors on demand.

Features

To avoid your application to depend on jMonit implementation code, jMonit provides the feature API : Any aggregator of the composite Monitor can expose a public interface, that we call "Feature". The instrumented application can use those features when the default add(long) method is not sufficient to expose it's state. This API class is used as the identifier for aggregators factories.

The monitor.getFeature(class) method is used to acces a feature. This method MAY return null, so allways check the returned object. The class argument is the expected feature API interface. Thanks to Java5 constructs, the returned object is safelly casted. The default Monitor implementation will anto-enhance it's composite to add the requested feature.

The following code sample demonstrates the feature API usage. Based on an existing monitor, we ask for a feature, dedicated to HTTP status monitoring. The returned object is then used to monitor the current request.

HttpStatus status = monitor.getFeature( HttpStatus.class ); if ( status != null ) { status.setHttpStatus( sc ); }

In many case, the aggregator code is simple and we can use a single class for aggregator and feature (feature is not required to be an interface).

Formatting

Computed indicators must be rendered to the application administrator. jMonit uses the Visitor pattern to expose the monitor (and its aggregators) datas.

An Aggregator MAY implement the org.jmonit.reporting.Visitable interface. In such case, it is reponsible to compute a Map representation of its state and pass it to the visitor. Some aggregators may not be visitable, and in such case are ignored. This can be used for example to create an aggregator that stores application state on shutdown, but has no data to report.

The Visitor pattern can be used by custom application code to build a report on the monitoring state, by simply binding a org.jmonit.reporting.Visitor implementation to the adequate formatting methods. jMonit uses a second level of abstraction via the Renderer interface. This one is used by the RestServlet to provide web-oriented rendering.

The RestServlet accepts REST style URIs. The request path is composed as :

/monitors[/tag/.*]/Feature[+Feature]*
Here are some examples :
  1. /monitors : all monitors, but only name and tags are returned
  2. /monitors/tag/web : all monitors tagged as "web"
  3. /monitors/tag/web/Statistics : all monitors tagged as "web" AND supporting the "Statistics" feature. The feature datas are also returned
  4. /monitors/tag/web/Statistics+Concurrency : all monitors tagged as "web" AND supporting both the "Statistics" and "Concurrency" features.

The data formatting depends on the request "accept" header. It also considers the request path extension. Based on this, a renderer instance is used. For example, request to /monitors/Statistics with accept header set to "application/json" will use the JsonRenderer. Based on this, we can render the monitored datas in many formats, like XML, CSV, PDF...

jMonit provides a web UI built over the REST+json facility. It uses the prototype js library to parse the JSON result and render datas in a grid. Point your browser to http://myserver/myapp/jMonit/performances.html to see it in action.