File: System\Diagnostics\TraceConfiguration.cs
Web Access
Project: src\src\libraries\System.Configuration.ConfigurationManager\src\System.Configuration.ConfigurationManager.csproj (System.Configuration.ConfigurationManager)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
namespace System.Diagnostics
{
    public static class TraceConfiguration
    {
        private static volatile bool s_registered;
 
        /// <summary>
        /// Register the configuration system to apply settings from configuration files
        /// to <seealso cref="System.Diagnostics.TraceSource"/> and related classes.
        /// </summary>
        public static void Register()
        {
            if (!s_registered)
            {
                // Registering callbacks more than once is fine, but avoid the overhead common cases without taking a lock.
                Trace.Refreshing += RefreshingConfiguration;
                Switch.Initializing += InitializingSwitch;
                TraceSource.Initializing += InitializingTraceSource;
 
                ConfigureTraceSettings();
 
                s_registered = true;
            }
        }
 
        private static void RefreshingConfiguration(object sender, EventArgs e) => DiagnosticsConfiguration.Refresh();
 
        private static void InitializingTraceSource(object sender, InitializingTraceSourceEventArgs e)
        {
            TraceSource traceSource = e.TraceSource;
 
            // Ported from https://referencesource.microsoft.com/#System/compmod/system/diagnostics/TraceSource.cs,176
            SourceElementsCollection sources = DiagnosticsConfiguration.Sources;
 
            if (sources != null)
            {
                SourceElement sourceElement = sources[traceSource.Name];
                if (sourceElement != null)
                {
                    e.WasInitialized = true;
 
                    // First check if the type changed.
                    if (HasSourceSwitchTypeChanged())
                    {
                        if (!string.IsNullOrEmpty(sourceElement.SwitchName))
                        {
                            CreateSwitch(sourceElement.SwitchType, sourceElement.SwitchName);
                        }
                        else
                        {
                            CreateSwitch(sourceElement.SwitchType, traceSource.Name);
 
                            if (!string.IsNullOrEmpty(sourceElement.SwitchValue))
                            {
                                traceSource.Switch.Level = Enum.Parse<SourceLevels>(sourceElement.SwitchValue);
                            }
                        }
                    }
                    else if (!string.IsNullOrEmpty(sourceElement.SwitchName))
                    {
                        // Create a new switch if the name changed, otherwise just refresh.
                        if (sourceElement.SwitchName != traceSource.Switch.DisplayName)
                            CreateSwitch(sourceElement.SwitchType, sourceElement.SwitchName);
                        else
                        {
                            traceSource.Switch.Refresh();
                        }
                    }
                    else
                    {
                        // The SwitchValue changed; just update our internalSwitch.
                        if (!string.IsNullOrEmpty(sourceElement.SwitchValue))
                        {
                            traceSource.Switch.Level = Enum.Parse<SourceLevels>(sourceElement.SwitchValue);
                        }
                        else
                        {
                            traceSource.Switch.Level = SourceLevels.Off;
                        }
                    }
 
                    TraceListener[] newListenerCollection = new TraceListener[sourceElement.Listeners.Count];
                    int listnerOffset = 0;
                    foreach (ListenerElement listenerElement in sourceElement.Listeners)
                    {
                        TraceListener listener = traceSource.Listeners[listenerElement.Name];
                        if (listener != null)
                        {
                            newListenerCollection[listnerOffset++] = listenerElement.RefreshRuntimeObject(listener);
                        }
                        else
                        {
                            newListenerCollection[listnerOffset++] = listenerElement.GetRuntimeObject();
                        }
                    }
 
                    TraceUtils.CopyStringDictionary(sourceElement.Attributes, traceSource.Attributes);
 
                    traceSource.Listeners.Clear();
                    traceSource.Listeners.AddRange(newListenerCollection);
                }
                else
                {
                    // There was no config, so clear whatever we have.
                    traceSource.Switch.Level = traceSource.DefaultLevel;
                    traceSource.Listeners.Clear();
                    traceSource.Attributes.Clear();
                }
 
                bool HasSourceSwitchTypeChanged()
                {
                    string sourceTypeName = sourceElement.SwitchType;
                    Type currentType = traceSource.Switch.GetType();
 
                    if (string.IsNullOrEmpty(sourceTypeName))
                    {
                        // SourceSwitch is the default switch type.
                        return currentType != typeof(SourceSwitch);
                    }
 
                    if (sourceTypeName == currentType.FullName)
                    {
                        return false;
                    }
 
                    // Since there can be more than one valid AssemblyQualifiedName for a given Type this
                    // check can return true for some cases which can cause a minor side effect of a new
                    // Switch being created instead of just being refreshed.
                    return sourceElement.SwitchType != currentType.AssemblyQualifiedName;
                }
            }
 
            void CreateSwitch(string typeName, string name)
            {
                if (!string.IsNullOrEmpty(typeName))
                {
                    traceSource.Switch = (SourceSwitch)TraceUtils.GetRuntimeObject(typeName, typeof(SourceSwitch), name);
                }
                else
                {
                    traceSource.Switch = new SourceSwitch(name, traceSource.DefaultLevel.ToString());
                }
            }
        }
 
        private static void ConfigureTraceSettings()
        {
            // Ported from https://referencesource.microsoft.com/#System/compmod/system/diagnostics/TraceInternal.cs,06360b4de5e221c2, https://referencesource.microsoft.com/#System/compmod/system/diagnostics/TraceInternal.cs,37
 
            TraceSection traceSection = DiagnosticsConfiguration.SystemDiagnosticsSection?.Trace;
 
            if (traceSection != null)
            {
                Trace.UseGlobalLock = traceSection.UseGlobalLock;
                Trace.AutoFlush = traceSection.AutoFlush;
                Trace.IndentSize = traceSection.IndentSize;
 
                ListenerElementsCollection listeners = DiagnosticsConfiguration.SystemDiagnosticsSection?.Trace.Listeners;
                if (listeners != null)
                {
                    // If listeners were configured, replace the defaults with these.
                    Trace.Listeners.Clear();
                    foreach (var listener in listeners.GetRuntimeObject())
                    {
                        Trace.Listeners.Add(listener);
                    }
                }
            }
        }
 
        private static void InitializingSwitch(object sender, InitializingSwitchEventArgs e)
        {
            Switch sw = e.Switch;
 
            // Ported from https://referencesource.microsoft.com/#System/compmod/system/diagnostics/Switch.cs,173
            SwitchElementsCollection switchSettings = DiagnosticsConfiguration.SwitchSettings;
            if (switchSettings != null)
            {
                SwitchElement mySettings = switchSettings[sw.DisplayName];
 
                if (mySettings != null)
                {
                    if (mySettings.Value != null)
                    {
                        sw.Value = mySettings.Value;
                    }
                    else
                    {
                        sw.Value = sw.DefaultValue;
                    }
 
                    TraceUtils.CopyStringDictionary(sw.Attributes, mySettings.Attributes);
                }
            }
        }
    }
}