HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Monitor webserver accessibility inconsistencies

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
webserverinconsistenciesaccessibilitymonitor

Problem

I have written a simple application to monitor whether a couple of Java EE 6 web applications deployed to Glassfish 3.1.2.2 are accessible. My intent is to demonstrate to our operations team that the applications are intermittently inaccessible.

```
package monitoring;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class Monitoring {

private static final Logger logger = Logger.getLogger("MonitoringLogger");

public static void main(String[] args) throws MalformedURLException, IOException, InterruptedException {
configureLogger();
URL[] urls = {
new URL("http://alpha:11480/AlphaApplication-war/"),
new URL("http://beta:11680/BetaApplication-war/")
};
while (true) {
for (URL url : urls) {
URLConnection connection = url.openConnection();
connection.setReadTimeout(5000);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
while (reader.ready()) {
logger.info(reader.readLine());
}
} catch (SocketTimeoutException exception) {
logger.log(Level.SEVERE, "Read timed out to {0}", url);
}
}
Thread.sleep(TimeUnit.MINUTES.toMillis(5));
}
}

private static void configureLogger() throws IOException {
FileHandler fh;
fh = new FileHandler("logfile.log");
logger.addHandler(fh);
SimpleFormatter formatter = new SimpleFormatter();
fh.setFormatter(formatter);
log

Solution

The concept in your code is fundamentally good, but there are a few things I would recommend you change.
Static initializers

First up, I like static initializer functions when the static component is non-trivial. So, for example, this code:

private static final Logger logger = Logger.getLogger("MonitoringLogger");

public static void main(String[] args) throws MalformedURLException, IOException, InterruptedException {
    configureLogger();
    ......
}

private static void configureLogger() throws IOException {
    FileHandler fh;
    fh = new FileHandler("logfile.log");
    logger.addHandler(fh);
    SimpleFormatter formatter = new SimpleFormatter();
    fh.setFormatter(formatter);
    logger.info("Logger initialized");
}


I would replace with:

private static final Logger logger = configureLogger();

private static Logger configureLogger() {

    try {
        Logger logger = Logger.getLogger("MonitoringLogger");
        FileHandler fh;
        fh = new FileHandler("logfile.log");
        logger.addHandler(fh);
        SimpleFormatter formatter = new SimpleFormatter();
        fh.setFormatter(formatter);
        logger.info("Logger initialized");
        return logger;
    } catch (IOException ioe) {
        throw new IllegalStateException("Could not get logger up.", ioe);
    }
}


That's a 'trivial' change, but it puts the initialization sequence of the code in to a much more structured system.
What to log.

You don't really want to be logging what the sites are showing, you want to be logging their response times. I suggest pulling different metrics than the ones you are getting..... How long it took for the repsonse to come, and whether it was successful, or not. A log that looks like:

2015-07-22 12:23:34 [INFO] 3ms response from http://alpha:11480/AlphaApplication-war/
2015-07-22 12:26:12 [INFO] 3984ms response from http://alpha:11480/AlphaApplication-war/
2015-07-22 12:29:49 [ERROR] 5000ms TIME OUT FROM http://alpha:11480/AlphaApplication-war/


That would be much easier to process.

To do that, you will want to measure the actual times, not the responses... and you will pick up slow-to-respond servers too (perhaps a big garbage collection, over-congested network handler, or something).

So, create a function that has a response, which should be an Object:

private static final class ServerStat {
    private final boolean success;
    private final long milliseconds;

    ServerStat(boolean success, long milliseconds) {
        .....
    }
}


and then a function that tests an HTTP URL:

public static ServerStat pingServer(URL host) {
    long start = System.currentTimeMillis();
    
    boolean ok = false;
    try {

        URLConnection connection = url.openConnection();
        try (InputStream stream = connection.getInputStream()) {

            byte[] buffer = new byte[4096];
            while (stream.read(buffer) >= 0) {
                // throw the data away
            }
        }
        // no exceptions
        ok = true;
    } catch (Exception e) {
        // swallow any exception
    }
    return new ServerStat(ok, System.currentTimeMillis() - start);
}


Now, you have a function which times how long it takes to get a complete response (or fail) from a server.

Now, instead of having an infinite while-loop, have a non-daemon scheduled thread executor instead. Something like:

ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
    ses.scheduleAtFixedRate(() -> pingServerList(totest), 0, 5, TimeUnit.SECONDS);


That runs a function every 5 seconds.

I put it all together like this:

```
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class PingServer {

private static final class ServerStat {
private final boolean success;
private final long milliseconds;
private final String message;

ServerStat(boolean success, long milliseconds, String message) {
this.success = success;
this.milliseconds = milliseconds;
this.message = message;
}
}

public static ServerStat pingServer(URL url) {
long start = System.currentTimeMillis();

boolean ok = false;
String message = "OK";
try {

URLConnection connection = url.openConnection();
connection.setReadTimeout(3000);
try (InputStream stream = connection.getInputStream()) {

byte[] buffer = new byte[4096];
while (stream.read(buffer) >= 0) {
// throw the data away
}
}
// no exceptions
ok = true;
} catch (Exception e) {
message = e.getClass().getName() + ": " + e.ge

Code Snippets

private static final Logger logger = Logger.getLogger("MonitoringLogger");

public static void main(String[] args) throws MalformedURLException, IOException, InterruptedException {
    configureLogger();
    ......
}

private static void configureLogger() throws IOException {
    FileHandler fh;
    fh = new FileHandler("logfile.log");
    logger.addHandler(fh);
    SimpleFormatter formatter = new SimpleFormatter();
    fh.setFormatter(formatter);
    logger.info("Logger initialized");
}
private static final Logger logger = configureLogger();

private static Logger configureLogger() {

    try {
        Logger logger = Logger.getLogger("MonitoringLogger");
        FileHandler fh;
        fh = new FileHandler("logfile.log");
        logger.addHandler(fh);
        SimpleFormatter formatter = new SimpleFormatter();
        fh.setFormatter(formatter);
        logger.info("Logger initialized");
        return logger;
    } catch (IOException ioe) {
        throw new IllegalStateException("Could not get logger up.", ioe);
    }
}
2015-07-22 12:23:34 [INFO] 3ms response from http://alpha:11480/AlphaApplication-war/
2015-07-22 12:26:12 [INFO] 3984ms response from http://alpha:11480/AlphaApplication-war/
2015-07-22 12:29:49 [ERROR] 5000ms TIME OUT FROM http://alpha:11480/AlphaApplication-war/
private static final class ServerStat {
    private final boolean success;
    private final long milliseconds;

    ServerStat(boolean success, long milliseconds) {
        .....
    }
}
public static ServerStat pingServer(URL host) {
    long start = System.currentTimeMillis();
    
    boolean ok = false;
    try {

        URLConnection connection = url.openConnection();
        try (InputStream stream = connection.getInputStream()) {

            byte[] buffer = new byte[4096];
            while (stream.read(buffer) >= 0) {
                // throw the data away
            }
        }
        // no exceptions
        ok = true;
    } catch (Exception e) {
        // swallow any exception
    }
    return new ServerStat(ok, System.currentTimeMillis() - start);
}

Context

StackExchange Code Review Q#97731, answer score: 4

Revisions (0)

No revisions yet.