// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Threading.Tasks; namespace System.Diagnostics.Tracing { /// Simple event listener than invokes a callback for each event received. internal sealed class TestEventListener : EventListener { private readonly string _targetSourceName; private readonly Guid _targetSourceGuid; private readonly EventLevel _level; private readonly double? _eventCounterInterval; private Action _eventWritten; private List _tmpEventSourceList = new List(); public TestEventListener(string targetSourceName, EventLevel level, double? eventCounterInterval = null) { // Store the arguments _targetSourceName = targetSourceName; _level = level; _eventCounterInterval = eventCounterInterval; LoadSourceList(); } public TestEventListener(Guid targetSourceGuid, EventLevel level, double? eventCounterInterval = null) { // Store the arguments _targetSourceGuid = targetSourceGuid; _level = level; _eventCounterInterval = eventCounterInterval; LoadSourceList(); } private void LoadSourceList() { // The base constructor, which is called before this constructor, // will invoke the virtual OnEventSourceCreated method for each // existing EventSource, which means OnEventSourceCreated will be // called before _targetSourceGuid and _level have been set. As such, // we store a temporary list that just exists from the moment this instance // is created (instance field initializers run before the base constructor) // and until we finish construction... in that window, OnEventSourceCreated // will store the sources into the list rather than try to enable them directly, // and then here we can enumerate that list, then clear it out. List sources; lock (_tmpEventSourceList) { sources = _tmpEventSourceList; _tmpEventSourceList = null; } foreach (EventSource source in sources) { EnableSourceIfMatch(source); } } protected override void OnEventSourceCreated(EventSource eventSource) { List tmp = _tmpEventSourceList; if (tmp != null) { lock (tmp) { if (_tmpEventSourceList != null) { _tmpEventSourceList.Add(eventSource); return; } } } EnableSourceIfMatch(eventSource); } private void EnableSourceIfMatch(EventSource source) { if (source.Name.Equals(_targetSourceName) || source.Guid.Equals(_targetSourceGuid)) { if (_eventCounterInterval != null) { var args = new Dictionary { { "EventCounterIntervalSec", _eventCounterInterval?.ToString() } }; EnableEvents(source, _level, EventKeywords.All, args); } else { EnableEvents(source, _level); } } } public void RunWithCallback(Action handler, Action body) { _eventWritten = handler; try { body(); } finally { _eventWritten = null; } } public async Task RunWithCallbackAsync(Action handler, Func body) { _eventWritten = handler; try { await body().ConfigureAwait(false); } finally { _eventWritten = null; } } protected override void OnEventWritten(EventWrittenEventArgs eventData) { _eventWritten?.Invoke(eventData); } } }