clockwerk-opensim – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ |
||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions are met: |
||
7 | * * Redistributions of source code must retain the above copyright |
||
8 | * notice, this list of conditions and the following disclaimer. |
||
9 | * * Redistributions in binary form must reproduce the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer in the |
||
11 | * documentation and/or other materials provided with the distribution. |
||
12 | * * Neither the name of the OpenSimulator Project nor the |
||
13 | * names of its contributors may be used to endorse or promote products |
||
14 | * derived from this software without specific prior written permission. |
||
15 | * |
||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
26 | */ |
||
27 | |||
28 | using System; |
||
29 | using System.Collections; |
||
30 | using System.Collections.Generic; |
||
31 | using System.Reflection; |
||
32 | using log4net; |
||
33 | using Nini.Config; |
||
34 | using OpenMetaverse; |
||
35 | using OpenSim.Framework; |
||
36 | using OpenSim.Framework.Monitoring; |
||
37 | using OpenSim.Framework.Servers; |
||
38 | using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts; |
||
39 | using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors; |
||
40 | using OpenSim.Region.Framework.Interfaces; |
||
41 | using OpenSim.Region.Framework.Scenes; |
||
42 | using Mono.Addins; |
||
43 | |||
44 | namespace OpenSim.Region.CoreModules.Framework.Monitoring |
||
45 | { |
||
46 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MonitorModule")] |
||
47 | public class MonitorModule : INonSharedRegionModule |
||
48 | { |
||
49 | /// <summary> |
||
50 | /// Is this module enabled? |
||
51 | /// </summary> |
||
52 | public bool Enabled { get; private set; } |
||
53 | |||
54 | private Scene m_scene; |
||
55 | |||
56 | /// <summary> |
||
57 | /// These are monitors where we know the static details in advance. |
||
58 | /// </summary> |
||
59 | /// <remarks> |
||
60 | /// Dynamic monitors also exist (we don't know any of the details of what stats we get back here) |
||
61 | /// but these are currently hardcoded. |
||
62 | /// </remarks> |
||
63 | private readonly List<IMonitor> m_staticMonitors = new List<IMonitor>(); |
||
64 | |||
65 | private readonly List<IAlert> m_alerts = new List<IAlert>(); |
||
66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
67 | |||
68 | public MonitorModule() |
||
69 | { |
||
70 | Enabled = true; |
||
71 | } |
||
72 | |||
73 | #region Implementation of INonSharedRegionModule |
||
74 | |||
75 | public void Initialise(IConfigSource source) |
||
76 | { |
||
77 | IConfig cnfg = source.Configs["Monitoring"]; |
||
78 | |||
79 | if (cnfg != null) |
||
80 | Enabled = cnfg.GetBoolean("Enabled", true); |
||
81 | |||
82 | if (!Enabled) |
||
83 | return; |
||
84 | |||
85 | } |
||
86 | |||
87 | public void AddRegion(Scene scene) |
||
88 | { |
||
89 | if (!Enabled) |
||
90 | return; |
||
91 | |||
92 | m_scene = scene; |
||
93 | |||
94 | m_scene.AddCommand("General", this, "monitor report", |
||
95 | "monitor report", |
||
96 | "Returns a variety of statistics about the current region and/or simulator", |
||
97 | DebugMonitors); |
||
98 | |||
99 | MainServer.Instance.AddHTTPHandler("/monitorstats/" + m_scene.RegionInfo.RegionID, StatsPage); |
||
100 | MainServer.Instance.AddHTTPHandler( |
||
101 | "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage); |
||
102 | |||
103 | AddMonitors(); |
||
104 | RegisterStatsManagerRegionStatistics(); |
||
105 | } |
||
106 | |||
107 | public void RemoveRegion(Scene scene) |
||
108 | { |
||
109 | if (!Enabled) |
||
110 | return; |
||
111 | |||
112 | MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID); |
||
113 | MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName)); |
||
114 | |||
115 | UnRegisterStatsManagerRegionStatistics(); |
||
116 | |||
117 | m_scene = null; |
||
118 | } |
||
119 | |||
120 | public void Close() |
||
121 | { |
||
122 | } |
||
123 | |||
124 | public string Name |
||
125 | { |
||
126 | get { return "Region Health Monitoring Module"; } |
||
127 | } |
||
128 | |||
129 | public void RegionLoaded(Scene scene) |
||
130 | { |
||
131 | } |
||
132 | |||
133 | public Type ReplaceableInterface |
||
134 | { |
||
135 | get { return null; } |
||
136 | } |
||
137 | |||
138 | #endregion |
||
139 | |||
140 | public void AddMonitors() |
||
141 | { |
||
142 | m_staticMonitors.Add(new AgentCountMonitor(m_scene)); |
||
143 | m_staticMonitors.Add(new ChildAgentCountMonitor(m_scene)); |
||
144 | m_staticMonitors.Add(new GCMemoryMonitor()); |
||
145 | m_staticMonitors.Add(new ObjectCountMonitor(m_scene)); |
||
146 | m_staticMonitors.Add(new PhysicsFrameMonitor(m_scene)); |
||
147 | m_staticMonitors.Add(new PhysicsUpdateFrameMonitor(m_scene)); |
||
148 | m_staticMonitors.Add(new PWSMemoryMonitor()); |
||
149 | m_staticMonitors.Add(new ThreadCountMonitor()); |
||
150 | m_staticMonitors.Add(new TotalFrameMonitor(m_scene)); |
||
151 | m_staticMonitors.Add(new EventFrameMonitor(m_scene)); |
||
152 | m_staticMonitors.Add(new LandFrameMonitor(m_scene)); |
||
153 | m_staticMonitors.Add(new LastFrameTimeMonitor(m_scene)); |
||
154 | |||
155 | m_staticMonitors.Add( |
||
156 | new GenericMonitor( |
||
157 | m_scene, |
||
158 | "TimeDilationMonitor", |
||
159 | "Time Dilation", |
||
160 | m => m.Scene.StatsReporter.LastReportedSimStats[0], |
||
161 | m => m.GetValue().ToString())); |
||
162 | |||
163 | m_staticMonitors.Add( |
||
164 | new GenericMonitor( |
||
165 | m_scene, |
||
166 | "SimFPSMonitor", |
||
167 | "Sim FPS", |
||
168 | m => m.Scene.StatsReporter.LastReportedSimStats[1], |
||
169 | m => string.Format("{0}", m.GetValue()))); |
||
170 | |||
171 | m_staticMonitors.Add( |
||
172 | new GenericMonitor( |
||
173 | m_scene, |
||
174 | "PhysicsFPSMonitor", |
||
175 | "Physics FPS", |
||
176 | m => m.Scene.StatsReporter.LastReportedSimStats[2], |
||
177 | m => string.Format("{0}", m.GetValue()))); |
||
178 | |||
179 | m_staticMonitors.Add( |
||
180 | new GenericMonitor( |
||
181 | m_scene, |
||
182 | "AgentUpdatesPerSecondMonitor", |
||
183 | "Agent Updates", |
||
184 | m => m.Scene.StatsReporter.LastReportedSimStats[3], |
||
185 | m => string.Format("{0} per second", m.GetValue()))); |
||
186 | |||
187 | m_staticMonitors.Add( |
||
188 | new GenericMonitor( |
||
189 | m_scene, |
||
190 | "ActiveObjectCountMonitor", |
||
191 | "Active Objects", |
||
192 | m => m.Scene.StatsReporter.LastReportedSimStats[7], |
||
193 | m => string.Format("{0}", m.GetValue()))); |
||
194 | |||
195 | m_staticMonitors.Add( |
||
196 | new GenericMonitor( |
||
197 | m_scene, |
||
198 | "ActiveScriptsMonitor", |
||
199 | "Active Scripts", |
||
200 | m => m.Scene.StatsReporter.LastReportedSimStats[19], |
||
201 | m => string.Format("{0}", m.GetValue()))); |
||
202 | |||
203 | m_staticMonitors.Add( |
||
204 | new GenericMonitor( |
||
205 | m_scene, |
||
206 | "ScriptEventsPerSecondMonitor", |
||
207 | "Script Events", |
||
208 | m => m.Scene.StatsReporter.LastReportedSimStats[20], |
||
209 | m => string.Format("{0} per second", m.GetValue()))); |
||
210 | |||
211 | m_staticMonitors.Add( |
||
212 | new GenericMonitor( |
||
213 | m_scene, |
||
214 | "InPacketsPerSecondMonitor", |
||
215 | "In Packets", |
||
216 | m => m.Scene.StatsReporter.LastReportedSimStats[13], |
||
217 | m => string.Format("{0} per second", m.GetValue()))); |
||
218 | |||
219 | m_staticMonitors.Add( |
||
220 | new GenericMonitor( |
||
221 | m_scene, |
||
222 | "OutPacketsPerSecondMonitor", |
||
223 | "Out Packets", |
||
224 | m => m.Scene.StatsReporter.LastReportedSimStats[14], |
||
225 | m => string.Format("{0} per second", m.GetValue()))); |
||
226 | |||
227 | m_staticMonitors.Add( |
||
228 | new GenericMonitor( |
||
229 | m_scene, |
||
230 | "UnackedBytesMonitor", |
||
231 | "Unacked Bytes", |
||
232 | m => m.Scene.StatsReporter.LastReportedSimStats[15], |
||
233 | m => string.Format("{0}", m.GetValue()))); |
||
234 | |||
235 | m_staticMonitors.Add( |
||
236 | new GenericMonitor( |
||
237 | m_scene, |
||
238 | "PendingDownloadsMonitor", |
||
239 | "Pending Downloads", |
||
240 | m => m.Scene.StatsReporter.LastReportedSimStats[17], |
||
241 | m => string.Format("{0}", m.GetValue()))); |
||
242 | |||
243 | m_staticMonitors.Add( |
||
244 | new GenericMonitor( |
||
245 | m_scene, |
||
246 | "PendingUploadsMonitor", |
||
247 | "Pending Uploads", |
||
248 | m => m.Scene.StatsReporter.LastReportedSimStats[18], |
||
249 | m => string.Format("{0}", m.GetValue()))); |
||
250 | |||
251 | m_staticMonitors.Add( |
||
252 | new GenericMonitor( |
||
253 | m_scene, |
||
254 | "TotalFrameTimeMonitor", |
||
255 | "Total Frame Time", |
||
256 | m => m.Scene.StatsReporter.LastReportedSimStats[8], |
||
257 | m => string.Format("{0} ms", m.GetValue()))); |
||
258 | |||
259 | m_staticMonitors.Add( |
||
260 | new GenericMonitor( |
||
261 | m_scene, |
||
262 | "NetFrameTimeMonitor", |
||
263 | "Net Frame Time", |
||
264 | m => m.Scene.StatsReporter.LastReportedSimStats[9], |
||
265 | m => string.Format("{0} ms", m.GetValue()))); |
||
266 | |||
267 | m_staticMonitors.Add( |
||
268 | new GenericMonitor( |
||
269 | m_scene, |
||
270 | "PhysicsFrameTimeMonitor", |
||
271 | "Physics Frame Time", |
||
272 | m => m.Scene.StatsReporter.LastReportedSimStats[10], |
||
273 | m => string.Format("{0} ms", m.GetValue()))); |
||
274 | |||
275 | m_staticMonitors.Add( |
||
276 | new GenericMonitor( |
||
277 | m_scene, |
||
278 | "SimulationFrameTimeMonitor", |
||
279 | "Simulation Frame Time", |
||
280 | m => m.Scene.StatsReporter.LastReportedSimStats[12], |
||
281 | m => string.Format("{0} ms", m.GetValue()))); |
||
282 | |||
283 | m_staticMonitors.Add( |
||
284 | new GenericMonitor( |
||
285 | m_scene, |
||
286 | "AgentFrameTimeMonitor", |
||
287 | "Agent Frame Time", |
||
288 | m => m.Scene.StatsReporter.LastReportedSimStats[16], |
||
289 | m => string.Format("{0} ms", m.GetValue()))); |
||
290 | |||
291 | m_staticMonitors.Add( |
||
292 | new GenericMonitor( |
||
293 | m_scene, |
||
294 | "ImagesFrameTimeMonitor", |
||
295 | "Images Frame Time", |
||
296 | m => m.Scene.StatsReporter.LastReportedSimStats[11], |
||
297 | m => string.Format("{0} ms", m.GetValue()))); |
||
298 | |||
299 | m_staticMonitors.Add( |
||
300 | new GenericMonitor( |
||
301 | m_scene, |
||
302 | "SpareFrameTimeMonitor", |
||
303 | "Spare Frame Time", |
||
304 | m => m.Scene.StatsReporter.LastReportedSimStats[21], |
||
305 | m => string.Format("{0} ms", m.GetValue()))); |
||
306 | |||
307 | m_alerts.Add(new DeadlockAlert(m_staticMonitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor)); |
||
308 | |||
309 | foreach (IAlert alert in m_alerts) |
||
310 | { |
||
311 | alert.OnTriggerAlert += OnTriggerAlert; |
||
312 | } |
||
313 | } |
||
314 | |||
315 | public void DebugMonitors(string module, string[] args) |
||
316 | { |
||
317 | foreach (IMonitor monitor in m_staticMonitors) |
||
318 | { |
||
319 | MainConsole.Instance.OutputFormat( |
||
320 | "[MONITOR MODULE]: {0} reports {1} = {2}", |
||
321 | m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue()); |
||
322 | } |
||
323 | |||
324 | foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats()) |
||
325 | { |
||
326 | MainConsole.Instance.OutputFormat( |
||
327 | "[MONITOR MODULE]: {0} reports {1} = {2}", |
||
328 | m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value); |
||
329 | } |
||
330 | } |
||
331 | |||
332 | public void TestAlerts() |
||
333 | { |
||
334 | foreach (IAlert alert in m_alerts) |
||
335 | { |
||
336 | alert.Test(); |
||
337 | } |
||
338 | } |
||
339 | |||
340 | public Hashtable StatsPage(Hashtable request) |
||
341 | { |
||
342 | // If request was for a specific monitor |
||
343 | // eg url/?monitor=Monitor.Name |
||
344 | if (request.ContainsKey("monitor")) |
||
345 | { |
||
346 | string monID = (string) request["monitor"]; |
||
347 | |||
348 | foreach (IMonitor monitor in m_staticMonitors) |
||
349 | { |
||
350 | string elemName = monitor.ToString(); |
||
351 | if (elemName.StartsWith(monitor.GetType().Namespace)) |
||
352 | elemName = elemName.Substring(monitor.GetType().Namespace.Length + 1); |
||
353 | |||
354 | if (elemName == monID || monitor.ToString() == monID) |
||
355 | { |
||
356 | Hashtable ereply3 = new Hashtable(); |
||
357 | |||
358 | ereply3["int_response_code"] = 404; // 200 OK |
||
359 | ereply3["str_response_string"] = monitor.GetValue().ToString(); |
||
360 | ereply3["content_type"] = "text/plain"; |
||
361 | |||
362 | return ereply3; |
||
363 | } |
||
364 | } |
||
365 | |||
366 | // FIXME: Arguably this should also be done with dynamic monitors but I'm not sure what the above code |
||
367 | // is even doing. Why are we inspecting the type of the monitor??? |
||
368 | |||
369 | // No monitor with that name |
||
370 | Hashtable ereply2 = new Hashtable(); |
||
371 | |||
372 | ereply2["int_response_code"] = 404; // 200 OK |
||
373 | ereply2["str_response_string"] = "No such monitor"; |
||
374 | ereply2["content_type"] = "text/plain"; |
||
375 | |||
376 | return ereply2; |
||
377 | } |
||
378 | |||
379 | string xml = "<data>"; |
||
380 | foreach (IMonitor monitor in m_staticMonitors) |
||
381 | { |
||
382 | string elemName = monitor.GetName(); |
||
383 | xml += "<" + elemName + ">" + monitor.GetValue().ToString() + "</" + elemName + ">"; |
||
384 | // m_log.DebugFormat("[MONITOR MODULE]: {0} = {1}", elemName, monitor.GetValue()); |
||
385 | } |
||
386 | |||
387 | foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats()) |
||
388 | { |
||
389 | xml += "<" + tuple.Key + ">" + tuple.Value + "</" + tuple.Key + ">"; |
||
390 | } |
||
391 | |||
392 | xml += "</data>"; |
||
393 | |||
394 | Hashtable ereply = new Hashtable(); |
||
395 | |||
396 | ereply["int_response_code"] = 200; // 200 OK |
||
397 | ereply["str_response_string"] = xml; |
||
398 | ereply["content_type"] = "text/xml"; |
||
399 | |||
400 | return ereply; |
||
401 | } |
||
402 | |||
403 | void OnTriggerAlert(System.Type reporter, string reason, bool fatal) |
||
404 | { |
||
405 | m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")"); |
||
406 | } |
||
407 | |||
408 | private List<Stat> registeredStats = new List<Stat>(); |
||
409 | private void MakeStat(string pName, string pUnitName, Action<Stat> act) |
||
410 | { |
||
411 | Stat tempStat = new Stat(pName, pName, pName, pUnitName, "scene", m_scene.RegionInfo.RegionName, StatType.Pull, act, StatVerbosity.Info); |
||
412 | StatsManager.RegisterStat(tempStat); |
||
413 | registeredStats.Add(tempStat); |
||
414 | } |
||
415 | private void RegisterStatsManagerRegionStatistics() |
||
416 | { |
||
417 | MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); }); |
||
418 | MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); }); |
||
419 | MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); }); |
||
420 | MakeStat("ActivePrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetActiveObjectsCount(); }); |
||
421 | MakeStat("ActiveScripts", "scripts", (s) => { s.Value = m_scene.SceneGraph.GetActiveScriptsCount(); }); |
||
422 | |||
423 | MakeStat("TimeDilation", "sec/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[0]; }); |
||
424 | MakeStat("SimFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[1]; }); |
||
425 | MakeStat("PhysicsFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[2]; }); |
||
426 | MakeStat("AgentUpdates", "updates/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[3]; }); |
||
427 | MakeStat("FrameTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[8]; }); |
||
428 | MakeStat("NetTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[9]; }); |
||
429 | MakeStat("OtherTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[12]; }); |
||
430 | MakeStat("PhysicsTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[10]; }); |
||
431 | MakeStat("AgentTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[16]; }); |
||
432 | MakeStat("ImageTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[11]; }); |
||
433 | MakeStat("ScriptLines", "lines/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[20]; }); |
||
434 | MakeStat("SimSpareMS", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[21]; }); |
||
435 | } |
||
436 | |||
437 | private void UnRegisterStatsManagerRegionStatistics() |
||
438 | { |
||
439 | foreach (Stat stat in registeredStats) |
||
440 | { |
||
441 | StatsManager.DeregisterStat(stat); |
||
442 | stat.Dispose(); |
||
443 | } |
||
444 | registeredStats.Clear(); |
||
445 | } |
||
446 | |||
447 | } |
||
448 | } |