aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Monitoring/StatsManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Monitoring/StatsManager.cs')
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs239
1 files changed, 239 insertions, 0 deletions
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index d78fa6a..0762b01 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -25,6 +25,10 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
29using System.Collections.Generic;
30using System.Text;
31
28namespace OpenSim.Framework.Monitoring 32namespace OpenSim.Framework.Monitoring
29{ 33{
30 /// <summary> 34 /// <summary>
@@ -32,6 +36,24 @@ namespace OpenSim.Framework.Monitoring
32 /// </summary> 36 /// </summary>
33 public class StatsManager 37 public class StatsManager
34 { 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
48 /// <summary>
49 /// Registered stats categorized by category/container/shortname
50 /// </summary>
51 /// <remarks>
52 /// Do not add or remove directly from this dictionary.
53 /// </remarks>
54 public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
55 = new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
56
35 private static AssetStatsCollector assetStats; 57 private static AssetStatsCollector assetStats;
36 private static UserStatsCollector userStats; 58 private static UserStatsCollector userStats;
37 private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); 59 private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
@@ -40,6 +62,75 @@ namespace OpenSim.Framework.Monitoring
40 public static UserStatsCollector UserStats { get { return userStats; } } 62 public static UserStatsCollector UserStats { get { return userStats; } }
41 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } 63 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
42 64
65 public static void RegisterConsoleCommands(ICommandConsole 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.Output(stat.ToConsoleString());
130 }
131 }
132 }
133
43 /// <summary> 134 /// <summary>
44 /// Start collecting statistics related to assets. 135 /// Start collecting statistics related to assets.
45 /// Should only be called once. 136 /// Should only be called once.
@@ -61,5 +152,153 @@ namespace OpenSim.Framework.Monitoring
61 152
62 return userStats; 153 return userStats;
63 } 154 }
155
156 /// <summary>
157 /// Registers a statistic.
158 /// </summary>
159 /// <param name='stat'></param>
160 /// <returns></returns>
161 public static bool RegisterStat(Stat stat)
162 {
163 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
164 Dictionary<string, Stat> container = null, newContainer;
165
166 lock (RegisteredStats)
167 {
168 // Stat name is not unique across category/container/shortname key.
169 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
170 // in a class are run in the same instance of the VM.
171 if (TryGetStat(stat, out category, out container))
172 return false;
173
174 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
175 // This means that we don't need to lock or copy them on iteration, which will be a much more
176 // common operation after startup.
177 if (container != null)
178 newContainer = new Dictionary<string, Stat>(container);
179 else
180 newContainer = new Dictionary<string, Stat>();
181
182 if (category != null)
183 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
184 else
185 newCategory = new Dictionary<string, Dictionary<string, Stat>>();
186
187 newContainer[stat.ShortName] = stat;
188 newCategory[stat.Container] = newContainer;
189 RegisteredStats[stat.Category] = newCategory;
190 }
191
192 return true;
193 }
194
195 /// <summary>
196 /// Deregister a statistic
197 /// </summary>>
198 /// <param name='stat'></param>
199 /// <returns></returns
200 public static bool DeregisterStat(Stat stat)
201 {
202 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
203 Dictionary<string, Stat> container = null, newContainer;
204
205 lock (RegisteredStats)
206 {
207 if (!TryGetStat(stat, out category, out container))
208 return false;
209
210 newContainer = new Dictionary<string, Stat>(container);
211 newContainer.Remove(stat.ShortName);
212
213 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
214 newCategory.Remove(stat.Container);
215
216 newCategory[stat.Container] = newContainer;
217 RegisteredStats[stat.Category] = newCategory;
218
219 return true;
220 }
221 }
222
223 public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
224 {
225 return RegisteredStats.TryGetValue(category, out stats);
226 }
227
228 public static bool TryGetStat(
229 Stat stat,
230 out Dictionary<string, Dictionary<string, Stat>> category,
231 out Dictionary<string, Stat> container)
232 {
233 category = null;
234 container = null;
235
236 lock (RegisteredStats)
237 {
238 if (RegisteredStats.TryGetValue(stat.Category, out category))
239 {
240 if (category.TryGetValue(stat.Container, out container))
241 {
242 if (container.ContainsKey(stat.ShortName))
243 return true;
244 }
245 }
246 }
247
248 return false;
249 }
250
251 public static void RecordStats()
252 {
253 lock (RegisteredStats)
254 {
255 foreach (Dictionary<string, Dictionary<string, Stat>> category in RegisteredStats.Values)
256 {
257 foreach (Dictionary<string, Stat> container in category.Values)
258 {
259 foreach (Stat stat in container.Values)
260 {
261 if (stat.MeasuresOfInterest != MeasuresOfInterest.None)
262 stat.RecordValue();
263 }
264 }
265 }
266 }
267 }
268 }
269
270 /// <summary>
271 /// Stat type.
272 /// </summary>
273 /// <remarks>
274 /// A push stat is one which is continually updated and so it's value can simply by read.
275 /// A pull stat is one where reading the value triggers a collection method - the stat is not continually updated.
276 /// </remarks>
277 public enum StatType
278 {
279 Push,
280 Pull
281 }
282
283 /// <summary>
284 /// Measures of interest for this stat.
285 /// </summary>
286 [Flags]
287 public enum MeasuresOfInterest
288 {
289 None,
290 AverageChangeOverTime
291 }
292
293 /// <summary>
294 /// Verbosity of stat.
295 /// </summary>
296 /// <remarks>
297 /// Info will always be displayed.
298 /// </remarks>
299 public enum StatVerbosity
300 {
301 Debug,
302 Info
64 } 303 }
65} \ No newline at end of file 304} \ No newline at end of file