aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Monitoring/StatsManager.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs193
1 files changed, 174 insertions, 19 deletions
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index b5dc24f..a67c5f8 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using OpenSim.Framework.Console;
30 31
31namespace OpenSim.Framework.Monitoring 32namespace OpenSim.Framework.Monitoring
32{ 33{
@@ -35,13 +36,23 @@ namespace OpenSim.Framework.Monitoring
35 /// </summary> 36 /// </summary>
36 public class StatsManager 37 public class StatsManager
37 { 38 {
39 // Subcommand used to list other stats.
40 public const string AllSubCommand = "all";
41
42 // Subcommand used to list other stats.
43 public const string ListSubCommand = "list";
44
45 // All subcommands
46 public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
47
38 /// <summary> 48 /// <summary>
39 /// Registered stats. 49 /// Registered stats categorized by category/container/shortname
40 /// </summary> 50 /// </summary>
41 /// <remarks> 51 /// <remarks>
42 /// Do not add or remove from this dictionary. 52 /// Do not add or remove directly from this dictionary.
43 /// </remarks> 53 /// </remarks>
44 public static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>(); 54 public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
55 = new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
45 56
46 private static AssetStatsCollector assetStats; 57 private static AssetStatsCollector assetStats;
47 private static UserStatsCollector userStats; 58 private static UserStatsCollector userStats;
@@ -51,6 +62,76 @@ namespace OpenSim.Framework.Monitoring
51 public static UserStatsCollector UserStats { get { return userStats; } } 62 public static UserStatsCollector UserStats { get { return userStats; } }
52 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } 63 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
53 64
65 public static void RegisterConsoleCommands(CommandConsole console)
66 {
67 console.Commands.AddCommand(
68 "General",
69 false,
70 "show stats",
71 "show stats [list|all|<category>]",
72 "Show statistical information for this server",
73 "If no final argument is specified then legacy statistics information is currently shown.\n"
74 + "If list is specified then statistic categories are shown.\n"
75 + "If all is specified then all registered statistics are shown.\n"
76 + "If a category name is specified then only statistics from that category are shown.\n"
77 + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
78 HandleShowStatsCommand);
79 }
80
81 public static void HandleShowStatsCommand(string module, string[] cmd)
82 {
83 ICommandConsole con = MainConsole.Instance;
84
85 if (cmd.Length > 2)
86 {
87 var categoryName = cmd[2];
88
89 if (categoryName == AllSubCommand)
90 {
91 foreach (var category in RegisteredStats.Values)
92 {
93 OutputCategoryStatsToConsole(con, category);
94 }
95 }
96 else if (categoryName == ListSubCommand)
97 {
98 con.Output("Statistic categories available are:");
99 foreach (string category in RegisteredStats.Keys)
100 con.OutputFormat(" {0}", category);
101 }
102 else
103 {
104 Dictionary<string, Dictionary<string, Stat>> category;
105 if (!RegisteredStats.TryGetValue(categoryName, out category))
106 {
107 con.OutputFormat("No such category as {0}", categoryName);
108 }
109 else
110 {
111 OutputCategoryStatsToConsole(con, category);
112 }
113 }
114 }
115 else
116 {
117 // Legacy
118 con.Output(SimExtraStats.Report());
119 }
120 }
121
122 private static void OutputCategoryStatsToConsole(
123 ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
124 {
125 foreach (var container in category.Values)
126 {
127 foreach (Stat stat in container.Values)
128 {
129 con.OutputFormat(
130 "{0}.{1}.{2} : {3}{4}", stat.Category, stat.Container, stat.ShortName, stat.Value, stat.UnitName);
131 }
132 }
133 }
134
54 /// <summary> 135 /// <summary>
55 /// Start collecting statistics related to assets. 136 /// Start collecting statistics related to assets.
56 /// Should only be called once. 137 /// Should only be called once.
@@ -73,43 +154,100 @@ namespace OpenSim.Framework.Monitoring
73 return userStats; 154 return userStats;
74 } 155 }
75 156
157 /// <summary>
158 /// Registers a statistic.
159 /// </summary>
160 /// <param name='stat'></param>
161 /// <returns></returns>
76 public static bool RegisterStat(Stat stat) 162 public static bool RegisterStat(Stat stat)
77 { 163 {
164 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
165 Dictionary<string, Stat> container = null, newContainer;
166
78 lock (RegisteredStats) 167 lock (RegisteredStats)
79 { 168 {
80 if (RegisteredStats.ContainsKey(stat.UniqueName)) 169 // Stat name is not unique across category/container/shortname key.
81 { 170 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
82 // XXX: For now just return false. This is to avoid problems in regression tests where all tests 171 // in a class are run in the same instance of the VM.
83 // in a class are run in the same instance of the VM. 172 if (TryGetStat(stat, out category, out container))
84 return false; 173 return false;
85 174
86// throw new Exception( 175 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
87// "StatsManager already contains stat with ShortName {0} in Category {1}", stat.ShortName, stat.Category); 176 // This means that we don't need to lock or copy them on iteration, which will be a much more
88 } 177 // common operation after startup.
178 if (container != null)
179 newContainer = new Dictionary<string, Stat>(container);
180 else
181 newContainer = new Dictionary<string, Stat>();
182
183 if (category != null)
184 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
185 else
186 newCategory = new Dictionary<string, Dictionary<string, Stat>>();
89 187
90 // We take a replace-on-write approach here so that we don't need to generate a new Dictionary 188 newContainer[stat.ShortName] = stat;
91 Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats); 189 newCategory[stat.Container] = newContainer;
92 newRegisteredStats[stat.UniqueName] = stat; 190 RegisteredStats[stat.Category] = newCategory;
93 RegisteredStats = newRegisteredStats;
94 } 191 }
95 192
96 return true; 193 return true;
97 } 194 }
98 195
196 /// <summary>
197 /// Deregister a statistic
198 /// </summary>>
199 /// <param name='stat'></param>
200 /// <returns></returns
99 public static bool DeregisterStat(Stat stat) 201 public static bool DeregisterStat(Stat stat)
100 { 202 {
203 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
204 Dictionary<string, Stat> container = null, newContainer;
205
101 lock (RegisteredStats) 206 lock (RegisteredStats)
102 { 207 {
103 if (!RegisteredStats.ContainsKey(stat.UniqueName)) 208 if (!TryGetStat(stat, out category, out container))
104 return false; 209 return false;
105 210
106 Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats); 211 newContainer = new Dictionary<string, Stat>(container);
107 newRegisteredStats.Remove(stat.UniqueName); 212 newContainer.Remove(stat.UniqueName);
108 RegisteredStats = newRegisteredStats; 213
214 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
215 newCategory.Remove(stat.Container);
216
217 newCategory[stat.Container] = newContainer;
218 RegisteredStats[stat.Category] = newCategory;
109 219
110 return true; 220 return true;
111 } 221 }
112 } 222 }
223
224 public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
225 {
226 return RegisteredStats.TryGetValue(category, out stats);
227 }
228
229 public static bool TryGetStat(
230 Stat stat,
231 out Dictionary<string, Dictionary<string, Stat>> category,
232 out Dictionary<string, Stat> container)
233 {
234 category = null;
235 container = null;
236
237 lock (RegisteredStats)
238 {
239 if (RegisteredStats.TryGetValue(stat.Category, out category))
240 {
241 if (category.TryGetValue(stat.Container, out container))
242 {
243 if (container.ContainsKey(stat.ShortName))
244 return true;
245 }
246 }
247 }
248
249 return false;
250 }
113 } 251 }
114 252
115 /// <summary> 253 /// <summary>
@@ -157,9 +295,26 @@ namespace OpenSim.Framework.Monitoring
157 295
158 public virtual double Value { get; set; } 296 public virtual double Value { get; set; }
159 297
298 /// <summary>
299 /// Constructor
300 /// </summary>
301 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
302 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
303 /// <param name='unitName'>
304 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
305 /// e.g. " frames"
306 /// </param>
307 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
308 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
309 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
310 /// <param name='description'>Description of stat</param>
160 public Stat( 311 public Stat(
161 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description) 312 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
162 { 313 {
314 if (StatsManager.SubCommands.Contains(category))
315 throw new Exception(
316 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
317
163 ShortName = shortName; 318 ShortName = shortName;
164 Name = name; 319 Name = name;
165 UnitName = unitName; 320 UnitName = unitName;
@@ -203,7 +358,7 @@ namespace OpenSim.Framework.Monitoring
203 358
204 public PercentageStat( 359 public PercentageStat(
205 string shortName, string name, string category, string container, StatVerbosity verbosity, string description) 360 string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
206 : base(shortName, name, " %", category, container, verbosity, description) 361 : base(shortName, name, "%", category, container, verbosity, description)
207 { 362 {
208 } 363 }
209 } 364 }