29 using System.Collections.Generic;
30 using System.Diagnostics;
32 using System.Net.NetworkInformation;
34 using System.Threading;
37 using OpenMetaverse.StructuredData;
38 using OpenSim.Framework;
40 namespace OpenSim.Framework.Monitoring
44 private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
45 private readonly
string LogHeader =
"[SERVER STATS]";
47 public bool Enabled =
false;
48 private static Dictionary<string, Stat> RegisteredStats =
new Dictionary<string, Stat>();
50 public readonly
string CategoryServer =
"server";
52 public readonly
string ContainerThreadpool =
"threadpool";
53 public readonly
string ContainerProcessor =
"processor";
54 public readonly
string ContainerMemory =
"memory";
55 public readonly
string ContainerNetwork =
"network";
56 public readonly
string ContainerProcess =
"process";
58 public string NetworkInterfaceTypes =
"Ethernet";
60 readonly
int performanceCounterSampleInterval = 500;
63 private class PerfCounterControl
65 public PerformanceCounter perfCounter;
68 public PerfCounterControl(PerformanceCounter pPc)
69 :
this(pPc, String.Empty)
72 public PerfCounterControl(PerformanceCounter pPc,
string pName)
80 PerfCounterControl processorPercentPerfCounter = null;
88 IConfig cfg = source.Configs[
"Monitoring"];
91 Enabled = cfg.GetBoolean(
"ServerStatsEnabled",
true);
95 NetworkInterfaceTypes = cfg.GetString(
"NetworkInterfaceTypes",
"Ethernet");
101 if (RegisteredStats.Count == 0)
102 RegisterServerStats();
107 if (RegisteredStats.Count > 0)
109 foreach (
Stat stat
in RegisteredStats.Values)
111 StatsManager.DeregisterStat(stat);
114 RegisteredStats.Clear();
118 private void MakeStat(
string pName,
string pDesc,
string pUnit,
string pContainer, Action<Stat> act)
123 private void MakeStat(
string pName,
string pDesc,
string pUnit,
string pContainer, Action<Stat> act,
MeasuresOfInterest moi)
128 Stat stat =
new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer,
StatType.Pull, moi, act,
StatVerbosity.Debug);
129 StatsManager.RegisterStat(stat);
130 RegisteredStats.Add(pName, stat);
136 PerformanceCounter tempPC;
142 tempName =
"CPUPercent";
143 tempPC =
new PerformanceCounter(
"Processor",
"% Processor Time",
"_Total");
144 processorPercentPerfCounter =
new PerfCounterControl(tempPC);
146 tempStat =
new Stat(tempName, tempName,
"",
"percent", CategoryServer, ContainerProcessor,
147 StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter); },
149 StatsManager.RegisterStat(tempStat);
150 RegisteredStats.Add(tempName, tempStat);
152 MakeStat(
"TotalProcessorTime", null,
"sec", ContainerProcessor,
153 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds, 3); });
155 MakeStat(
"UserProcessorTime", null,
"sec", ContainerProcessor,
156 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().UserProcessorTime.TotalSeconds, 3); });
158 MakeStat(
"PrivilegedProcessorTime", null,
"sec", ContainerProcessor,
159 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds, 3); });
161 MakeStat(
"Threads", null,
"threads", ContainerProcessor,
162 (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
166 m_log.ErrorFormat(
"{0} Exception creating 'Process': {1}", LogHeader, e);
169 MakeStat(
"BuiltinThreadpoolWorkerThreadsAvailable", null,
"threads", ContainerThreadpool,
172 int workerThreads, iocpThreads;
173 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
174 s.Value = workerThreads;
177 MakeStat(
"BuiltinThreadpoolIOCPThreadsAvailable", null,
"threads", ContainerThreadpool,
180 int workerThreads, iocpThreads;
181 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
182 s.Value = iocpThreads;
185 if (Util.FireAndForgetMethod ==
FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null)
187 MakeStat(
"STPMaxThreads", null,
"threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads);
188 MakeStat(
"STPMinThreads", null,
"threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads);
189 MakeStat(
"STPConcurrency", null,
"threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems);
190 MakeStat(
"STPActiveThreads", null,
"threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads);
191 MakeStat(
"STPInUseThreads", null,
"threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads);
192 MakeStat(
"STPWorkItemsWaiting", null,
"threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks);
197 "Number of outbound HTTP requests made",
200 s => s.Value = WebUtil.RequestNumber,
205 List<string> okInterfaceTypes =
new List<string>(NetworkInterfaceTypes.Split(
','));
208 foreach (NetworkInterface nic
in nics)
210 if (nic.OperationalStatus != OperationalStatus.Up)
213 string nicInterfaceType = nic.NetworkInterfaceType.ToString();
214 if (!okInterfaceTypes.Contains(nicInterfaceType))
216 m_log.DebugFormat(
"{0} Not including stats for network interface '{1}' of type '{2}'.",
217 LogHeader, nic.Name, nicInterfaceType);
218 m_log.DebugFormat(
"{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
219 LogHeader, NetworkInterfaceTypes);
223 if (nic.Supports(NetworkInterfaceComponent.IPv4))
225 IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
226 if (nicStats != null)
228 MakeStat(
"BytesRcvd/" + nic.Name, nic.Name,
"KB", ContainerNetwork,
229 (s) => { LookupNic(s, (ns) => {
return ns.BytesReceived; }, 1024.0); });
230 MakeStat(
"BytesSent/" + nic.Name, nic.Name,
"KB", ContainerNetwork,
231 (s) => { LookupNic(s, (ns) => {
return ns.BytesSent; }, 1024.0); });
232 MakeStat(
"TotalBytes/" + nic.Name, nic.Name,
"KB", ContainerNetwork,
233 (s) => { LookupNic(s, (ns) => {
return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
241 m_log.ErrorFormat(
"{0} Exception creating 'Network Interface': {1}", LogHeader, e);
244 MakeStat(
"ProcessMemory", null,
"MB", ContainerMemory,
245 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); });
246 MakeStat(
"HeapMemory", null,
"MB", ContainerMemory,
247 (s) => { s.Value = Math.Round(GC.GetTotalMemory(
false) / 1024d / 1024d, 3); });
248 MakeStat(
"LastHeapAllocationRate", null,
"MB/sec", ContainerMemory,
249 (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
250 MakeStat(
"AverageHeapAllocationRate", null,
"MB/sec", ContainerMemory,
251 (s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
253 MakeStat(
"ProcessResident", null,
"MB", ContainerProcess,
256 Process myprocess = Process.GetCurrentProcess();
258 s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0);
260 MakeStat(
"ProcessPaged", null,
"MB", ContainerProcess,
263 Process myprocess = Process.GetCurrentProcess();
265 s.Value = Math.Round(Process.GetCurrentProcess().PagedMemorySize64 / 1024.0 / 1024.0);
267 MakeStat(
"ProcessVirtual", null,
"MB", ContainerProcess,
270 Process myprocess = Process.GetCurrentProcess();
272 s.Value = Math.Round(Process.GetCurrentProcess().VirtualMemorySize64 / 1024.0 / 1024.0);
274 MakeStat(
"PeakProcessResident", null,
"MB", ContainerProcess,
277 Process myprocess = Process.GetCurrentProcess();
279 s.Value = Math.Round(Process.GetCurrentProcess().PeakWorkingSet64 / 1024.0 / 1024.0);
281 MakeStat(
"PeakProcessPaged", null,
"MB", ContainerProcess,
284 Process myprocess = Process.GetCurrentProcess();
286 s.Value = Math.Round(Process.GetCurrentProcess().PeakPagedMemorySize64 / 1024.0 / 1024.0);
288 MakeStat(
"PeakProcessVirtual", null,
"MB", ContainerProcess,
291 Process myprocess = Process.GetCurrentProcess();
293 s.Value = Math.Round(Process.GetCurrentProcess().PeakVirtualMemorySize64 / 1024.0 / 1024.0);
301 private delegate
double PerfCounterNextValue();
303 private void GetNextValue(Stat stat, PerfCounterControl perfControl)
305 if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval)
307 if (perfControl != null && perfControl.perfCounter != null)
311 stat.Value = Math.Round(perfControl.perfCounter.NextValue(), 3);
315 m_log.ErrorFormat(
"{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e);
318 perfControl.lastFetch = Util.EnvironmentTickCount();
325 private delegate
double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
326 private void LookupNic(Stat stat, GetIPv4StatValue getter,
double factor)
330 (network) => network.Name == stat.Description);
333 foreach (NetworkInterface nic
in nics)
335 IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
336 if (intrStats != null)
338 double newVal = Math.Round(getter(intrStats) / factor, 3);
347 m_log.ErrorFormat(
"{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description);
377 StringBuilder sb =
new StringBuilder();
379 return sb.ToString();
FireAndForgetMethod
The method used by Util.FireAndForget for asynchronously firing events
OpenMetaverse.StructuredData.OSDMap OSDMap
Holds individual statistic details
ServerStatsAggregator(string shortName, string name, string description, string unitName, string category, string container)
override OSDMap ToOSDMap()
StatVerbosity
Verbosity of stat.
System.Collections.IEnumerable IEnumerable
override string ToConsoleString()
void RegisterServerStats()
MeasuresOfInterest
Measures of interest for this stat.
void Initialise(IConfigSource source)