package org.curriki.tools.monitor;
import org.apache.commons.exec.*;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.LinkedList;
import java.util.List;
public class MonitorAllSources implements MonitoringConstants {
private static final int duration = 80*1000;
private static String userName = "polx";
public static void main(String[] args) throws Exception {
new MonitorAllSources(args[0]);
}
private File baseDir;
private MyBackgroundProcess apacheLogTailer, appservTailer, topCollector;
private RegularLauncher threadDumpRequestor;
private OutputStream errorStream;
private MonitorAllSources(String processNum) throws Exception {
baseDir = new File(System.getProperty("user.dir"));
new File(baseDir, "output").mkdirs();
errorStream = new FileOutputStream("output/errors.log");
try {
System.out.println("--- Using appserv process number " + processNum + ".");
// launch log collectors
apacheLogTailer = new MyBackgroundProcess("apacheLogTailer",
"./pick-apache-log-minute.sh",
"apacheLog.txt", duration);
apacheLogTailer.start();
appservTailer = new MyBackgroundProcess("appServerTailer",
"ssh appserv@failover-app ./shorttail.sh /appserv/nohup.out 60",
"appservLogs.txt", duration);
appservTailer.start();
topCollector = new MyBackgroundProcess("topCollector",
"ssh appserv@failover-app /usr/sfw/bin/top -U appserv -s 1 -n -d 60",
"tops.txt", duration);
topCollector.start();
// send regular show process list
threadDumpRequestor = new RegularLauncher(
"ssh polx@prod-db /export/home/polx/showProcessList.sh",
12, 5000, "mysqlProcessList.txt","----------------------");
MonitorCacheEviction monitorCacheEviction = new MonitorCacheEviction(new File("cacheEvictions.js"));
monitorCacheEviction.start();
// send regular QUIT signals
threadDumpRequestor = new RegularLauncher("ssh appserv@failover-app /appserv/threadDump.sh", 12, 5000, null, null);
System.out.println("--- Processes launched for one minute, waiting one minute more.");
long startTime = System.currentTimeMillis();
Thread.sleep(120000);
fetchPageLoadTimes();
// now launch stream analyzers
System.out.println("--- Now rendering.");
MonitorWebRenderer.process(startTime, startTime+duration, processNum);
} finally {
/* if(apacheLogTailer!=null) apacheLogTailer.finish();
if(appservTailer!=null) appservTailer.finish();
if(topCollector!=null) topCollector.finish();
if(threadDumpRequestor!=null) threadDumpRequestor.stop(); */
}
}
static void fetchPageLoadTimes() {
HttpClient client = new HttpClient();
String[] urls = URLS_TO_MONITOR;
byte[] b= new byte[512];
for(String url: urls) {
try {
url = MonitorPageLoadTime.urlToFile(url);
GetMethod method = new GetMethod(PAGE_LOAD_MEASURE_BASE + URLEncoder.encode(url));
client.executeMethod(method);
int i=0;
InputStream in = method.getResponseBodyAsStream();
FileOutputStream out = new FileOutputStream(url);
while((i=in.read(b,0,512))!=-1) {
out.write(b,0,i);
}
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class MyBackgroundProcess extends Thread {
final Executor executor;
final ExecuteWatchdog watchdog;
final ExecuteStreamHandler streamHandler;
OutputStream out;
final String outputFile;
final String cli;
boolean finished = false;
MyBackgroundProcess(String name, String cli, String outputFile, long duration) throws IOException {
super(name);
this.cli = cli;
watchdog = new ExecuteWatchdog(duration);
executor = new DefaultExecutor();
executor.setWatchdog(watchdog);
executor.setExitValues(new int[]{0,255});
this.outputFile = outputFile;
if(outputFile!=null) out = new FileOutputStream(outputFile);//new ByteArrayOutputStream();
else out = null;
streamHandler = new PumpStreamHandler(new PrintStream(out), new PrintStream(out));
executor.setStreamHandler(streamHandler);
}
public void run() {
try {
System.out.println("--- Launching " + cli);
System.out.println("--- Output " + outputFile);
int result = executor.execute( CommandLine.parse(cli));
System.out.println("Result is " + result);
} catch (IOException e) {
System.out.println(" - process " + getName() + " failed.");
e.printStackTrace();
} finally {
finished = true;
finish();
}
}
void finish() {
if(!finished) watchdog.stop();
try {
if(out instanceof ByteArrayOutputStream) {
ByteArrayOutputStream bout = (ByteArrayOutputStream) out;
out = new FileOutputStream(outputFile);
System.out.println("Sending buffer of size " + bout.size() + ".");
out.write(bout.toByteArray());
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
out.flush();
out.close();
} catch (IOException e) { e.printStackTrace(); }
}
}
class RegularLauncher {
Executor executor;
int numTimes;
final Thread thread;
void stop() {
thread.stop();
}
RegularLauncher(final String cmd, int numTimes, final int intervalMs, final String outputFile, final String separator) {
this.numTimes = numTimes;
thread = new Thread() { public void run() {
try {
OutputStream out = null;
if(outputFile!=null) out = new FileOutputStream(outputFile);
while (RegularLauncher.this.numTimes>0) {
executor = new DefaultExecutor();
if(out!=null) executor.setStreamHandler(new PumpStreamHandler(out));
executor.execute(CommandLine.parse(cmd));
if(out!=null) {
out.write(separator.getBytes());
out.write((byte) '\n');
out.flush();
}
Thread.sleep(intervalMs);
RegularLauncher.this.numTimes--;
}
if(out!=null) out.close();
} catch (Exception e) {
e.printStackTrace();
}
} };
thread.start();
}
}
class MonitorCacheEviction extends Thread {
public MonitorCacheEviction(File file) {
this.file = file;
}
private File file;
private HttpClient client = new HttpClient();
private List<String[]> entries = new LinkedList<String[]>();
int numRuns = 0, maxRuns = 12, interval = 5;
long startTime;
NumberFormat numForm = new DecimalFormat("####.###");
public void run() {
GetMethod get = new GetMethod("http://failover-app:8080/xwiki/bin/view/CurrikiCode/CacheMonitor");
String prefix = "<li>eviction rate (ev/s):";
startTime = System.currentTimeMillis();
while(numRuns<maxRuns) {
try {
int status = client.executeMethod(get);
if(status!=200) throw new IOException("Bad response from Curriki: " + get.getStatusLine());
LineNumberReader in = new LineNumberReader(new InputStreamReader(get.getResponseBodyAsStream(),"utf-8"));
String line;
while((line=in.readLine())!=null) {
if(line.startsWith(prefix)) {
line = line.substring(prefix.length());
line = line.substring(0,line.indexOf('<'));
pushValue(line);
}
}
in.close();
numRuns++; long timeout;
while((timeout = startTime + numRuns * interval * 1000 - System.currentTimeMillis())<0)
numRuns++;
Thread.sleep(timeout);
} catch (InterruptedException e) {
break;
} catch (IOException e) {
e.printStackTrace();
}
}
output(file);
}
private void pushValue(String value) {
entries.add(new String[]{numForm.format(numRuns*interval), value});
}
public String getValues() {
StringBuilder b = new StringBuilder();
b.append("cacheEvictions = [");
boolean started = false;
for(String[] vals: entries) {
if(started) b.append(", ");
b.append("[").append(vals[0]).append(',').append(vals[1]).append("]");
started = true;
}
b.append("];");
return b.toString();
}
public void output(File file) {
try {
FileUtils.writeStringToFile(file, getValues());
} catch (IOException e) {
e.printStackTrace();
}
}
}