Permalink
Browse files

Created a configuration page and implemented enabling / disabling sta…

…ts recording from that page.
  • Loading branch information...
1 parent 56308f3 commit fb1cfb3a728dcba0d68cf8d792b2a6b2639f57da Greg Murray committed Jan 11, 2010
View
@@ -2,9 +2,13 @@
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
+ <classpathentry exported="true" kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry kind="lib" path="lib/servlet-api-2.4.jar"/>
- <classpathentry kind="lib" path="lib/org.json-0.0.3.jar"/>
+ <classpathentry kind="lib" path="lib/org.json-0.0.3.jar">
+ <attributes>
+ <attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
+ </attributes>
+ </classpathentry>
<classpathentry kind="output" path="build/classes"/>
</classpath>
@@ -48,7 +48,7 @@
public static final String EPISODE_POSTER = "resources/episodes-viewer.js";
public static final String EPISODE = "org.protorabbit.profile.episode";
public static final String START_TIME = "org.protorabbit.START_TIME";
- public static final String DEFAULT_EPISODE_PROCESS = "org.protorabbit.profile.episode.DEFAULT_PROCESS";;
+ public static final String DEFAULT_EPISODE_PROCESS = "org.protorabbit.profile.episode.DEFAULT_PROCESS";
public static final int UNKNOWN = 0;
public static final int SCRIPT = 1;
@@ -2,7 +2,9 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.logging.Logger;
import javax.servlet.ServletConfig;
@@ -212,12 +214,57 @@ protected void doGet(HttpServletRequest request,
Object jo = json.serialize( data );
response.getWriter().write( jo.toString() );
return;
+ } else if (command.startsWith("/configuration") ) {
+ JSONResponse jr = new JSONResponse();
+ Map<String,Object> configuration = new HashMap<String,Object>();
+ configuration.put( "canRecordStats", statsManager.canRecordStats() );
+ configuration.put( "statsRecordingEnabled", statsManager.isStatsRecordingEnabled() );
+ jr.setData( configuration);
+ Object jo = json.serialize( jr );
+ response.getWriter().write( jo.toString() );
+ return;
+ } else if (command.startsWith("/configure") ) {
+ String configCommand = getLastPathItem( command );
+ JSONResponse jr = new JSONResponse();
+ if ( configCommand != null ) {
+ String configValue = request.getParameter( "value" );
+ if ( "enableRecording".equals( configCommand )) {
+ if ( configValue != null) {
+ Boolean enabled = null;
+ if ( "true".equals(configValue) ) {
+ enabled = true;
+ } else if ( "false".equals(configValue)) {
+ enabled = false;
+ }
+ if ( enabled != null) {
+ statsManager.enableStatsRecording( enabled.booleanValue() );
+ jr.setData( ((enabled == Boolean.TRUE) ? "Enabled" : "Disabled ") + " stats recording" );
+ } else {
+ ArrayList<String> errors = new ArrayList<String>();
+ errors.add( "Bad query paramaters. A value property is required." );
+ jr.setErrors( errors );
+ }
+ } else {
+ ArrayList<String> errors = new ArrayList<String>();
+ errors.add( "Unknown command " + configCommand );
+ jr.setErrors( errors );
+ }
+ }
+ } else {
+ ArrayList<String> errors = new ArrayList<String>();
+ errors.add( "Command not provided as last part of url." );
+ jr.setErrors( errors );
+ }
+ Object jo = json.serialize( jr );
+ response.getWriter().write( jo.toString() );
+ return;
} else {
- String commands = "Commands are : all, " +
+ String commands = "Options are : all, " +
"summary/[timestamp]," +
"stats/[timestamp], " +
"archiveTimestamps, " +
- "summaryTimestamps";
+ "summaryTimestamps, " +
+ "configure";
Object data = createJSONError( commands );
response.setHeader( "pragma", "NO-CACHE");
response.setHeader( "Cache-Control", "no-cache" );
@@ -9,11 +9,13 @@
public interface IStatRecorder {
+ public void enableRecording( boolean enable );
public void init( ServletContext ctx);
public void recordStatItem( IStat stat );
public void shutdown();
public void cleanup();
public boolean canRecordStats();
+ public boolean isEnabled();
public List<Long> getArchiveTimestamps();
public List<Long> getSummaryTimestamps();
public Map<String, Object> loadStatsForDate(long timestamp);
@@ -46,6 +46,7 @@
private static final long ONE_DAY = ONE_HOUR * 24;
private static final long SEVEN_DAYS = ONE_DAY * 7;
private boolean canRecordStats = true;
+ private boolean recordStats = true;
private static Logger logger = null;
private File statsDirectory = null;
private String host = "localhost";
@@ -66,9 +67,8 @@ public long getTime( long timestamp, long resolution ) {
return timestamp - mod;
}
- public void init( ServletContext ctx ) {
+ private void getStatsDirectory( ServletContext ctx ) {
File temp = (File)ctx.getAttribute("javax.servlet.context.tempdir");
-
if ( temp.isDirectory() ) {
File pdir = new File ( temp, "protorabbit" );
statsDirectory = new File ( pdir , "stats" );
@@ -80,13 +80,19 @@ public void init( ServletContext ctx ) {
canRecordStats = false;
return;
}
+ } else {
+ canRecordStats = true;
}
getLogger().info( "Stats work area is : " + statsDirectory );
} else {
getLogger().info( "Could not access to work area." );
canRecordStats = false;
}
+ }
+
+ public void init( ServletContext ctx ) {
+ getStatsDirectory( ctx );
try {
InetAddress ia = null;
ia = InetAddress.getLocalHost();
@@ -143,9 +149,10 @@ private File getCurrentStatsFile() {
if ( !currentStatsFile.exists() ) {
try {
currentStatsFile.createNewFile();
-
} catch (IOException e) {
- getLogger().log( Level.SEVERE, "Could not create protorabbit directory to record stats." );
+ getLogger().log( Level.SEVERE,
+ "Could not create protorabbit directory to record stats. Message was " +
+ e.getLocalizedMessage() );
canRecordStats = false;
return null;
}
@@ -154,7 +161,7 @@ private File getCurrentStatsFile() {
}
public synchronized void recordStatItem(IStat stat) {
- if ( !canRecordStats ) {
+ if ( !canRecordStats || !recordStats ) {
return;
}
try {
@@ -164,12 +171,14 @@ public synchronized void recordStatItem(IStat stat) {
out.write( json.serialize(stat).toString() + ",\n" );
out.flush();
} else {
- getLogger().log( Level.SEVERE, "Could not write to stats file. The writer was null." );
+ getLogger().log( Level.SEVERE,
+ "Could not write to stats file. The writer was not available." );
canRecordStats = false;
return;
}
} catch (IOException e) {
- getLogger().log( Level.SEVERE, "Could not write to stats file." );
+ getLogger().log( Level.SEVERE,
+ "Could not write to stats file. Message was " + e.getLocalizedMessage() );
canRecordStats = false;
}
@@ -195,28 +204,29 @@ private String getBaseFileName() {
}
public void updateDailySummary() {
- long start = System.currentTimeMillis();
- getLogger().info("Updating daily summary.");
- String fileName = getBaseFileName() + "-summary.json";
- Map<String, Object> stats = loadStats( getCurrentStatsFile() );
- archiveStats(fileName, stats);
- long end = System.currentTimeMillis();
- getLogger().info("Daily summary complete. Time : " + ( end - start ) + "ms" );
+ if ( recordStats ) {
+ long start = System.currentTimeMillis();
+ getLogger().info("Updating daily summary.");
+ String fileName = getBaseFileName() + "-summary.json";
+ Map<String, Object> stats = loadStats( getCurrentStatsFile() );
+ archiveStats( fileName, stats );
+ long end = System.currentTimeMillis();
+ getLogger().info("Daily summary complete. Time : " + ( end - start ) + "ms" );
+ }
}
public Object loadSummary( File f ) {
FileInputStream fis;
Object stats = null;
try {
fis = new FileInputStream(f);
- StringBuffer buff = IOUtil.loadStringFromInputStream(fis, "UTF-8");
+ StringBuffer buff = IOUtil.loadStringFromInputStream( fis, "UTF-8" );
stats = json.genericDeserialize( buff.toString() );
} catch (FileNotFoundException e) {
- getLogger().log( Level.SEVERE, "Could deserialize file.", e );
+ getLogger().log( Level.SEVERE, "Could load summary file.", e );
} catch (IOException e) {
- getLogger().log( Level.SEVERE, "Could deserialize file.", e );
+ getLogger().log( Level.SEVERE, "Could load summary file.", e );
}
-
return stats;
}
@@ -393,7 +403,7 @@ private void combineLists( Map<String, Object> src, Map<String, Object> target,
getLogger().log( Level.SEVERE, "Error combining lists.", e );
}
}
-
+
@SuppressWarnings("unchecked")
public List<Object> condenseList( List<Object> tItems, long r ) {
LinkedHashMap<Long,Object> jBuckets = new LinkedHashMap<Long,Object>();
@@ -413,28 +423,28 @@ private void combineLists( Map<String, Object> src, Map<String, Object> target,
rvals.addAll(jBuckets.values());
return rvals;
}
-
+
private void combineSummaries( Map<String, Object> src, Map<String, Object> target, Resolution r ) {
// append views->values
- combineLists(src,target, "view", r);
+ combineLists( src,target, "view", r );
// append json->values
- combineLists(src,target, "json", r);
+ combineLists( src,target, "json", r );
// averageJSONProcessingTime->values
- combineLists(src,target, "averageViewProcessingTime", r);
+ combineLists( src,target, "averageViewProcessingTime", r );
// averageJSONPayload->values
- combineLists(src,target, "averageViewPayload", r);
+ combineLists( src,target, "averageViewPayload", r );
// averageJSONProcessingTime->values
- combineLists(src,target, "averageJSONProcessingTime", r);
+ combineLists( src,target, "averageJSONProcessingTime", r );
// averageJSONPayload->values
- combineLists(src,target, "averageJSONPayload", r);
+ combineLists( src,target, "averageJSONPayload", r );
// pageStats->text/html pageStats->application/json (in each get key work out averageContentLength, averageProcessingTime, accessCount, totalProcessingTime, totalContentLength
combinePageStats( src, target );
}
@SuppressWarnings("unchecked")
public Object loadSummarySinceDate( long timestamp, Resolution r ) {
Map<String, Object> summaries = null;
- if (statsDirectory != null) {
+ if (statsDirectory != null ) {
List<Long> times = getSummaryTimestamps();
@@ -784,4 +794,12 @@ public boolean canRecordStats() {
return canRecordStats;
}
+ public void enableRecording(boolean enable) {
+ recordStats = enable;
+ }
+
+ public boolean isEnabled() {
+ return recordStats;
+ }
+
}
@@ -493,4 +493,15 @@ public void contextInitialized( ServletContextEvent e ) {
sr.init( ctx );
}
+ public void enableStatsRecording( boolean enable ) {
+ sr.enableRecording( enable );
+ }
+
+ public boolean isStatsRecordingEnabled() {
+ return sr.isEnabled();
+ }
+
+ public boolean canRecordStats() {
+ return sr.canRecordStats();
+ }
}
Binary file not shown.
@@ -0,0 +1,73 @@
+<html>
+ <head>
+ <title>Protorabbit Monitor Configuration</title>
+ <script type="text/javascript" src="resources/jmaki/jmaki-full.js"></script>
+ <script type="text/javascript" src="resources/js/monitor.js"></script>
+ <script>
+ function enableStatsMonitoring( _enable ) {
+ ajax( {
+ url : "../stats/configure/enableRecording?value=" + _enable,
+ onsuccess : function( message ) {
+ loadStatus();
+ },
+ onerror : function( message) {
+ alert( message.errors.join(",") );
+ }
+ } )
+ }
+ function loadStatus() {
+ ajax( {
+ url : "../stats/configuration",
+ onsuccess : function( message ) {
+ var canRecord = document.getElementById( "canRecordStats" );
+ canRecord.innerHTML = message.data.canRecordStats;
+ var statsRecordingEnabled = document.getElementById( "statsRecordingEnabled" );
+ statsRecordingEnabled.innerHTML = ( message.data.statsRecordingEnabled === true ) ? "Enabled" : "Disabled";
+ var statsRecordingCommand = document.getElementById("statsRecordingCommand");
+ if ( message.data.statsRecordingEnabled === false) {
+ statsRecordingCommand.innerHTML = '<a href="javascript:void(0)" onclick="enableStatsMonitoring(true)">enable</a>';
+ } else {
+ statsRecordingCommand.innerHTML = '<a href="javascript:void(0)" onclick="enableStatsMonitoring(false)">disable</a>';
+ }
+ },
+ onerror : function( message) {
+ alert( message.errors.join(",") );
+ }
+ } )
+ }
+ jmaki.subscribe("/jmaki/runtime/loadComplete", loadStatus);
+ </script>
+ <style>
+ .pmenu {
+ padding:3px;
+ height:40px;
+ font-size:2em;
+ background:#333;
+ color:#fff
+ }
+
+ .pmenu a {
+ color : #fff;
+ font-size:0.4em;
+ }
+
+ .pmenu a:visited {
+ color : #fff;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="pmenu">
+ <div style="float:left">Protorabbit Monitor Configuration</div>
+ <div style="float:right">
+ <a href="components.html">Components</a>
+ <a href="resources.html">Resources</a>
+ <a href="statistics-archive.html">Statistics</a>
+ <a href="../"> Home</a>
+ </div>
+ </div>
+ <p> Can Record Stats : <span id="canRecordStats"></span></p>
+ <p> Stats Recording : <span id="statsRecordingEnabled"></span> (<span id="statsRecordingCommand"> </span>)</p>
+
+ </body>
+</html>
@@ -27,14 +27,15 @@
<div style="float:left">Protorabbit Monitor</div>
<div style="float:right">
<a href="components.html">Components</a>
- <a href="resources.html">Resources</a>
+ <a href="resources.html">Cached Resources</a>
<a href="statistics-archive.html">Statistics</a>
<a href="../"> Home</a>
</div>
</div>
+ <p><a href="configure.html">Configure Monitoring</a></p>
<p><a href="components.html">Loaded Components</a></p>
<p><a href="episodes.html">Episodes</a></p>
- <p><a href="resources.html">Resources</a></p>
+ <p><a href="resources.html">Cached Resources</a></p>
<p><a href="statistics-archive.html">Statistics</a></p>
<p><a href="tests.html">Tests</a></p>

0 comments on commit fb1cfb3

Please sign in to comment.