diff options
Merge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork
Diffstat (limited to 'OpenSim/Framework/Monitoring/StatsManager.cs')
-rw-r--r-- | OpenSim/Framework/Monitoring/StatsManager.cs | 239 |
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 | ||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Text; | ||
31 | |||
28 | namespace OpenSim.Framework.Monitoring | 32 | namespace 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 |