package com.javamonitor;
import static com.javamonitor.JmxHelper.mbeanExists;
import static com.javamonitor.JmxHelper.registerCoolMBeans;
import static com.javamonitor.JmxHelper.unregisterCoolMBeans;
import static com.javamonitor.mbeans.Server.serverObjectName;
import static java.lang.System.getProperty;
import static java.lang.System.getenv;
import static java.lang.Thread.sleep;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Logger.getLogger;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.javamonitor.mbeans.Server;
/**
* The Java-monitor collector class.
*
* @author Barry van Someren
* @author Kees Jan Koster <kjkoster@kjkoster.org>
*/
public class JavaMonitorCollector {
private static final Logger log = getLogger(JavaMonitorCollector.class
.getName());
private Thread collectorThread = null;
private Collector collector = null;
private boolean started = false;
private static final long ONE_MINUTE = 60L * 1000L;
private static final String JAVA_MONITOR_ID = "javamonitor.uniqueid";
private static final Server server = new Server();
/**
* Create a new Java-monitor collector, which requires the URL to be
* specified using the system property "javamonitor.url".
* <p>
* If specified, it will use the value from system property
* "javamonitor.uniqueid" as the unique ID for this application.
* Failing that, it will use the MBeans to find the lowest port number, if
* applicable.
*/
public JavaMonitorCollector() {
this(null);
}
/**
* Create a new Java-monitor collector, specifying a unique ID for this
* application.
* <p>
* The collector URL may be overridden from the command line using the
* system property "javamonitor.url".
* <p>
* The unique ID may be overridden from the command line using the system
* property "javamonitor.uniqueid".
*
* @param uniqueId
* The unique ID to use for this application, in case system
* property "javamonitor.uniqueid" is not set.
*/
public JavaMonitorCollector(final String uniqueId) {
String id = uniqueId;
if (getProperty(JAVA_MONITOR_ID) != null) {
id = getProperty(JAVA_MONITOR_ID);
}
if (id == null) {
id = checkForEatJId();
}
collector = new Collector(id);
collectorThread = new Thread(new CollectorDriver(),
"java-monitor collector");
}
/**
* We have some specific code for eatj.com's hosting service, because they
* use port dynamically. This causes eatj customers to see a new host after
* every restart. We check here to see if we are running at eatj. If so, we
* find the eatj user ID to use as lowest 'port'.
*
* @return The eatj user id, or <code>null</code> if we are not running on
* eatj hosts.
*/
private String checkForEatJId() {
final String hostname = getenv("HOSTNAME");
if (hostname == null) {
return null;
}
if (!hostname.toLowerCase().endsWith(".eatj.com")) {
return null;
}
return getenv("USER") + " (eatj)";
}
/**
* Start the collector, if it was not already started.
*
* @throws Exception
* When the helper MBeans could not be registered.
*/
public synchronized void start() throws Exception {
if (mbeanExists(serverObjectName)) {
throw new OnHoldException(
"A Java-monitor probe is already running in this JVM. See http://java-monitor.com/duplicate-probe.html");
}
if (!started && collectorThread != null) {
registerCoolMBeans(server);
collectorThread.start();
started = true;
}
}
/**
* Stop the collector, if it was running.
*/
public synchronized void stop() {
if (started && collectorThread != null) {
collectorThread.interrupt();
try {
collectorThread.join();
} catch (InterruptedException e) {
// ignore, we're going down anyway
}
unregisterCoolMBeans();
started = false;
}
}
private final class CollectorDriver implements Runnable {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
try {
// give the container around us a little time to start up and
// (more importantly) register its mbeans.
sleep(2000L);
for (;;) {
try {
for (;;) {
if (collector.push()) {
collector.push();
}
server.setLastException(null);
sleep(ONE_MINUTE);
}
} catch (InterruptedException e) {
throw e; // it ends up in the outer try block
} catch (OnHoldException e) {
throw e; // it ends up in the outer try block
} catch (Throwable e) {
if (server.getLastException() == null) {
server.setLastException(e);
log.log(Level.SEVERE,
"This probe was hit by an unexpected exception: "
+ e.getMessage(), e);
}
sleep(ONE_MINUTE);
}
}
} catch (InterruptedException e) {
// ignore. we're exiting
} catch (OnHoldException e) {
log.log(SEVERE,
"This probe was put on hold by the collector (redeploy to try again): "
+ e.getOnHoldBecause());
}
}
}
}