PageRenderTime 32ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs

https://gitlab.com/unofficial-mirrors/PowerShell
C# | 339 lines | 180 code | 47 blank | 112 comment | 23 complexity | f1e360919e2bbb30af5b1b618039b918 MD5 | raw file
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License.
  3. #if UNIX
  4. using System.Diagnostics.Eventing;
  5. using System.Management.Automation.Configuration;
  6. using System.Management.Automation.Internal;
  7. using System.Text;
  8. using System.Collections.Generic;
  9. namespace System.Management.Automation.Tracing
  10. {
  11. /// <summary>
  12. /// SysLog LogProvider implementation.
  13. /// </summary>
  14. internal class PSSysLogProvider : LogProvider
  15. {
  16. private static SysLogProvider s_provider;
  17. // by default, do not include channel bits
  18. internal const PSKeyword DefaultKeywords = (PSKeyword) (0x00FFFFFFFFFFFFFF);
  19. // the default enabled channel(s)
  20. internal const PSChannel DefaultChannels = PSChannel.Operational;
  21. /// <summary>
  22. /// Class constructor.
  23. /// </summary>
  24. static PSSysLogProvider()
  25. {
  26. s_provider = new SysLogProvider(PowerShellConfig.Instance.GetSysLogIdentity(),
  27. PowerShellConfig.Instance.GetLogLevel(),
  28. PowerShellConfig.Instance.GetLogKeywords(),
  29. PowerShellConfig.Instance.GetLogChannels());
  30. }
  31. /// <summary>
  32. /// Defines a thread local StringBuilder for building event payload strings.
  33. /// </summary>
  34. /// <remarks>
  35. /// NOTE: do not access this field directly, use the PayloadBuilder
  36. /// property to ensure correct thread initialization; otherwise, a null reference can occur.
  37. /// </remarks>
  38. [ThreadStatic]
  39. private static StringBuilder _payloadBuilder;
  40. private static StringBuilder PayloadBuilder
  41. {
  42. get
  43. {
  44. if (_payloadBuilder == null)
  45. {
  46. // NOTE: Thread static fields must be explicitly initialized for each thread.
  47. _payloadBuilder = new StringBuilder(200);
  48. }
  49. return _payloadBuilder;
  50. }
  51. }
  52. /// <summary>
  53. /// Determines whether any session is requesting the specified event from the provider.
  54. /// </summary>
  55. /// <param name="level"></param>
  56. /// <param name="keywords"></param>
  57. /// <returns></returns>
  58. /// <remarks>
  59. /// Typically, a provider does not call this method to determine whether a session requested the specified event;
  60. /// the provider simply writes the event, and ETW determines whether the event is logged to a session. A provider
  61. /// may want to call this function if the provider needs to perform extra work to generate the event. In this case,
  62. /// calling this function first to determine if a session requested the event or not, may save resources and time.
  63. /// </remarks>
  64. internal bool IsEnabled(PSLevel level, PSKeyword keywords)
  65. {
  66. return s_provider.IsEnabled(level, keywords);
  67. }
  68. /// <summary>
  69. /// Provider interface function for logging health event
  70. /// </summary>
  71. /// <param name="logContext"></param>
  72. /// <param name="eventId"></param>
  73. /// <param name="exception"></param>
  74. /// <param name="additionalInfo"></param>
  75. ///
  76. internal override void LogEngineHealthEvent(LogContext logContext, int eventId, Exception exception, Dictionary<String, String> additionalInfo)
  77. {
  78. StringBuilder payload = PayloadBuilder;
  79. payload.Clear();
  80. AppendException(payload, exception);
  81. payload.AppendLine();
  82. AppendAdditionalInfo(payload, additionalInfo);
  83. WriteEvent(PSEventId.Engine_Health, PSChannel.Operational, PSOpcode.Exception, PSTask.ExecutePipeline, logContext, payload.ToString());
  84. }
  85. /// <summary>
  86. /// Provider interface function for logging engine lifecycle event
  87. /// </summary>
  88. /// <param name="logContext"></param>
  89. /// <param name="newState"></param>
  90. /// <param name="previousState"></param>
  91. ///
  92. internal override void LogEngineLifecycleEvent(LogContext logContext, EngineState newState, EngineState previousState)
  93. {
  94. if (IsEnabled(PSLevel.Informational, PSKeyword.Cmdlets | PSKeyword.UseAlwaysAnalytic))
  95. {
  96. StringBuilder payload = PayloadBuilder;
  97. payload.Clear();
  98. payload.AppendLine(StringUtil.Format(EtwLoggingStrings.EngineStateChange, previousState.ToString(), newState.ToString()));
  99. PSTask task = PSTask.EngineStart;
  100. if (newState == EngineState.Stopped ||
  101. newState == EngineState.OutOfService ||
  102. newState == EngineState.None ||
  103. newState == EngineState.Degraded)
  104. {
  105. task = PSTask.EngineStop;
  106. }
  107. WriteEvent(PSEventId.Engine_Lifecycle, PSChannel.Analytic, PSOpcode.Method, task, logContext, payload.ToString());
  108. }
  109. }
  110. /// <summary>
  111. /// Provider interface function for logging command health event
  112. /// </summary>
  113. /// <param name="logContext"></param>
  114. /// <param name="exception"></param>
  115. internal override void LogCommandHealthEvent(LogContext logContext, Exception exception)
  116. {
  117. StringBuilder payload = PayloadBuilder;
  118. payload.Clear();
  119. AppendException(payload, exception);
  120. WriteEvent(PSEventId.Command_Health, PSChannel.Operational, PSOpcode.Exception, PSTask.ExecutePipeline, logContext, payload.ToString());
  121. }
  122. /// <summary>
  123. /// Provider interface function for logging command lifecycle event
  124. /// </summary>
  125. /// <param name="getLogContext"></param>
  126. /// <param name="newState"></param>
  127. ///
  128. internal override void LogCommandLifecycleEvent(Func<LogContext> getLogContext, CommandState newState)
  129. {
  130. if (IsEnabled(PSLevel.Informational, PSKeyword.Cmdlets | PSKeyword.UseAlwaysAnalytic))
  131. {
  132. LogContext logContext = getLogContext();
  133. StringBuilder payload = PayloadBuilder;
  134. payload.Clear();
  135. if (logContext.CommandType != null)
  136. {
  137. if (logContext.CommandType.Equals(StringLiterals.Script, StringComparison.OrdinalIgnoreCase))
  138. {
  139. payload.AppendLine(StringUtil.Format(EtwLoggingStrings.ScriptStateChange, newState.ToString()));
  140. }
  141. else
  142. {
  143. payload.AppendLine(StringUtil.Format(EtwLoggingStrings.CommandStateChange, logContext.CommandName, newState.ToString()));
  144. }
  145. }
  146. PSTask task = PSTask.CommandStart;
  147. if (newState == CommandState.Stopped ||
  148. newState == CommandState.Terminated)
  149. {
  150. task = PSTask.CommandStop;
  151. }
  152. WriteEvent(PSEventId.Command_Lifecycle, PSChannel.Analytic, PSOpcode.Method, task, logContext, payload.ToString());
  153. }
  154. }
  155. /// <summary>
  156. /// Provider interface function for logging pipeline execution detail.
  157. /// </summary>
  158. /// <param name="logContext"></param>
  159. /// <param name="pipelineExecutionDetail"></param>
  160. internal override void LogPipelineExecutionDetailEvent(LogContext logContext, List<String> pipelineExecutionDetail)
  161. {
  162. StringBuilder payload = PayloadBuilder;
  163. payload.Clear();
  164. if (pipelineExecutionDetail != null)
  165. {
  166. foreach (String detail in pipelineExecutionDetail)
  167. {
  168. payload.AppendLine(detail);
  169. }
  170. }
  171. WriteEvent(PSEventId.Pipeline_Detail, PSChannel.Operational, PSOpcode.Method, PSTask.ExecutePipeline, logContext, payload.ToString());
  172. }
  173. /// <summary>
  174. /// Provider interface function for logging provider health event
  175. /// </summary>
  176. /// <param name="logContext"></param>
  177. /// <param name="providerName"></param>
  178. /// <param name="exception"></param>
  179. internal override void LogProviderHealthEvent(LogContext logContext, string providerName, Exception exception)
  180. {
  181. StringBuilder payload = PayloadBuilder;
  182. payload.Clear();
  183. AppendException(payload, exception);
  184. payload.AppendLine();
  185. Dictionary<String, String> additionalInfo = new Dictionary<string, string>();
  186. additionalInfo.Add(EtwLoggingStrings.ProviderNameString, providerName);
  187. AppendAdditionalInfo(payload, additionalInfo);
  188. WriteEvent(PSEventId.Provider_Health, PSChannel.Operational, PSOpcode.Exception, PSTask.ExecutePipeline, logContext, payload.ToString());
  189. }
  190. /// <summary>
  191. /// Provider interface function for logging provider lifecycle event
  192. /// </summary>
  193. /// <param name="logContext"></param>
  194. /// <param name="providerName"></param>
  195. /// <param name="newState"></param>
  196. ///
  197. internal override void LogProviderLifecycleEvent(LogContext logContext, string providerName, ProviderState newState)
  198. {
  199. if (IsEnabled(PSLevel.Informational, PSKeyword.Cmdlets | PSKeyword.UseAlwaysAnalytic))
  200. {
  201. StringBuilder payload = PayloadBuilder;
  202. payload.Clear();
  203. payload.AppendLine(StringUtil.Format(EtwLoggingStrings.ProviderStateChange, providerName, newState.ToString()));
  204. PSTask task = PSTask.ProviderStart;
  205. if (newState == ProviderState.Stopped)
  206. {
  207. task = PSTask.ProviderStop;
  208. }
  209. WriteEvent(PSEventId.Provider_Lifecycle, PSChannel.Analytic, PSOpcode.Method, task, logContext, payload.ToString());
  210. }
  211. }
  212. /// <summary>
  213. /// Provider interface function for logging settings event
  214. /// </summary>
  215. /// <param name="logContext"></param>
  216. /// <param name="variableName"></param>
  217. /// <param name="value"></param>
  218. /// <param name="previousValue"></param>
  219. ///
  220. internal override void LogSettingsEvent(LogContext logContext, string variableName, string value, string previousValue)
  221. {
  222. if (IsEnabled(PSLevel.Informational, PSKeyword.Cmdlets | PSKeyword.UseAlwaysAnalytic))
  223. {
  224. StringBuilder payload = PayloadBuilder;
  225. payload.Clear();
  226. if (previousValue == null)
  227. {
  228. payload.AppendLine(StringUtil.Format(EtwLoggingStrings.SettingChangeNoPrevious, variableName, value));
  229. }
  230. else
  231. {
  232. payload.AppendLine(StringUtil.Format(EtwLoggingStrings.SettingChange, variableName, previousValue, value));
  233. }
  234. WriteEvent(PSEventId.Settings, PSChannel.Analytic, PSOpcode.Method, PSTask.ExecutePipeline, logContext, payload.ToString());
  235. }
  236. }
  237. /// <summary>
  238. /// The SysLog provider does not use logging variables
  239. /// </summary>
  240. /// <returns></returns>
  241. internal override bool UseLoggingVariables()
  242. {
  243. return false;
  244. }
  245. /// <summary>
  246. /// Writes a single event
  247. /// </summary>
  248. /// <param name="id">event id</param>
  249. /// <param name="channel"></param>
  250. /// <param name="opcode"></param>
  251. /// <param name="task"></param>
  252. /// <param name="logContext">log context</param>
  253. /// <param name="payLoad"></param>
  254. internal void WriteEvent(PSEventId id, PSChannel channel, PSOpcode opcode, PSTask task, LogContext logContext, string payLoad)
  255. {
  256. s_provider.Log(id, channel, task, opcode, GetPSLevelFromSeverity(logContext.Severity), DefaultKeywords,
  257. LogContextToString(logContext),
  258. GetPSLogUserData(logContext.ExecutionContext),
  259. payLoad);
  260. }
  261. /// <summary>
  262. /// Writes an event
  263. /// </summary>
  264. /// <param name="id"></param>
  265. /// <param name="channel"></param>
  266. /// <param name="opcode"></param>
  267. /// <param name="level"></param>
  268. /// <param name="task"></param>
  269. /// <param name="keyword"></param>
  270. /// <param name="args"></param>
  271. internal void WriteEvent(PSEventId id, PSChannel channel, PSOpcode opcode, PSLevel level, PSTask task, PSKeyword keyword, params object[] args)
  272. {
  273. s_provider.Log(id, channel, task, opcode, level, keyword, args);
  274. }
  275. /// <summary>
  276. /// Writes an activity transfer event
  277. /// </summary>
  278. internal void WriteTransferEvent(Guid parentActivityId)
  279. {
  280. s_provider.LogTransfer(parentActivityId);
  281. }
  282. /// <summary>
  283. /// Sets the activity id for the current thread.
  284. /// </summary>
  285. /// <param name="newActivityId">the GUID identifying the activity.</param>
  286. internal void SetActivityIdForCurrentThread(Guid newActivityId)
  287. {
  288. s_provider.SetActivity(newActivityId);
  289. }
  290. }
  291. }
  292. #endif // UNIX