ChecksManager.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Linq;
  30. using System.Reflection;
  31. using System.Text;
  32. using log4net;
  33. namespace OpenSim.Framework.Monitoring
  34. {
  35. /// <summary>
  36. /// Static class used to register/deregister checks on runtime conditions.
  37. /// </summary>
  38. public static class ChecksManager
  39. {
  40. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  41. // Subcommand used to list other stats.
  42. public const string ListSubCommand = "list";
  43. // All subcommands
  44. public static HashSet<string> SubCommands = new HashSet<string> { ListSubCommand };
  45. /// <summary>
  46. /// Checks categorized by category/container/shortname
  47. /// </summary>
  48. /// <remarks>
  49. /// Do not add or remove directly from this dictionary.
  50. /// </remarks>
  51. public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>> RegisteredChecks
  52. = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>>();
  53. public static void RegisterConsoleCommands(ICommandConsole console)
  54. {
  55. console.Commands.AddCommand(
  56. "General",
  57. false,
  58. "show checks",
  59. "show checks",
  60. "Show checks configured for this server",
  61. "If no argument is specified then info on all checks will be shown.\n"
  62. + "'list' argument will show check categories.\n"
  63. + "THIS FACILITY IS EXPERIMENTAL",
  64. HandleShowchecksCommand);
  65. }
  66. public static void HandleShowchecksCommand(string module, string[] cmd)
  67. {
  68. ICommandConsole con = MainConsole.Instance;
  69. if (cmd.Length > 2)
  70. {
  71. foreach (string name in cmd.Skip(2))
  72. {
  73. string[] components = name.Split('.');
  74. string categoryName = components[0];
  75. // string containerName = components.Length > 1 ? components[1] : null;
  76. if (categoryName == ListSubCommand)
  77. {
  78. con.Output("check categories available are:");
  79. foreach (string category in RegisteredChecks.Keys)
  80. con.OutputFormat(" {0}", category);
  81. }
  82. // else
  83. // {
  84. // SortedDictionary<string, SortedDictionary<string, Check>> category;
  85. // if (!Registeredchecks.TryGetValue(categoryName, out category))
  86. // {
  87. // con.OutputFormat("No such category as {0}", categoryName);
  88. // }
  89. // else
  90. // {
  91. // if (String.IsNullOrEmpty(containerName))
  92. // {
  93. // OutputConfiguredToConsole(con, category);
  94. // }
  95. // else
  96. // {
  97. // SortedDictionary<string, Check> container;
  98. // if (category.TryGetValue(containerName, out container))
  99. // {
  100. // OutputContainerChecksToConsole(con, container);
  101. // }
  102. // else
  103. // {
  104. // con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
  105. // }
  106. // }
  107. // }
  108. // }
  109. }
  110. }
  111. else
  112. {
  113. OutputAllChecksToConsole(con);
  114. }
  115. }
  116. /// <summary>
  117. /// Registers a statistic.
  118. /// </summary>
  119. /// <param name='stat'></param>
  120. /// <returns></returns>
  121. public static bool RegisterCheck(Check check)
  122. {
  123. SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
  124. SortedDictionary<string, Check> container = null, newContainer;
  125. lock (RegisteredChecks)
  126. {
  127. // Check name is not unique across category/container/shortname key.
  128. // XXX: For now just return false. This is to avoid problems in regression tests where all tests
  129. // in a class are run in the same instance of the VM.
  130. if (TryGetCheckParents(check, out category, out container))
  131. return false;
  132. // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
  133. // This means that we don't need to lock or copy them on iteration, which will be a much more
  134. // common operation after startup.
  135. if (container != null)
  136. newContainer = new SortedDictionary<string, Check>(container);
  137. else
  138. newContainer = new SortedDictionary<string, Check>();
  139. if (category != null)
  140. newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
  141. else
  142. newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>();
  143. newContainer[check.ShortName] = check;
  144. newCategory[check.Container] = newContainer;
  145. RegisteredChecks[check.Category] = newCategory;
  146. }
  147. return true;
  148. }
  149. /// <summary>
  150. /// Deregister an check
  151. /// </summary>>
  152. /// <param name='stat'></param>
  153. /// <returns></returns>
  154. public static bool DeregisterCheck(Check check)
  155. {
  156. SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
  157. SortedDictionary<string, Check> container = null, newContainer;
  158. lock (RegisteredChecks)
  159. {
  160. if (!TryGetCheckParents(check, out category, out container))
  161. return false;
  162. newContainer = new SortedDictionary<string, Check>(container);
  163. newContainer.Remove(check.ShortName);
  164. newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
  165. newCategory.Remove(check.Container);
  166. newCategory[check.Container] = newContainer;
  167. RegisteredChecks[check.Category] = newCategory;
  168. return true;
  169. }
  170. }
  171. public static bool TryGetCheckParents(
  172. Check check,
  173. out SortedDictionary<string, SortedDictionary<string, Check>> category,
  174. out SortedDictionary<string, Check> container)
  175. {
  176. category = null;
  177. container = null;
  178. lock (RegisteredChecks)
  179. {
  180. if (RegisteredChecks.TryGetValue(check.Category, out category))
  181. {
  182. if (category.TryGetValue(check.Container, out container))
  183. {
  184. if (container.ContainsKey(check.ShortName))
  185. return true;
  186. }
  187. }
  188. }
  189. return false;
  190. }
  191. public static void CheckChecks()
  192. {
  193. lock (RegisteredChecks)
  194. {
  195. foreach (SortedDictionary<string, SortedDictionary<string, Check>> category in RegisteredChecks.Values)
  196. {
  197. foreach (SortedDictionary<string, Check> container in category.Values)
  198. {
  199. foreach (Check check in container.Values)
  200. {
  201. if (!check.CheckIt())
  202. m_log.WarnFormat(
  203. "[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage);
  204. }
  205. }
  206. }
  207. }
  208. }
  209. private static void OutputAllChecksToConsole(ICommandConsole con)
  210. {
  211. foreach (var category in RegisteredChecks.Values)
  212. {
  213. OutputCategoryChecksToConsole(con, category);
  214. }
  215. }
  216. private static void OutputCategoryChecksToConsole(
  217. ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Check>> category)
  218. {
  219. foreach (var container in category.Values)
  220. {
  221. OutputContainerChecksToConsole(con, container);
  222. }
  223. }
  224. private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary<string, Check> container)
  225. {
  226. foreach (Check check in container.Values)
  227. {
  228. con.Output(check.ToConsoleString());
  229. }
  230. }
  231. }
  232. }