File: compmod\system\diagnostics\TraceInternal.cs
Project: ndp\fx\src\System.csproj (System)
//------------------------------------------------------------------------------
// <copyright file="TraceInternal.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Diagnostics {
    using System.Threading;
    using System.IO;
    using System.Security.Permissions;
    using System.Collections;
 
    internal static class TraceInternal {
        private static volatile string appName = null;
        static volatile TraceListenerCollection listeners;
        static volatile bool autoFlush;
        static volatile bool useGlobalLock;
        [ThreadStatic]
        static int indentLevel;
        static volatile int indentSize;
        static volatile bool settingsInitialized;
        static volatile bool defaultInitialized;
 
 
        // this is internal so TraceSource can use it.  We want to lock on the same object because both TraceInternal and 
        // TraceSource could be writing to the same listeners at the same time. 
        internal static readonly object critSec = new object();
 
        public static TraceListenerCollection Listeners { 
            get {
                InitializeSettings();
                if (listeners == null) {
                    lock (critSec) {
                        if (listeners == null) {
                            // We only need to check that the main section exists.  Everything else will get 
                            // created for us if it doesn't exist already. 
                            SystemDiagnosticsSection configSectionSav = DiagnosticsConfiguration.SystemDiagnosticsSection;
                            if (configSectionSav != null) {
                                listeners = configSectionSav.Trace.Listeners.GetRuntimeObject();
                            }
                            else {
                                // If machine.config was deleted the code will get to here
                                // supply at least something to prevent the world from coming to
                                // an abrupt end. 
                                listeners = new TraceListenerCollection();
                                TraceListener defaultListener = new DefaultTraceListener();
                                defaultListener.IndentLevel = indentLevel;
                                defaultListener.IndentSize = indentSize;
                                listeners.Add(defaultListener);
                            }
                        }
                    }
                }
                return listeners;
            }
        }
 
        internal static string AppName {
            get {
                if (appName == null) {
                    new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Assert();
                    appName = Path.GetFileName(Environment.GetCommandLineArgs()[0]);
                }
                return appName;
            }
        }
        
        public static bool AutoFlush { 
            get { 
                InitializeSettings();
                return autoFlush; 
            }
 
            set {
                InitializeSettings();    
                autoFlush = value;
            }
        }
 
        public static bool UseGlobalLock { 
            get { 
                InitializeSettings();
                return useGlobalLock; 
            }
 
            set {
                InitializeSettings();    
                useGlobalLock = value;
            }
        }
        
        public static int IndentLevel {
            get { return indentLevel; }
 
            set {
                // Use global lock
                lock (critSec) {
                    // We don't want to throw here -- it is very bad form to have debug or trace
                    // code throw exceptions!
                    if (value < 0) {
                        value = 0;
                    }
                    indentLevel = value;
                    
                    if (listeners != null) {
                        foreach (TraceListener listener in Listeners) {
                            listener.IndentLevel = indentLevel;
                        }
                    }
                }
            }
        }
 
        public static int IndentSize {
            get { 
                InitializeSettings();
                return indentSize; 
            }
            
            set {
                InitializeSettings();    
                SetIndentSize(value);
            }
        }
 
        static void SetIndentSize(int value) {
            // Use global lock
            lock (critSec) {                
                // We don't want to throw here -- it is very bad form to have debug or trace
                // code throw exceptions!            
                if (value < 0) {
                    value = 0;
                }
 
                indentSize = value;
                
                if (listeners != null) {
                    foreach (TraceListener listener in Listeners) {
                        listener.IndentSize = indentSize;
                    }
                } 
            }
        }
 
        public static void Indent() {
            // Use global lock
            lock (critSec) {
                InitializeSettings();
                if (indentLevel < Int32.MaxValue) {
                    indentLevel++;
                }
                foreach (TraceListener listener in Listeners) {
                    listener.IndentLevel = indentLevel;
                }
            }
        }
 
        public static void Unindent() {
            // Use global lock
            lock (critSec) {
                InitializeSettings();
                if (indentLevel > 0) {
                    indentLevel--;
                }
                foreach (TraceListener listener in Listeners) {
                    listener.IndentLevel = indentLevel;
                }
            }
        }
 
        public static void Flush() {
            if (listeners != null) {
                if (UseGlobalLock) {
                    lock (critSec) {
                        foreach (TraceListener listener in Listeners) {
                            listener.Flush();
                        }            
                    }
                }
                else {
                    foreach (TraceListener listener in Listeners) {
                        if (!listener.IsThreadSafe) {
                            lock (listener) {
                                listener.Flush();
                            }
                        }
                        else {
                            listener.Flush();
                        }
                    }            
                }
            }
        }
 
        public static void Close() {
            if (listeners != null) {
                // Use global lock
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.Close();
                    }            
                }
            }
        }
 
        public static void Assert(bool condition) {
            if (condition) return;
            Fail(string.Empty);
        }
 
        public static void Assert(bool condition, string message) {
            if (condition) return;
            Fail(message);
        }
 
        public static void Assert(bool condition, string message, string detailMessage) {
            if (condition) return;
            Fail(message, detailMessage);
        }
 
        public static void Fail(string message) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.Fail(message);
                        if (AutoFlush) listener.Flush();
                    }            
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.Fail(message);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.Fail(message);
                        if (AutoFlush) listener.Flush();
                    }
                }            
            }
        }        
 
        public static void Fail(string message, string detailMessage) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.Fail(message, detailMessage);
                        if (AutoFlush) listener.Flush();
                    }            
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.Fail(message, detailMessage);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.Fail(message, detailMessage);
                        if (AutoFlush) listener.Flush();
                    }
                }            
            }
        }        
 
        private static void InitializeSettings() {
            // we want to redo this logic exactly once if the last time we entered the config
            // system was still initializing.  (ASURT 111941, VSWhidbey 149552)
            if (!settingsInitialized || (defaultInitialized && DiagnosticsConfiguration.IsInitialized())) {
                // we should avoid 2 threads altering the state concurrently for predictable behavior
                // though it may not be strictly necessary at present
                lock(critSec) {
                    if (!settingsInitialized || (defaultInitialized && DiagnosticsConfiguration.IsInitialized())) {
                        defaultInitialized = DiagnosticsConfiguration.IsInitializing();
    
                        // Getting IndentSize and AutoFlush will load config on demand.
                        // If we load config and there are trace listeners added, we'll
                        // end up recursing, but that recursion will be stopped in
                        // DiagnosticsConfiguration.Initialize()           
                        SetIndentSize(DiagnosticsConfiguration.IndentSize);
                        autoFlush = DiagnosticsConfiguration.AutoFlush;
                        useGlobalLock = DiagnosticsConfiguration.UseGlobalLock;
                        settingsInitialized = true;
                    }
                }
            }
        }
 
        // This method refreshes all the data from the configuration file, so that updated to the configuration file are mirrored
        // in the System.Diagnostics.Trace class
        static internal void Refresh() {
            lock (critSec) {
                settingsInitialized = false;
                listeners = null;
            }
            InitializeSettings();
        }
 
    	public static void TraceEvent(TraceEventType eventType, int id, string format, params object[] args) {
 
            TraceEventCache EventCache = new TraceEventCache();
 
            if (UseGlobalLock) {
                lock (critSec) {
                    if (args == null) {
                        foreach (TraceListener listener in Listeners) {
                            listener.TraceEvent(EventCache, AppName, eventType, id, format);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        foreach (TraceListener listener in Listeners) {
                            listener.TraceEvent(EventCache, AppName, eventType, id, format, args);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                }
            }
            else {
                if (args == null) {
                    foreach (TraceListener listener in Listeners) {
                        if (!listener.IsThreadSafe) {
                            lock (listener) {
                                listener.TraceEvent(EventCache, AppName, eventType, id, format);
                                if (AutoFlush) listener.Flush();
                            }
                        }
                        else {
                            listener.TraceEvent(EventCache, AppName, eventType, id, format);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                }
                else {
                    foreach (TraceListener listener in Listeners) {
                        if (!listener.IsThreadSafe) {
                            lock (listener) {
                                listener.TraceEvent(EventCache, AppName, eventType, id, format, args);
                                if (AutoFlush) listener.Flush();
                            }
                        }
                        else {
                            listener.TraceEvent(EventCache, AppName, eventType, id, format, args);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                }
            }
    	}
    	
 
        public static void Write(string message) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.Write(message);
                        if (AutoFlush) listener.Flush();
                    }                        
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.Write(message);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.Write(message);
                        if (AutoFlush) listener.Flush();
                    }
                }                        
            }
        }
 
        public static void Write(object value) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.Write(value);
                        if (AutoFlush) listener.Flush();
                    }                        
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.Write(value);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.Write(value);
                        if (AutoFlush) listener.Flush();
                    }
                }                        
            }
        }
 
        public static void Write(string message, string category) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.Write(message, category);
                        if (AutoFlush) listener.Flush();
                    }                        
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.Write(message, category);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.Write(message, category);
                        if (AutoFlush) listener.Flush();
                    }
                }                        
            }
        }
 
        public static void Write(object value, string category) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.Write(value, category);
                        if (AutoFlush) listener.Flush();
                    }                        
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.Write(value, category);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.Write(value, category);
                        if (AutoFlush) listener.Flush();
                    }
                }                        
            }
        }
 
        public static void WriteLine(string message) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.WriteLine(message);
                        if (AutoFlush) listener.Flush();
                    }                        
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.WriteLine(message);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.WriteLine(message);
                        if (AutoFlush) listener.Flush();
                    }
                }                        
            }
        }
 
        public static void WriteLine(object value) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.WriteLine(value);
                        if (AutoFlush) listener.Flush();
                    }                        
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.WriteLine(value);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.WriteLine(value);
                        if (AutoFlush) listener.Flush();
                    }
                }                        
            }
        }
 
        public static void WriteLine(string message, string category) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.WriteLine(message, category);
                        if (AutoFlush) listener.Flush();
                    }                        
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.WriteLine(message, category);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.WriteLine(message, category);
                        if (AutoFlush) listener.Flush();
                    }
                }                        
            }
        }
 
        public static void WriteLine(object value, string category) {
            if (UseGlobalLock) {
                lock (critSec) {
                    foreach (TraceListener listener in Listeners) {
                        listener.WriteLine(value, category);
                        if (AutoFlush) listener.Flush();
                    }                        
                }
            }
            else {
                foreach (TraceListener listener in Listeners) {
                    if (!listener.IsThreadSafe) {
                        lock (listener) {
                            listener.WriteLine(value, category);
                            if (AutoFlush) listener.Flush();
                        }
                    }
                    else {
                        listener.WriteLine(value, category);
                        if (AutoFlush) listener.Flush();
                    }
                }                        
            }
        }
 
        public static void WriteIf(bool condition, string message) {
            if (condition)
                Write(message);
        }
 
        public static void WriteIf(bool condition, object value) {
            if (condition)
                Write(value);
        }
 
        public static void WriteIf(bool condition, string message, string category) {
            if (condition)
                Write(message, category);
        }
 
        public static void WriteIf(bool condition, object value, string category) {
            if (condition)
                Write(value, category);
        }
 
        public static void WriteLineIf(bool condition, string message) {
            if (condition)
                WriteLine(message);
        }
 
        public static void WriteLineIf(bool condition, object value) {
            if (condition)
                WriteLine(value);
        }
 
        public static void WriteLineIf(bool condition, string message, string category) {
            if (condition)
                WriteLine(message, category);
        }
 
        public static void WriteLineIf(bool condition, object value, string category) {
            if (condition)
                WriteLine(value, category);
        }
    }
}