Explorar o código

Add JSONification of WebStats module. Adds a '?json' query parameter
to the fetch URL to return the data in JSON format. Also adds a simple
'sim.html' that uses JavaScript to display the JSON data. Not pretty
but an example.

Robert Adams %!s(int64=11) %!d(string=hai) anos
pai
achega
427ab219b8

+ 82 - 2
OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs

@@ -32,6 +32,7 @@ using System.Reflection;
 using System.Text;
 using Mono.Data.SqliteClient;
 using OpenMetaverse;
+using OpenMetaverse.StructuredData;
 using OpenSim.Framework;
 using OpenSim.Region.Framework.Scenes;
 using OpenSim.Framework.Monitoring;
@@ -51,7 +52,6 @@ namespace OpenSim.Region.UserStatistics
 
         public Hashtable ProcessModel(Hashtable pParams)
         {
-            
             List<Scene> m_scene = (List<Scene>)pParams["Scenes"];
 
             Hashtable nh = new Hashtable();
@@ -129,6 +129,86 @@ namespace OpenSim.Region.UserStatistics
             return output.ToString();
         }
 
+        /// <summary>
+        /// Convert active connections information to JSON string. Returns a structure:
+        /// <pre>
+        /// {"regionName": {
+        ///     "presenceName": {
+        ///         "name": "presenceName",
+        ///         "position": "<x,y,z>",
+        ///         "isRoot": "false",
+        ///         "throttle": {
+        ///         },
+        ///         "queue": {
+        ///         }
+        ///     },
+        ///     ... // multiple presences in the scene
+        ///   },
+        ///   ...   // multiple regions in the sim
+        /// }
+        ///
+        /// </pre>
+        /// </summary>
+        /// <param name="pModelResult"></param>
+        /// <returns></returns>
+        public string RenderJson(Hashtable pModelResult)
+        {
+            List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
+
+            OSDMap regionInfo = new OSDMap();
+            foreach (Scene scene in all_scenes)
+            {
+                OSDMap sceneInfo = new OpenMetaverse.StructuredData.OSDMap();
+                List<ScenePresence> avatarInScene = scene.GetScenePresences();
+                foreach (ScenePresence av in avatarInScene)
+                {
+                    OSDMap presenceInfo = new OSDMap();
+                    presenceInfo.Add("Name", new OSDString(av.Name));
+
+                    Dictionary<string,string> queues = new Dictionary<string, string>();
+                    if (av.ControllingClient is IStatsCollector)
+                    {
+                        IStatsCollector isClient = (IStatsCollector) av.ControllingClient;
+                        queues = decodeQueueReport(isClient.Report());
+                    }
+                    OSDMap queueInfo = new OpenMetaverse.StructuredData.OSDMap();
+                    foreach (KeyValuePair<string, string> kvp in queues) {
+                        queueInfo.Add(kvp.Key, new OSDString(kvp.Value));
+                    }
+                    sceneInfo.Add("queues", queueInfo);
+
+                    if (av.IsChildAgent)
+                        presenceInfo.Add("isRoot", new OSDString("false"));
+                    else
+                        presenceInfo.Add("isRoot", new OSDString("true"));
+
+                    if (av.AbsolutePosition == DefaultNeighborPosition)
+                    {
+                        presenceInfo.Add("position", new OSDString("<0, 0, 0>"));
+                    }
+                    else
+                    {
+                        presenceInfo.Add("position", new OSDString(string.Format("<{0},{1},{2}>",
+                                                    (int)av.AbsolutePosition.X,
+                                                    (int) av.AbsolutePosition.Y,
+                                                    (int) av.AbsolutePosition.Z)) );
+                    }
+
+                    Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1));
+                    OSDMap throttleInfo = new OpenMetaverse.StructuredData.OSDMap();
+                    foreach (string throttlename in throttles.Keys)
+                    {
+                        throttleInfo.Add(throttlename, new OSDString(throttles[throttlename].ToString()));
+                    }
+                    presenceInfo.Add("throttle", throttleInfo);
+
+                    sceneInfo.Add(av.Name, presenceInfo);
+                }
+                regionInfo.Add(scene.RegionInfo.RegionName, sceneInfo);
+            }
+            return regionInfo.ToString();
+        }
+
         public Dictionary<string, int> DecodeClientThrottles(byte[] throttle)
         {
             Dictionary<string, int> returndict = new Dictionary<string, int>();
@@ -203,7 +283,7 @@ namespace OpenSim.Region.UserStatistics
                 returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++;
                 returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++;
                 returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++;
-                returndic.Add("Asset", rep.Substring((7 * pos), 8)); 
+                returndic.Add("Asset", rep.Substring((7 * pos), 8));
                 /*
                  * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
                                  SendQueue.Count(),

+ 27 - 0
OpenSim/Region/UserStatistics/Clients_report.cs

@@ -31,6 +31,7 @@ using System.Collections.Generic;
 using System.Text;
 using Mono.Data.SqliteClient;
 using OpenMetaverse;
+using OpenMetaverse.StructuredData;
 using OpenSim.Region.Framework.Scenes;
 
 namespace OpenSim.Region.UserStatistics
@@ -44,6 +45,32 @@ namespace OpenSim.Region.UserStatistics
             get { return "Client"; }
         }
 
+        /// <summary>
+        /// Return summar information in the form:
+        /// <pre>
+        /// {"totalUsers": "34",
+        ///  "totalSessions": "233",
+        ///  ...
+        /// }
+        /// </pre>
+        /// </summary>
+        /// <param name="pModelResult"></param>
+        /// <returns></returns>
+        public string RenderJson(Hashtable pModelResult) {
+            stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"];
+
+            OSDMap summaryInfo = new OpenMetaverse.StructuredData.OSDMap();
+            summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString()));
+            summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString()));
+            summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString()));
+            summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString()));
+            summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString()));
+            summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString()));
+            summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString()));
+            summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString()));
+            return summaryInfo.ToString();
+        }
+
         public Hashtable ProcessModel(Hashtable pParams)
         {
             SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"];

+ 27 - 0
OpenSim/Region/UserStatistics/Default_Report.cs

@@ -32,6 +32,7 @@ using System.Reflection;
 using System.Text;
 using Mono.Data.SqliteClient;
 using OpenMetaverse;
+using OpenMetaverse.StructuredData;
 using OpenSim.Region.Framework.Scenes;
 using OpenSim.Framework.Monitoring;
 
@@ -230,6 +231,31 @@ TD.align_top { vertical-align: top; }
             return returnstruct;
         }
 
+        /// <summary>
+        /// Return summar information in the form:
+        /// <pre>
+        /// {"totalUsers": "34",
+        ///  "totalSessions": "233",
+        ///  ...
+        /// }
+        /// </pre>
+        /// </summary>
+        /// <param name="pModelResult"></param>
+        /// <returns></returns>
+        public string RenderJson(Hashtable pModelResult) {
+            stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"];
+
+            OSDMap summaryInfo = new OSDMap();
+            summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString()));
+            summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString()));
+            summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString()));
+            summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString()));
+            summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString()));
+            summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString()));
+            summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString()));
+            summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString()));
+            return summaryInfo.ToString();
+        }
     }
 
     public struct stats_default_page_values
@@ -247,4 +273,5 @@ TD.align_top { vertical-align: top; }
         public Dictionary<UUID, USimStatsData> sim_stat_data;
         public Dictionary<string, IStatsController> stats_reports;
     }
+ 
 }

+ 1 - 0
OpenSim/Region/UserStatistics/IStatsReport.cs

@@ -34,5 +34,6 @@ namespace OpenSim.Region.UserStatistics
         string ReportName { get; }
         Hashtable ProcessModel(Hashtable pParams);
         string RenderView(Hashtable pModelResult);
+        string RenderJson(Hashtable pModelResult);
     }
 }

+ 29 - 0
OpenSim/Region/UserStatistics/LogLinesAJAX.cs

@@ -33,6 +33,7 @@ using System.Text;
 using System.Text.RegularExpressions;
 using Mono.Data.SqliteClient;
 using OpenMetaverse;
+using OpenMetaverse.StructuredData;
 using OpenSim.Region.Framework.Scenes;
 using OpenSim.Framework.Monitoring;
 
@@ -125,6 +126,34 @@ namespace OpenSim.Region.UserStatistics
             return output.ToString();
         }
 
+        /// <summary>
+        /// Return the last log lines. Output in the format:
+        /// <pre>
+        /// {"logLines": [
+        /// "line1",
+        /// "line2",
+        /// ...
+        /// ]
+        /// }
+        /// </pre>
+        /// </summary>
+        /// <param name="pModelResult"></param>
+        /// <returns></returns>
+        public string RenderJson(Hashtable pModelResult)
+        {
+            OSDMap logInfo = new OpenMetaverse.StructuredData.OSDMap();
+
+            OSDArray logLines = new OpenMetaverse.StructuredData.OSDArray();
+            string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n");
+            string[] result = Regex.Split(tmp, "\n");
+            for (int i = 0; i < result.Length; i++)
+            {
+                logLines.Add(new OSDString(result[i]));
+            }
+            logInfo.Add("logLines", logLines);
+            return logInfo.ToString();
+        }
+
         #endregion
     }
 }

+ 23 - 8
OpenSim/Region/UserStatistics/Prototype_distributor.cs

@@ -36,7 +36,18 @@ namespace OpenSim.Region.UserStatistics
 {
     public class Prototype_distributor : IStatsController
     {
-        private string prototypejs=string.Empty;
+        private string jsFileName = "prototype.js";
+        private string prototypejs = string.Empty;
+
+        public Prototype_distributor()
+        {
+            jsFileName = "prototype.js";
+        }
+
+        public Prototype_distributor(string jsName) 
+        {
+            jsFileName = jsName;
+        }
 
         public string ReportName
         {
@@ -45,20 +56,24 @@ namespace OpenSim.Region.UserStatistics
         public Hashtable ProcessModel(Hashtable pParams)
         {
             Hashtable pResult = new Hashtable();
-            if (prototypejs.Length == 0)
+            pResult["js"] = jsFileName;
+            return pResult;
+        }
+
+        public string RenderView(Hashtable pModelResult)
+        {
+            string fileName = (string)pModelResult["js"];
+            using (StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/" + fileName, FileMode.Open)))
             {
-                StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/prototype.js", FileMode.Open));
                 prototypejs = fs.ReadToEnd();
                 fs.Close();
-                fs.Dispose();
             }
-            pResult["js"] = prototypejs;
-            return pResult;
+            return prototypejs;
         }
 
-        public string RenderView(Hashtable pModelResult)
+        public string RenderJson(Hashtable pModelResult)
         {
-            return pModelResult["js"].ToString();
+            return "{}";
         }
 
     }

+ 5 - 0
OpenSim/Region/UserStatistics/Sessions_Report.cs

@@ -278,6 +278,11 @@ TD.align_top { vertical-align: top; }
             public DateTime start_time;
         }
 
+        public string RenderJson(Hashtable pModelResult)
+        {
+            return "{}";
+        }
         #endregion
     }
+
 }

+ 59 - 0
OpenSim/Region/UserStatistics/SimStatsAJAX.cs

@@ -32,6 +32,7 @@ using System.Reflection;
 using System.Text;
 using Mono.Data.SqliteClient;
 using OpenMetaverse;
+using OpenMetaverse.StructuredData;
 using OpenSim.Region.Framework.Scenes;
 using OpenSim.Framework.Monitoring;
 
@@ -218,6 +219,64 @@ namespace OpenSim.Region.UserStatistics
             return output.ToString();
         }
 
+        /// <summary>
+        /// Return stat information for all regions in the sim. Returns data of the form:
+        /// <pre>
+        /// {"REGIONNAME": {
+        ///     "region": "REGIONNAME",
+        ///     "timeDilation": "101", 
+        ///     ...     // the rest of the stat info
+        ///     },
+        ///  ...    // entries for each region
+        ///  }
+        /// </pre>
+        /// </summary>
+        /// <param name="pModelResult"></param>
+        /// <returns></returns>
+        public string RenderJson(Hashtable pModelResult)
+        {
+            List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
+            Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"];
+
+            OSDMap allStatsInfo = new OpenMetaverse.StructuredData.OSDMap();
+            foreach (USimStatsData sdata in sdatadic.Values)
+            {
+                OSDMap statsInfo = new OpenMetaverse.StructuredData.OSDMap();
+                string regionName = "unknown";
+                foreach (Scene sn in all_scenes)
+                {
+                    if (sn.RegionInfo.RegionID == sdata.RegionId)
+                    {
+                        regionName = sn.RegionInfo.RegionName;
+                        break;
+                    }
+                }
+                statsInfo.Add("region", new OSDString(regionName));
+                statsInfo.Add("timeDilation", new OSDString(sdata.TimeDilation.ToString()));
+                statsInfo.Add("simFPS", new OSDString(sdata.SimFps.ToString()));
+                statsInfo.Add("physicsFPS", new OSDString(sdata.PhysicsFps.ToString()));
+                statsInfo.Add("agentUpdates", new OSDString(sdata.AgentUpdates.ToString()));
+                statsInfo.Add("rootAgents", new OSDString(sdata.RootAgents.ToString()));
+                statsInfo.Add("childAgents", new OSDString(sdata.ChildAgents.ToString()));
+                statsInfo.Add("totalPrims", new OSDString(sdata.TotalPrims.ToString()));
+                statsInfo.Add("activePrims", new OSDString(sdata.ActivePrims.ToString()));
+                statsInfo.Add("activeScripts", new OSDString(sdata.ActiveScripts.ToString()));
+                statsInfo.Add("scriptLinesPerSec", new OSDString(sdata.ScriptLinesPerSecond.ToString()));
+                statsInfo.Add("totalFrameTime", new OSDString(sdata.TotalFrameTime.ToString()));
+                statsInfo.Add("agentFrameTime", new OSDString(sdata.AgentFrameTime.ToString()));
+                statsInfo.Add("physicsFrameTime", new OSDString(sdata.PhysicsFrameTime.ToString()));
+                statsInfo.Add("otherFrameTime", new OSDString(sdata.OtherFrameTime.ToString()));
+                statsInfo.Add("outPacketsPerSec", new OSDString(sdata.OutPacketsPerSecond.ToString()));
+                statsInfo.Add("inPacketsPerSec", new OSDString(sdata.InPacketsPerSecond.ToString()));
+                statsInfo.Add("unackedByptes", new OSDString(sdata.UnackedBytes.ToString()));
+                statsInfo.Add("pendingDownloads", new OSDString(sdata.PendingDownloads.ToString()));
+                statsInfo.Add("pendingUploads", new OSDString(sdata.PendingUploads.ToString()));
+
+                allStatsInfo.Add(regionName, statsInfo);
+            }
+            return allStatsInfo.ToString();
+        }
+
         #endregion
     }
 }

+ 4 - 0
OpenSim/Region/UserStatistics/Updater_distributor.cs

@@ -62,5 +62,9 @@ namespace OpenSim.Region.UserStatistics
             return pModelResult["js"].ToString();
         }
 
+        public string RenderJson(Hashtable pModelResult) {
+            return "{}";
+        }
+
     }
 }

+ 24 - 1
OpenSim/Region/UserStatistics/WebStatsModule.cs

@@ -121,6 +121,10 @@ namespace OpenSim.Region.UserStatistics
             reports.Add("clients.report", clientReport);
             reports.Add("sessions.report", sessionsReport);
 
+            reports.Add("sim.css", new Prototype_distributor("sim.css"));
+            reports.Add("sim.html", new Prototype_distributor("sim.html"));
+            reports.Add("jquery.js", new Prototype_distributor("jquery.js"));
+
             ////
             // Add Your own Reports here (Do Not Modify Lines here Devs!)
             ////
@@ -255,9 +259,12 @@ namespace OpenSim.Region.UserStatistics
             string regpath = request["uri"].ToString();
             int response_code = 404;
             string contenttype = "text/html";
+            bool jsonFormatOutput = false;
             
             string strOut = string.Empty;
 
+            // The request patch should be "/SStats/reportName" where 'reportName'
+            // is one of the names added to the 'reports' hashmap.
             regpath = regpath.Remove(0, 8);
             if (regpath.Length == 0) regpath = "default.report";
             if (reports.ContainsKey(regpath))
@@ -265,6 +272,9 @@ namespace OpenSim.Region.UserStatistics
                 IStatsController rep = reports[regpath];
                 Hashtable repParams = new Hashtable();
 
+                if (request.ContainsKey("json"))
+                    jsonFormatOutput = true;
+
                 if (request.ContainsKey("requestvars"))
                     repParams["RequestVars"] = request["requestvars"];
                 else
@@ -284,13 +294,26 @@ namespace OpenSim.Region.UserStatistics
                 
                 concurrencyCounter++;
 
-                strOut = rep.RenderView(rep.ProcessModel(repParams));
+                if (jsonFormatOutput) 
+                {
+                    strOut = rep.RenderJson(rep.ProcessModel(repParams));
+                    contenttype = "text/json";
+                }
+                else 
+                {
+                    strOut = rep.RenderView(rep.ProcessModel(repParams));
+                }
 
                 if (regpath.EndsWith("js"))
                 {
                     contenttype = "text/javascript";
                 }
 
+                if (regpath.EndsWith("css"))
+                {
+                    contenttype = "text/css";
+                }
+
                 concurrencyCounter--;
                 
                 response_code = 200;

+ 1 - 1
bin/data/LICENSE-README-IMPORTANT.txt

@@ -2,4 +2,4 @@ Not all of the files in this directory are licensed under the BSD license. Some
 
 These files are:
 
-- avataranimations.xml (Derivative work of viewerart.ini, Creative Commons Attribution+Share-Alike v2.5 License)
+- avataranimations.xml (Derivative work of viewerart.ini, Creative Commons Attribution+Share-Alike v2.5 License)

+ 85 - 0
bin/data/sim.css

@@ -0,0 +1,85 @@
+body {
+ font-family: Veranda,Arial,Helvetica,sans-serif;
+ font-size: 12px;
+ background: #4A5F6D;
+ color: #EEEAD6;
+ padding: 0px;
+ margin: 0px;
+}
+.footer {
+ font-family: Veranda,Arial,Helvetica,sans-serif;
+ font-size: 10px;
+}
+td {
+ font-family: Veranda,Arial,Helvetica,sans-serif;
+ font-size: 12px;
+ padding: 4px;
+ margin: 4px;
+}
+blockquote {
+ font-family: Veranda,Arial,Helvetica,sans-serif;
+ font-style: italic;
+ font-size: 12px;
+}
+pre {
+ padding: 5px;
+ background-color: #8080B0;
+ color: #000000;
+ margin-left: 20px;
+ font-size: 11px;
+}
+:link {
+ color: #ffffff;
+}
+:visited {
+ color: #d0d0d0;
+}
+.SimSectionHeader {
+    font-size: 120%;
+}
+div.SimSectionContainer {
+    padding: 10px 0px 0px 20px;
+}
+/* SimStats ===================================== */
+#SimSimStats div {
+    margin-left: 20px;
+    background: #3A4F5D;
+}
+#SimSimStats table td {
+    text-align: right;
+    padding: 0px 0px 0px 5px;
+    margin: 0px 0px 0px 0px;
+}
+/* Region Stats ===================================== */
+#SimRegionStats div {
+    margin-left: 20px;
+    background: #3A4F5D;
+}
+#SimRegionStats table {
+    border: 1px;
+    border-style: solid; 
+}
+#SimRegionStats table td {
+    text-align: right;
+    padding: 0px 0px 0px 5px;
+    margin: 0px 0px 0px 0px;
+}
+/* Session Stats ===================================== */
+#SimSessionStats div {
+    margin-left: 20px;
+    background: #3A4F5D;
+}
+#SimSessionStats table td {
+    text-align: right;
+    padding: 0px 0px 0px 5px;
+    margin: 0px 0px 0px 0px;
+}
+/* LogFile ===================================== */
+#SimLogFile div {
+    margin-left: 20px;
+}
+#SimLogFile table td {
+    text-align: right;
+    padding: 0px 0px 0px 5px;
+    margin: 0px 0px 0px 0px;
+}

+ 291 - 0
bin/data/sim.html

@@ -0,0 +1,291 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Simulator statistics</title>
+<link rel="stylesheet" href="sim.css" type="text/css"/>
+<!-- <script type="text/javascript" src="jquery.js"></script> -->
+<!-- <script type="text/javascript" src="https://code.jquery.com/jquery-1.9.0.min.js"></script> -->
+<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
+<!-- <script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/libs/jQuery/jquery-1.9.0.min.js"></script> -->
+<noscript>
+<p color="red">
+Your browser does not support Javascript. This won't work for you.
+</p>
+</noscript>
+<script type="text/javascript">
+$(document).ready(function() {
+    // Major divisions in the content accordioning
+    $('.SimSection').show('slow');
+    $('.SimSectionHeader').click(function() {
+        $(this).next().slideToggle('slow');
+        return false;
+    });
+
+    // Start the timed functions
+    TimerDataStuff();
+});
+
+// One of the sections is viewer statistics. Poll for the data.
+var statTimerHandle;
+var graphFPS;
+var lastFPS = 10;
+var xxThru = 0;
+function TimerDataStuff() {
+    statTimerHandle = setInterval('TimerStatDisplay()', 5000);
+}
+
+// called by timer to fetch and display statistic information
+var doingStatDisplay = false;
+function TimerStatDisplay() {
+    if (doingStatDisplay) return;
+    doingStatDisplay = true;
+    if ($('#SimSimStats').is(':visible')) {
+        DisplaySimStats();
+    }
+    if ($('#SimRegionStats').is(':visible')) {
+        DisplayPerRegionStats();
+    }
+    if ($('#SimSessionStats').is(':visible')) {
+        DisplaySessionStats();
+    }
+    if ($('#SimLogFile').is(':visible')) {
+        DisplayLogFile();
+    }
+    doingStatDisplay = false;
+}
+
+var simName = "127.0.0.1";
+var simPort = "9000";
+function DisplaySimStats() {
+    var statURL = "http://" + simName + ":" + simPort + "/SStats/?json=1";
+    $.ajax({
+        type: "GET",
+        url: statURL,
+        dataType: 'json',
+        timeout: 1000,
+        success: function(data, status) {
+            if (status == 'success') {
+                DisplaySimStatDetails(data);
+            }
+        },
+        error: function(xmlHTTPRequest, errorType) {
+            // DebugLog('Failed fetch');
+        }
+    });
+}
+
+function DisplayPerRegionStats() {
+    var statURL = "http://" + simName + ":" + simPort + "/SStats/simstatsajax.html?json=1";
+    $.ajax({
+        type: "GET",
+        url: statURL,
+        dataType: 'json',
+        timeout: 1000,
+        success: function(data, status) {
+            if (status == 'success') {
+                DisplayRegionStatDetails(data);
+            }
+        },
+        error: function(xmlHTTPRequest, errorType) {
+            // DebugLog('Failed fetch');
+        }
+    });
+};
+
+function DisplayLogFile() {
+    var statURL = "http://" + simName + ":" + simPort + "/SStats/activelogajax.html?json=1";
+    $.ajax({
+        type: "GET",
+        url: statURL,
+        dataType: 'json',
+        timeout: 1000,
+        success: function(data, status) {
+            if (status == 'success') {
+                DisplayLogFileDetails(data);
+            }
+        },
+        error: function(xmlHTTPRequest, errorType) {
+            // DebugLog('Failed fetch');
+        }
+    });
+};
+
+function DisplaySessionStats() {
+    var statURL = "http://" + simName + ":" + simPort + "/SStats/activeconnectionsajax.html?json=1";
+    $.ajax({
+        type: "GET",
+        url: statURL,
+        dataType: 'json',
+        timeout: 1000,
+        success: function(data, status) {
+            if (status == 'success') {
+                DisplaySessionStatsDetails(data);
+            }
+        },
+        error: function(xmlHTTPRequest, errorType) {
+            // DebugLog('Failed fetch');
+        }
+    });
+};
+
+function DisplaySimStatDetails(data) {
+    var simInfo = new StringBuffer();
+    simInfo.append('<table id="RegionStatsTable">');
+    simInfo.append('<tr>');
+    simInfo.append('<th>Total Users</th>');
+    simInfo.append('<th>Total Sessions</th>');
+    simInfo.append('<th>Avg client FPS</th>');
+    simInfo.append('<th>Avg client Mem</th>');
+    simInfo.append('<th>Avg ping time</th>');
+    simInfo.append('<th>KB out</th>');
+    simInfo.append('<th>KB in</th>');
+    simInfo.append('</tr>');
+    simInfo.append('<tr>');
+    simInfo.append('<td>' + data.totalUsers + '</td>');
+    simInfo.append('<td>' + data.totalSessions + '</td>');
+    simInfo.append('<td>' + data.averageClientFPS + '</td>');
+    simInfo.append('<td>' + data.averageClientMem + '</td>');
+    simInfo.append('<td>' + data.averagePingTime + '</td>');
+    simInfo.append('<td>' + data.totalKBOut + '</td>');
+    simInfo.append('<td>' + data.totalKBIn + '</td>');
+    simInfo.append('</tr>');
+    simInfo.append('</table>');
+    $('#SimSimStats').empty();
+    $('#SimSimStats').append(simInfo.toString());
+}
+
+function DisplayRegionStatDetails(data) {
+    var regionInfo = new StringBuffer();
+    regionInfo.append('<table id="RegionStatsTable">');
+    regionInfo.append('<tr>');
+    regionInfo.append('<th>Region</th>');
+    regionInfo.append('<th>Agents</th>');
+    regionInfo.append('<th>Child</th>');
+    regionInfo.append('<th>FPS</th>');
+    regionInfo.append('<th>Frame Time</th>');
+    regionInfo.append('<th>Phys Time</th>');
+    regionInfo.append('<th>Prims</th>');
+    regionInfo.append('</tr>');
+    for (region in data) {
+        regionInfo.append('<tr>');
+        regionInfo.append('<td>' + data[region].region + '</td>');
+        regionInfo.append('<td>' + data[region].rootAgents + '</td>');
+        regionInfo.append('<td>' + data[region].childAgents + '</td>');
+        regionInfo.append('<td>' + data[region].simFPS + '</td>');
+        regionInfo.append('<td>' + data[region].totalFrameTime + '</td>');
+        regionInfo.append('<td>' + data[region].physicsFrameTime + '</td>');
+        regionInfo.append('<td>' + data[region].totalPrims + '</td>');
+        regionInfo.append('</tr>');
+    }
+    regionInfo.append('</table>');
+    $('#SimRegionStats').empty();
+    $('#SimRegionStats').append(regionInfo.toString());
+}
+
+function DisplayLogFileDetails(data) {
+    var logInfo = new StringBuffer();
+    var logPattern = /^(.+),\d\d\d .* \[(.+)\]: (.+)$/;
+    for (logLine in data['logLines']) {
+        logInfo.append('<div>');
+        var logPieces = logPattern.exec(data['logLines'][logLine]);
+        if (logPieces) {
+            logInfo.append(logPieces[1] + ' [' + logPieces[2]
+                    + '] ' + logPieces[3]);
+        }
+        else {
+            logInfo.append(data['logLines'][logLine]);
+        }
+
+        logInfo.append('</div>');
+    }
+    $('#SimLogFile').empty();
+    $('#SimLogFile').append(logInfo.toString());
+}
+
+function DisplaySessionStatsDetails(data) {
+    var userInfo = new StringBuffer();
+    userInfo.append('<table>');
+    userInfo.append('<tr>');
+    userInfo.append('<th>region</th>');
+    userInfo.append('<th>user</th>');
+    userInfo.append('<th></th>');
+    userInfo.append('<th>position</th>');
+    userInfo.append('</tr>');
+    for (region in data) {
+        for (user in data[region]) {
+            if (user != 'queues') {
+                userInfo.append('<tr>');
+                userInfo.append('<td>' + region + '</td>');
+                userInfo.append('<td>' + data[region][user].Name + '</td>');
+                if (data[region][user].isRoot == 'true') {
+                    userInfo.append('<td>root</td>');
+                }
+                else {
+                    userInfo.append('<td>child</td>');
+                }
+                userInfo.append('<td>' + data[region][user].position + '</td>');
+                userInfo.append('</tr>');
+            }
+        }
+    }
+    userInfo.append('</table>');
+    $('#SimSessionStats').empty();
+    $('#SimSessionStats').append(userInfo.toString());
+}
+
+function DebugLog(msg) {
+    $("#DEBUG").append('<div>' + msg + '</div>');
+    $("#DEBUG").show();
+}
+
+function StringBuffer() {
+    this.__strings__ = new Array;
+}
+StringBuffer.prototype.append = function(str) {
+    this.__strings__.push(str);
+}
+StringBuffer.prototype.toString = function() {
+    return this.__strings__.join("");
+}
+
+</script>
+</head>
+<body id="SimBody">
+<div id="SimHeader"></div>
+<div id="SimContent">
+
+<!-- ============================================== -->
+<div class="SimSectionContainer">
+<a class="SimSectionHeader" href="#">Simulator Stats</a>
+<div id="SimSimStats" class="SimSection">
+</div>  <!-- SimSimStats -->
+</div>  <!-- SimSectionContainer -->
+
+<!-- ============================================== -->
+<div class="SimSectionContainer">
+<a class="SimSectionHeader" href="#">Region Stats</a>
+<div id="SimRegionStats" class="SimSection">
+</div>  <!-- SimRegionStats -->
+</div>  <!-- SimSectionContainer -->
+
+<!-- ============================================== -->
+<div class="SimSectionContainer">
+<a class="SimSectionHeader" href="#">Sessions</a>
+<div id="SimSessionStats" class="SimSection">
+</div>  <!-- SimSessionStats -->
+</div>  <!-- SimSectionContainer -->
+
+<!-- ============================================== -->
+<div class="SimSectionContainer">
+<a class="SimSectionHeader" href="#">Log File</a>
+<div id="SimLogFile" class="SimSection">
+</div>  <!-- SimLogFile -->
+</div>  <!-- SimSectionContainer -->
+
+<!-- ============================================== -->
+</div>  <!-- SimContent -->
+<div id="DEBUG"></div>
+<div id="SimFooter"></div>
+</body>
+</html>