From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001
From: David Walter Seikel
Date: Thu, 3 Nov 2016 21:44:39 +1000
Subject: Initial update to OpenSim 0.8.2.1 source code.
---
OpenSim/Framework/Monitoring/StatsManager.cs | 403 ++++++++++++++++++++++-----
1 file changed, 328 insertions(+), 75 deletions(-)
(limited to 'OpenSim/Framework/Monitoring/StatsManager.cs')
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index 0762b01..3136ee8 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -26,15 +26,20 @@
*/
using System;
+using System.Collections;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
+using OpenSim.Framework;
+using OpenMetaverse.StructuredData;
+
namespace OpenSim.Framework.Monitoring
{
///
- /// Singleton used to provide access to statistics reporters
+ /// Static class used to register/deregister/fetch statistics
///
- public class StatsManager
+ public static class StatsManager
{
// Subcommand used to list other stats.
public const string AllSubCommand = "all";
@@ -51,31 +56,43 @@ namespace OpenSim.Framework.Monitoring
///
/// Do not add or remove directly from this dictionary.
///
- public static Dictionary>> RegisteredStats
- = new Dictionary>>();
+ public static SortedDictionary>> RegisteredStats
+ = new SortedDictionary>>();
- private static AssetStatsCollector assetStats;
- private static UserStatsCollector userStats;
- private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
+// private static AssetStatsCollector assetStats;
+// private static UserStatsCollector userStats;
+// private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
- public static AssetStatsCollector AssetStats { get { return assetStats; } }
- public static UserStatsCollector UserStats { get { return userStats; } }
- public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
+// public static AssetStatsCollector AssetStats { get { return assetStats; } }
+// public static UserStatsCollector UserStats { get { return userStats; } }
+ public static SimExtraStatsCollector SimExtraStats { get; set; }
public static void RegisterConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"General",
false,
- "show stats",
- "show stats [list|all|]",
+ "stats show",
+ "stats show [list|all|([.])+",
"Show statistical information for this server",
"If no final argument is specified then legacy statistics information is currently shown.\n"
- + "If list is specified then statistic categories are shown.\n"
- + "If all is specified then all registered statistics are shown.\n"
- + "If a category name is specified then only statistics from that category are shown.\n"
+ + "'list' argument will show statistic categories.\n"
+ + "'all' will show all statistics.\n"
+ + "A name will show statistics from that category.\n"
+ + "A . name will show statistics from that category in that container.\n"
+ + "More than one name can be given separated by spaces.\n"
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
HandleShowStatsCommand);
+
+ console.Commands.AddCommand(
+ "General",
+ false,
+ "show stats",
+ "show stats [list|all|([.])+",
+ "Alias for 'stats show' command",
+ HandleShowStatsCommand);
+
+ StatsLogger.RegisterConsoleCommands(console);
}
public static void HandleShowStatsCommand(string module, string[] cmd)
@@ -84,105 +101,286 @@ namespace OpenSim.Framework.Monitoring
if (cmd.Length > 2)
{
- var categoryName = cmd[2];
-
- if (categoryName == AllSubCommand)
+ foreach (string name in cmd.Skip(2))
{
- foreach (var category in RegisteredStats.Values)
+ string[] components = name.Split('.');
+
+ string categoryName = components[0];
+ string containerName = components.Length > 1 ? components[1] : null;
+ string statName = components.Length > 2 ? components[2] : null;
+
+ if (categoryName == AllSubCommand)
{
- OutputCategoryStatsToConsole(con, category);
+ OutputAllStatsToConsole(con);
}
- }
- else if (categoryName == ListSubCommand)
- {
- con.Output("Statistic categories available are:");
- foreach (string category in RegisteredStats.Keys)
- con.OutputFormat(" {0}", category);
- }
- else
- {
- Dictionary> category;
- if (!RegisteredStats.TryGetValue(categoryName, out category))
+ else if (categoryName == ListSubCommand)
{
- con.OutputFormat("No such category as {0}", categoryName);
+ con.Output("Statistic categories available are:");
+ foreach (string category in RegisteredStats.Keys)
+ con.OutputFormat(" {0}", category);
}
else
{
- OutputCategoryStatsToConsole(con, category);
+ SortedDictionary> category;
+ if (!RegisteredStats.TryGetValue(categoryName, out category))
+ {
+ con.OutputFormat("No such category as {0}", categoryName);
+ }
+ else
+ {
+ if (String.IsNullOrEmpty(containerName))
+ {
+ OutputCategoryStatsToConsole(con, category);
+ }
+ else
+ {
+ SortedDictionary container;
+ if (category.TryGetValue(containerName, out container))
+ {
+ if (String.IsNullOrEmpty(statName))
+ {
+ OutputContainerStatsToConsole(con, container);
+ }
+ else
+ {
+ Stat stat;
+ if (container.TryGetValue(statName, out stat))
+ {
+ OutputStatToConsole(con, stat);
+ }
+ else
+ {
+ con.OutputFormat(
+ "No such stat {0} in {1}.{2}", statName, categoryName, containerName);
+ }
+ }
+ }
+ else
+ {
+ con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
+ }
+ }
+ }
}
}
}
else
{
// Legacy
- con.Output(SimExtraStats.Report());
+ if (SimExtraStats != null)
+ con.Output(SimExtraStats.Report());
+ else
+ OutputAllStatsToConsole(con);
}
}
- private static void OutputCategoryStatsToConsole(
- ICommandConsole con, Dictionary> category)
+ public static List GetAllStatsReports()
+ {
+ List reports = new List();
+
+ foreach (var category in RegisteredStats.Values)
+ reports.AddRange(GetCategoryStatsReports(category));
+
+ return reports;
+ }
+
+ private static void OutputAllStatsToConsole(ICommandConsole con)
{
+ foreach (string report in GetAllStatsReports())
+ con.Output(report);
+ }
+
+ private static List GetCategoryStatsReports(
+ SortedDictionary> category)
+ {
+ List reports = new List();
+
foreach (var container in category.Values)
+ reports.AddRange(GetContainerStatsReports(container));
+
+ return reports;
+ }
+
+ private static void OutputCategoryStatsToConsole(
+ ICommandConsole con, SortedDictionary> category)
+ {
+ foreach (string report in GetCategoryStatsReports(category))
+ con.Output(report);
+ }
+
+ private static List GetContainerStatsReports(SortedDictionary container)
+ {
+ List reports = new List();
+
+ foreach (Stat stat in container.Values)
+ reports.Add(stat.ToConsoleString());
+
+ return reports;
+ }
+
+ private static void OutputContainerStatsToConsole(
+ ICommandConsole con, SortedDictionary container)
+ {
+ foreach (string report in GetContainerStatsReports(container))
+ con.Output(report);
+ }
+
+ private static void OutputStatToConsole(ICommandConsole con, Stat stat)
+ {
+ con.Output(stat.ToConsoleString());
+ }
+
+ // Creates an OSDMap of the format:
+ // { categoryName: {
+ // containerName: {
+ // statName: {
+ // "Name": name,
+ // "ShortName": shortName,
+ // ...
+ // },
+ // statName: {
+ // "Name": name,
+ // "ShortName": shortName,
+ // ...
+ // },
+ // ...
+ // },
+ // containerName: {
+ // ...
+ // },
+ // ...
+ // },
+ // categoryName: {
+ // ...
+ // },
+ // ...
+ // }
+ // The passed in parameters will filter the categories, containers and stats returned. If any of the
+ // parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned.
+ // Case matters.
+ public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName)
+ {
+ OSDMap map = new OSDMap();
+
+ foreach (string catName in RegisteredStats.Keys)
{
- foreach (Stat stat in container.Values)
+ // Do this category if null spec, "all" subcommand or category name matches passed parameter.
+ // Skip category if none of the above.
+ if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName))
+ continue;
+
+ OSDMap contMap = new OSDMap();
+ foreach (string contName in RegisteredStats[catName].Keys)
{
- con.Output(stat.ToConsoleString());
+ if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName))
+ continue;
+
+ OSDMap statMap = new OSDMap();
+
+ SortedDictionary theStats = RegisteredStats[catName][contName];
+ foreach (string statName in theStats.Keys)
+ {
+ if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName))
+ continue;
+
+ statMap.Add(statName, theStats[statName].ToOSDMap());
+ }
+
+ contMap.Add(contName, statMap);
}
+ map.Add(catName, contMap);
}
+
+ return map;
}
- ///
- /// Start collecting statistics related to assets.
- /// Should only be called once.
- ///
- public static AssetStatsCollector StartCollectingAssetStats()
+ public static Hashtable HandleStatsRequest(Hashtable request)
{
- assetStats = new AssetStatsCollector();
+ Hashtable responsedata = new Hashtable();
+// string regpath = request["uri"].ToString();
+ int response_code = 200;
+ string contenttype = "text/json";
- return assetStats;
- }
+ string pCategoryName = StatsManager.AllSubCommand;
+ string pContainerName = StatsManager.AllSubCommand;
+ string pStatName = StatsManager.AllSubCommand;
- ///
- /// Start collecting statistics related to users.
- /// Should only be called once.
- ///
- public static UserStatsCollector StartCollectingUserStats()
- {
- userStats = new UserStatsCollector();
+ if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString();
+ if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString();
+ if (request.ContainsKey("stat")) pStatName = request["stat"].ToString();
- return userStats;
+ string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString();
+
+ // If requestor wants it as a callback function, build response as a function rather than just the JSON string.
+ if (request.ContainsKey("callback"))
+ {
+ strOut = request["callback"].ToString() + "(" + strOut + ");";
+ }
+
+ // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}",
+ // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut);
+
+ responsedata["int_response_code"] = response_code;
+ responsedata["content_type"] = contenttype;
+ responsedata["keepalive"] = false;
+ responsedata["str_response_string"] = strOut;
+ responsedata["access_control_allow_origin"] = "*";
+
+ return responsedata;
}
+// ///
+// /// Start collecting statistics related to assets.
+// /// Should only be called once.
+// ///
+// public static AssetStatsCollector StartCollectingAssetStats()
+// {
+// assetStats = new AssetStatsCollector();
+//
+// return assetStats;
+// }
+//
+// ///
+// /// Start collecting statistics related to users.
+// /// Should only be called once.
+// ///
+// public static UserStatsCollector StartCollectingUserStats()
+// {
+// userStats = new UserStatsCollector();
+//
+// return userStats;
+// }
+
///
- /// Registers a statistic.
+ /// Register a statistic.
///
///
///
public static bool RegisterStat(Stat stat)
{
- Dictionary> category = null, newCategory;
- Dictionary container = null, newContainer;
+ SortedDictionary> category = null, newCategory;
+ SortedDictionary container = null, newContainer;
lock (RegisteredStats)
{
// Stat name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM.
- if (TryGetStat(stat, out category, out container))
+ if (TryGetStatParents(stat, out category, out container))
return false;
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
// This means that we don't need to lock or copy them on iteration, which will be a much more
// common operation after startup.
if (container != null)
- newContainer = new Dictionary(container);
+ newContainer = new SortedDictionary(container);
else
- newContainer = new Dictionary();
+ newContainer = new SortedDictionary();
if (category != null)
- newCategory = new Dictionary>(category);
+ newCategory = new SortedDictionary>(category);
else
- newCategory = new Dictionary>();
+ newCategory = new SortedDictionary>();
newContainer[stat.ShortName] = stat;
newCategory[stat.Container] = newContainer;
@@ -196,21 +394,21 @@ namespace OpenSim.Framework.Monitoring
/// Deregister a statistic
/// >
///
- ///
public static bool DeregisterStat(Stat stat)
{
- Dictionary> category = null, newCategory;
- Dictionary container = null, newContainer;
+ SortedDictionary> category = null, newCategory;
+ SortedDictionary container = null, newContainer;
lock (RegisteredStats)
{
- if (!TryGetStat(stat, out category, out container))
+ if (!TryGetStatParents(stat, out category, out container))
return false;
- newContainer = new Dictionary(container);
+ newContainer = new SortedDictionary(container);
newContainer.Remove(stat.ShortName);
- newCategory = new Dictionary>(category);
+ newCategory = new SortedDictionary>(category);
newCategory.Remove(stat.Container);
newCategory[stat.Container] = newContainer;
@@ -220,15 +418,70 @@ namespace OpenSim.Framework.Monitoring
}
}
- public static bool TryGetStats(string category, out Dictionary> stats)
+ public static bool TryGetStat(string category, string container, string statShortName, out Stat stat)
{
- return RegisteredStats.TryGetValue(category, out stats);
+ stat = null;
+ SortedDictionary> categoryStats;
+
+ lock (RegisteredStats)
+ {
+ if (!TryGetStatsForCategory(category, out categoryStats))
+ return false;
+
+ SortedDictionary containerStats;
+
+ if (!categoryStats.TryGetValue(container, out containerStats))
+ return false;
+
+ return containerStats.TryGetValue(statShortName, out stat);
+ }
+ }
+
+ public static bool TryGetStatsForCategory(
+ string category, out SortedDictionary> stats)
+ {
+ lock (RegisteredStats)
+ return RegisteredStats.TryGetValue(category, out stats);
+ }
+
+ ///
+ /// Get the same stat for each container in a given category.
+ ///
+ ///
+ /// The stats if there were any to fetch. Otherwise null.
+ ///
+ ///
+ ///
+ public static List GetStatsFromEachContainer(string category, string statShortName)
+ {
+ SortedDictionary> categoryStats;
+
+ lock (RegisteredStats)
+ {
+ if (!RegisteredStats.TryGetValue(category, out categoryStats))
+ return null;
+
+ List stats = null;
+
+ foreach (SortedDictionary containerStats in categoryStats.Values)
+ {
+ if (containerStats.ContainsKey(statShortName))
+ {
+ if (stats == null)
+ stats = new List();
+
+ stats.Add(containerStats[statShortName]);
+ }
+ }
+
+ return stats;
+ }
}
- public static bool TryGetStat(
+ public static bool TryGetStatParents(
Stat stat,
- out Dictionary> category,
- out Dictionary container)
+ out SortedDictionary> category,
+ out SortedDictionary container)
{
category = null;
container = null;
@@ -252,9 +505,9 @@ namespace OpenSim.Framework.Monitoring
{
lock (RegisteredStats)
{
- foreach (Dictionary> category in RegisteredStats.Values)
+ foreach (SortedDictionary> category in RegisteredStats.Values)
{
- foreach (Dictionary container in category.Values)
+ foreach (SortedDictionary container in category.Values)
{
foreach (Stat stat in container.Values)
{
--
cgit v1.1