OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
Stat.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.Generic;
30 using System.Linq;
31 using System.Reflection;
32 using System.Text;
33 using log4net;
34 using OpenMetaverse.StructuredData;
35 
36 namespace OpenSim.Framework.Monitoring
37 {
41  public class Stat : IDisposable
42  {
43 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 
45  public static readonly char[] DisallowedShortNameCharacters = { '.' };
46 
50  public string Category { get; private set; }
51 
60  public string Container { get; private set; }
61 
62  public StatType StatType { get; private set; }
63 
64  public MeasuresOfInterest MeasuresOfInterest { get; private set; }
65 
69  public Action<Stat> PullAction { get; private set; }
70 
71  public StatVerbosity Verbosity { get; private set; }
72  public string ShortName { get; private set; }
73  public string Name { get; private set; }
74  public string Description { get; private set; }
75  public virtual string UnitName { get; private set; }
76 
77  public virtual double Value
78  {
79  get
80  {
81  // Asking for an update here means that the updater cannot access this value without infinite recursion.
82  // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
83  // called by the pull action and just return the value.
84  if (StatType == StatType.Pull)
85  PullAction(this);
86 
87  return m_value;
88  }
89 
90  set
91  {
92  m_value = value;
93  }
94  }
95 
96  private double m_value;
97 
104  private Queue<double> m_samples;
105 
113  private static int m_maxSamples = 24;
114 
115  public Stat(
116  string shortName,
117  string name,
118  string description,
119  string unitName,
120  string category,
121  string container,
122  StatType type,
123  Action<Stat> pullAction,
124  StatVerbosity verbosity)
125  : this(
126  shortName,
127  name,
128  description,
129  unitName,
130  category,
131  container,
132  type,
134  pullAction,
135  verbosity)
136  {
137  }
138 
155  public Stat(
156  string shortName,
157  string name,
158  string description,
159  string unitName,
160  string category,
161  string container,
162  StatType type,
163  MeasuresOfInterest moi,
164  Action<Stat> pullAction,
165  StatVerbosity verbosity)
166  {
167  if (StatsManager.SubCommands.Contains(category))
168  throw new Exception(
169  string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
170 
171  foreach (char c in DisallowedShortNameCharacters)
172  {
173  if (shortName.IndexOf(c) != -1)
174  shortName = shortName.Replace(c, '#');
175 // throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
176  }
177 
178  ShortName = shortName;
179  Name = name;
180  Description = description;
181  UnitName = unitName;
182  Category = category;
183  Container = container;
184  StatType = type;
185 
186  if (StatType == StatType.Push && pullAction != null)
187  throw new Exception("A push stat cannot have a pull action");
188  else
189  PullAction = pullAction;
190 
191  MeasuresOfInterest = moi;
192 
193  if ((moi & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
194  m_samples = new Queue<double>(m_maxSamples);
195 
196  Verbosity = verbosity;
197  }
198 
199  // IDisposable.Dispose()
200  public virtual void Dispose()
201  {
202  return;
203  }
204 
211  public void RecordValue()
212  {
213  double newValue = Value;
214 
215  lock (m_samples)
216  {
217  if (m_samples.Count >= m_maxSamples)
218  m_samples.Dequeue();
219 
220 // m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name);
221 
222  m_samples.Enqueue(newValue);
223  }
224  }
225 
226  public virtual string ToConsoleString()
227  {
228  StringBuilder sb = new StringBuilder();
229  sb.AppendFormat(
230  "{0}.{1}.{2} : {3}{4}",
231  Category,
232  Container,
233  ShortName,
234  Value,
235  string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName));
236 
237  AppendMeasuresOfInterest(sb);
238 
239  return sb.ToString();
240  }
241 
242  public virtual OSDMap ToBriefOSDMap()
243  {
244  OSDMap ret = new OSDMap();
245 
246  ret.Add("Value", OSD.FromReal(Value));
247 
248  double lastChangeOverTime, averageChangeOverTime;
249 
250  return ret;
251  }
252 
253  public virtual OSDMap ToOSDMap()
254  {
255  OSDMap ret = new OSDMap();
256  ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
257 
258  ret.Add("Category", OSD.FromString(Category));
259  ret.Add("Container", OSD.FromString(Container));
260  ret.Add("ShortName", OSD.FromString(ShortName));
261  ret.Add("Name", OSD.FromString(Name));
262  ret.Add("Description", OSD.FromString(Description));
263  ret.Add("UnitName", OSD.FromString(UnitName));
264  ret.Add("Value", OSD.FromReal(Value));
265 
266  double lastChangeOverTime, averageChangeOverTime;
267  if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
268  {
269  ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime));
270  ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime));
271  }
272 
273  return ret;
274  }
275 
276  // Compute the averages over time and return same.
277  // Return 'true' if averages were actually computed. 'false' if no average info.
278  public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime)
279  {
280  bool ret = false;
281  lastChangeOverTime = 0;
282  averageChangeOverTime = 0;
283 
284  if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
285  {
286  double totalChange = 0;
287  double? penultimateSample = null;
288  double? lastSample = null;
289 
290  lock (m_samples)
291  {
292  // m_log.DebugFormat(
293  // "[STAT]: Samples for {0} are {1}",
294  // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
295 
296  foreach (double s in m_samples)
297  {
298  if (lastSample != null)
299  totalChange += s - (double)lastSample;
300 
301  penultimateSample = lastSample;
302  lastSample = s;
303  }
304  }
305 
306  if (lastSample != null && penultimateSample != null)
307  {
308  lastChangeOverTime
309  = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
310  }
311 
312  int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
313 
314  averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
315  ret = true;
316  }
317 
318  return ret;
319  }
320 
321  protected void AppendMeasuresOfInterest(StringBuilder sb)
322  {
323  double lastChangeOverTime = 0;
324  double averageChangeOverTime = 0;
325 
326  if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
327  {
328  sb.AppendFormat(
329  ", {0:0.##}{1}/s, {2:0.##}{3}/s",
330  lastChangeOverTime,
331  string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName),
332  averageChangeOverTime,
333  string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName));
334  }
335  }
336  }
337 }
virtual OSDMap ToBriefOSDMap()
Definition: Stat.cs:242
virtual string ToConsoleString()
Definition: Stat.cs:226
OpenMetaverse.StructuredData.OSDMap OSDMap
Holds individual statistic details
Definition: Stat.cs:41
Stat(string shortName, string name, string description, string unitName, string category, string container, StatType type, MeasuresOfInterest moi, Action< Stat > pullAction, StatVerbosity verbosity)
Constructor
Definition: Stat.cs:155
virtual OSDMap ToOSDMap()
Definition: Stat.cs:253
void AppendMeasuresOfInterest(StringBuilder sb)
Definition: Stat.cs:321
Stat(string shortName, string name, string description, string unitName, string category, string container, StatType type, Action< Stat > pullAction, StatVerbosity verbosity)
Definition: Stat.cs:115
void RecordValue()
Record a value in the sample set.
Definition: Stat.cs:211
StatVerbosity
Verbosity of stat.
bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime)
Definition: Stat.cs:278
MeasuresOfInterest
Measures of interest for this stat.