File: System\Diagnostics\DefaultTraceListener.cs
Web Access
Project: src\src\libraries\System.Diagnostics.TraceSource\src\System.Diagnostics.TraceSource.csproj (System.Diagnostics.TraceSource)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
 
namespace System.Diagnostics
{
    /// <devdoc>
    ///    <para>Provides
    ///       the default output methods and behavior for tracing.</para>
    /// </devdoc>
    public class DefaultTraceListener : TraceListener
    {
        private bool _assertUIEnabled;
        private bool _settingsInitialized;
        private string? _logFileName;
 
        /// <devdoc>
        /// <para>Initializes a new instance of the <see cref='System.Diagnostics.DefaultTraceListener'/> class with
        ///    Default as its <see cref='System.Diagnostics.TraceListener.Name'/>.</para>
        /// </devdoc>
        public DefaultTraceListener()
            : base("Default")
        {
        }
 
        public bool AssertUiEnabled
        {
            get
            {
                if (!_settingsInitialized) InitializeSettings();
                return _assertUIEnabled;
            }
            set
            {
                if (!_settingsInitialized) InitializeSettings();
                _assertUIEnabled = value;
            }
        }
 
        public string? LogFileName
        {
            get
            {
                if (!_settingsInitialized) InitializeSettings();
                return _logFileName;
            }
            set
            {
                if (!_settingsInitialized) InitializeSettings();
                _logFileName = value;
            }
        }
 
        /// <devdoc>
        ///    <para>
        ///       Emits or displays a message
        ///       and a stack trace for an assertion that
        ///       always fails.
        ///    </para>
        /// </devdoc>
        public override void Fail(string? message)
        {
            Fail(message, null);
        }
 
        /// <devdoc>
        ///    <para>
        ///       Emits or displays messages and a stack trace for an assertion that
        ///       always fails.
        ///    </para>
        /// </devdoc>
        public override void Fail(string? message, string? detailMessage)
        {
            string stackTrace;
            try
            {
                stackTrace = new StackTrace(fNeedFileInfo: true).ToString();
            }
            catch
            {
                stackTrace = "";
            }
            WriteAssert(stackTrace, message, detailMessage);
            if (AssertUiEnabled)
            {
                DebugProvider.FailCore(stackTrace, message, detailMessage, "Assertion Failed");
            }
        }
 
        private void InitializeSettings()
        {
            // don't use the property setters here to avoid infinite recursion.
            _assertUIEnabled = DiagnosticsConfiguration.AssertUIEnabled;
            _logFileName = DiagnosticsConfiguration.LogFileName;
            _settingsInitialized = true;
        }
 
        private void WriteAssert(string stackTrace, string? message, string? detailMessage)
        {
            WriteLine(SR.DebugAssertBanner + Environment.NewLine
                   + SR.DebugAssertShortMessage + Environment.NewLine
                   + message + Environment.NewLine
                   + SR.DebugAssertLongMessage + Environment.NewLine
                   + detailMessage + Environment.NewLine
                   + stackTrace);
        }
 
        /// <devdoc>
        ///    <para>
        ///       Writes the output using <see cref="System.Diagnostics.Debug.Write(string)"/>.
        ///    </para>
        /// </devdoc>
        public override void Write(string? message)
        {
            Write(message, useLogFile: true);
        }
 
        /// <devdoc>
        ///    <para>
        ///       Writes the output followed by a line terminator using <see cref="System.Diagnostics.Debug.Write(string)"/>.
        ///    </para>
        /// </devdoc>
        public override void WriteLine(string? message)
        {
            WriteLine(message, useLogFile: true);
        }
 
        private void WriteLine(string? message, bool useLogFile)
        {
            if (NeedIndent)
                WriteIndent();
 
            // The concat is done here to enable a single call to Write
            Write(message + Environment.NewLine, useLogFile);
            NeedIndent = true;
        }
 
        private void Write(string? message, bool useLogFile)
        {
            message ??= string.Empty;
 
            if (NeedIndent && message.Length != 0)
            {
                WriteIndent();
            }
 
            DebugProvider.WriteCore(message);
 
            if (useLogFile && !string.IsNullOrEmpty(LogFileName))
            {
                WriteToLogFile(message);
            }
        }
 
        private void WriteToLogFile(string message)
        {
            try
            {
                File.AppendAllText(LogFileName!, message);
            }
            catch (Exception e)
            {
                WriteLine(SR.Format(SR.ExceptionOccurred, LogFileName, e), useLogFile: false);
            }
        }
    }
}