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.
This commit is contained in:
Robert Adams
2013-01-24 10:44:57 -08:00
parent d5b950633d
commit 427ab219b8
13 changed files with 660 additions and 14 deletions

View File

@@ -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(),

View File

@@ -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"];

View File

@@ -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;
}
}

View File

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

View File

@@ -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
}
}

View File

@@ -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)
{
StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/prototype.js", FileMode.Open));
prototypejs = fs.ReadToEnd();
fs.Close();
fs.Dispose();
}
pResult["js"] = prototypejs;
pResult["js"] = jsFileName;
return pResult;
}
public string RenderView(Hashtable pModelResult)
{
return pModelResult["js"].ToString();
string fileName = (string)pModelResult["js"];
using (StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/" + fileName, FileMode.Open)))
{
prototypejs = fs.ReadToEnd();
fs.Close();
}
return prototypejs;
}
public string RenderJson(Hashtable pModelResult)
{
return "{}";
}
}

View File

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

View File

@@ -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
}
}

View File

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

View File

@@ -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;