patternjavaMinor
Monitor webserver accessibility inconsistencies
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
```
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:
I would replace with:
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:
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:
and then a function that tests an HTTP URL:
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:
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
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.