OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
MonitorModule.cs
Go to the documentation of this file.
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")]
48  {
52  public bool Enabled { get; private set; }
53 
54  private Scene m_scene;
55 
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[23],
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[38],
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 }
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Holds individual statistic details
Definition: Stat.cs:41
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
StatVerbosity
Verbosity of stat.