File: TestEventListener.cs
Web Access
Project: src\src\System.Private.ServiceModel\tests\Common\Infrastructure\Infrastructure.Common.csproj (Infrastructure.Common)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
 
namespace Infrastructure.Common
{
    /// <summary>Simple event listener</summary>
    /// This class is based on https://github.com/dotnet/corefx/blob/master/src/Common/tests/System/Diagnostics/Tracing/TestEventListener.cs
    public sealed class TestEventListener : EventListener
    {
        private Dictionary<string, bool> _targetSourceName = new Dictionary<string, bool>();
        private readonly EventLevel _level;
 
        private Action<EventWrittenEventArgs> _eventWritten;
        private List<EventSource> _tmpEventSourceList = new List<EventSource>();
 
        public TestEventListener(List<string> targetSourceNames, EventLevel level)
        {
            // Store the arguments
            foreach (var targetSourceName in targetSourceNames)
            {
                _targetSourceName.Add(targetSourceName, true);
            }
            _level = level;
 
            LoadSourceList();
        }
 
        public new Action<EventWrittenEventArgs> EventWritten
        {
            get { return _eventWritten; }
            set { _eventWritten = value; }
        }
 
        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 _targetSourceName 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<EventSource> sources;
            lock (_tmpEventSourceList)
            {
                sources = _tmpEventSourceList;
                _tmpEventSourceList = null;
            }
            foreach (EventSource source in sources)
            {
                EnableSourceIfMatch(source);
            }
        }
 
        protected override void OnEventSourceCreated(EventSource eventSource)
        {
            List<EventSource> tmp = _tmpEventSourceList;
            if (tmp != null)
            {
                lock (tmp)
                {
                    if (_tmpEventSourceList != null)
                    {
                        _tmpEventSourceList.Add(eventSource);
                        return;
                    }
                }
            }
 
            EnableSourceIfMatch(eventSource);
        }
 
        private void EnableSourceIfMatch(EventSource source)
        {
            if (_targetSourceName.ContainsKey(source.Name))
            {
                EnableEvents(source, _level);
            }
        }
        protected override void OnEventWritten(EventWrittenEventArgs eventData)
        {
            _eventWritten?.Invoke(eventData);
        }
    }
}