Quick Trace Code

public static class QuickTrace
{
    static TextWriterTraceListener textWriterTraceListener;

    public static void WriteLog(string strLog, string category = "")
    {
        if (textWriterTraceListener is null)
        {
            textWriterTraceListener = new TextWriterTraceListener("D:\\" + "ProjectOperate_" + DateTime.Now.ToString("yyyy-MM-dd") + ".log");
            Trace.Listeners.Add(textWriterTraceListener);
            Trace.AutoFlush = true;
        }
        if (string.IsNullOrEmpty(category))
        {
            category = "Category";
        }
        Trace.WriteLine(DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff ") + category + " " + strLog + Environment.NewLine);

    }

}

Listeners

The Listeners collection is shared by both the Debug and the Trace classes; adding a trace listener to either class adds the listener to both

EventLog

事件日志有两个重要的属性,一个是事件来源,一个是事件日志名,这两个在创建的时候就已经一一对应好了,后期是不能改的。当添加日志时,不指定日志名时,系统会自动搜索对应的事件来源所对应的日志名。创建事件来源需要管理员权限。 EventLog eventLog1 = new EventLog(); if (!EventLog.SourceExists(“TestMichaelSource”)) { EventLog.CreateEventSource( “TestMichaelSource”, “TestMichaelNewLog”); } eventLog1.Source = “TestMichaelSource”; //eventLog1.Log = “TestMichaelNewLog”; eventLog1.WriteEntry(“Monitoring the System”, EventLogEntryType.Information, eventId++); eventLog1.WriteEntry(“In OnStop.”); eventLog1.WriteEntry(“Monitoring the System”, EventLogEntryType.Information, eventId++); eventLog1.WriteEntry(“In OnStop.”);

Trace Category

Trace.WriteLine使用Category时,如果需要使用Filter,那么它的Filter级别是Verbose,原因不明。 textWriterTraceListener.Filter = new EventTypeFilter(SourceLevels.Verbose); Trace.WriteLine(“WriteLine”, “Category”);

AutoFlush,Close

The trace listeners use the values of the Trace class properties Indent, IndentSize, and AutoFlush to format trace output. 所以可以通过设置Trace.AutoFlush的值启用所有的TraceListener自动Flush,而不需要再手动Flush。但是对于AutoFlush,如果使用的是TextWriterTraceListener,日志文件并不会自动关闭,需要手动Close才会关闭。

Trace.AutoFlush = true;

//traceSource.Flush();
//Calling a Write or WriteLine method after calling Close automatically reopens the stream.
traceSource.Close();

<configuration>  
  <system.diagnostics>  
    <trace autoflush="false" indentsize="3" />  
  </system.diagnostics>  
</configuration> 

Trace.UseGlobalLock

The global lock is always used if the trace listener is not thread safe, regardless of the value of UseGlobalLock.

TraceSource

TraceSource.defaultLevel is used to initialize the TraceSource.Switch.

TraceSource.TraceEvent

The TraceEvent method calls the ShouldTrace method of the SourceSwitch object returned by the Switch property. If ShouldTrace returns true, TraceEvent calls the corresponding TraceEvent method of each listener. Otherwise, TraceEvent returns without calling the listeners’ methods.

TextWriterTraceListener.Filter (SourceFilter)

通过设置TextWriterTraceListener.Filter的名称,可以过滤TraceSource。如果程序中只有一个TraceSource(通常情况下,建议只有一个TraceSource),则直接设置为默认null即可,此时如果希望设置,SourceFilter的名称必须和TraceSource名称一致。如果有多个TraceSource,那么TraceSource的名称必须不一样,此时可以通过SourceFilter的名称过滤只显示哪些TraceSource触发的日志事件,哪怕TraceSource已经添加了该TextWriterTraceListener,但是加入TextWriterTraceListener的Filter对象设置的名称和TraceSource名称不一致,TextWriterTraceListener也不会记录该TraceSource触发的日志事件。所以说TraceSource可以过滤日志等级,TextWriterTraceListener可以过滤日志源。

textWriterTraceListener.Filter = new SourceFilter("PickMasterUtility");

traceSource = new TraceSource("PickMasterUtility", SourceLevels.All);
traceSource.Switch = sourceSwitch;
traceSource.Listeners.Add(textWriterTraceListener);

TextWriterTraceListener.Filter (EventTypeFilter)

除了通过设置TraceSource.TraceEvent过滤日志等级外,还可以在每个TraceListener中再次过滤日志等级。

textWriterTraceListener = new TextWriterTraceListener(logFilePath, "RIS2Writer");
textWriterTraceListener.Filter = new EventTypeFilter( SourceLevels.Error);

TraceListener.TraceOutputOptions

The TraceOptions enumeration is not used by the following classes and methods:

  1. The EventLogTraceListener class, because it can cause a large volume of data to be written to the log.
  2. The Write and WriteLine methods of the ConsoleTraceListener, DefaultTraceListener, and TextWriterTraceListener classes.
  3. The Write and WriteLine methods of the TraceListener class when they are not overridden in a derived class.

Trace Filter

Trace对应的Listener可以使用Filter功能,对应下面三个函数。 Trace.TraceInformation(“TraceInformation”); Trace.TraceError(“TraceError”); Trace.TraceWarning(“TraceWarning”);

Release配置下,如果使用Trace输出日志,需要选中/d:TRACE功能。

日志文件夹

RIS2 Log

public static class RIS2Log
{
    private static string logFileDirectory;

    private static string logFileName;

    private static bool logFileNameDateSuffix = true;

    private static long archiveSize=100000000;

    private static TextWriterTraceListener textWriterTraceListener;

    private static EventLogTraceListener eventLogTraceListener;

    private static bool useTraceSource = true;

    private static TraceSource traceSource = null;

    private static SourceSwitch sourceSwitch = new SourceSwitch("RIS2Log", SourceLevels.Information.ToString());
     
    private static void ArchiveLogFile(string logFilePath)
    {
        try
        {
            if (File.Exists(logFilePath))
            {
                long fileSize = new FileInfo(logFilePath).Length;
                if (fileSize > archiveSize)
                {
                    File.Copy(logFilePath, logFilePath + ".old", true);
                    File.Delete(logFilePath);
                }
            }
        }
        catch (Exception)
        {
        }

    }

    /// <summary>
    /// The default log file name is "RIS2.log".
    /// When the size of the log file is more than 100MB, it will be copied as file name "RIS2.log.old".
    /// After copied, the original log file will be deleted.
    /// </summary>
    /// <param name="fileDirectory">Directory of the log file</param>
    /// <param name="useDateSuffix">log file name with date suffix</param>
    public static void InitLogTrace(string fileDirectory, bool useDateSuffix)
    {
        logFileDirectory = fileDirectory;
        logFileName = "RIS2.log";
        logFileNameDateSuffix = useDateSuffix;
        if (logFileNameDateSuffix)
        {
            logFileName = $"RIS2_{DateTime.Now:yyyy-MM-dd}.log";
        }
        
        string logFilePath = Path.Combine(logFileDirectory, logFileName);

        ArchiveLogFile(logFilePath);
                   
        try
        {
            textWriterTraceListener = new TextWriterTraceListener(logFilePath);
        }
        catch (Exception)
        {
            throw;
        }
        eventLogTraceListener = new EventLogTraceListener("RIS2");

        if (useTraceSource)
        {
            traceSource = new TraceSource("PickMasterUtility", SourceLevels.All);
            traceSource.Switch = sourceSwitch;
            traceSource.Listeners.Add(textWriterTraceListener);
            //traceSource.Listeners.Add(eventLogTraceListener);
        }
        else
        {
            Trace.AutoFlush = true;
            Trace.Listeners.Add(textWriterTraceListener);
            //Trace.Listeners.Add(eventLogTraceListener);
        }
    }

    public static void WriteLog(string strLog, string category = "")
    {
        try
        {
            string logFilePath = Path.Combine(logFileDirectory, logFileName);

            ArchiveLogFile(logFilePath);

            if (string.IsNullOrEmpty(category))
            {
                category = "Category";
            }
            if (traceSource == null)
            {
                Trace.WriteLine(DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff ") + category + " " + strLog + Environment.NewLine);
                //Trace.WriteLineIf(sourceSwitch.Level>= SourceLevels.Information,DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff ") + category + " " + strLog + Environment.NewLine);
            }
            else
            {
                //foreach (TraceListener item in traceSource.Listeners)
                //{
                //    item.WriteLine(DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff ") + category + " " + strLog + Environment.NewLine);
                //    item.Flush();
                //}
                traceSource.TraceEvent(TraceEventType.Information, 0, DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff ") + category + " " + strLog + Environment.NewLine);
                traceSource.Flush();
                //Calling a Write or WriteLine method after calling Close automatically reopens the stream.
                traceSource.Close();
            }
        }
        catch (Exception)
        {
        }

    }

    public static void WriteLog(Exception ex, string category = "")
    {
        try
        {
            string logFilePath = Path.Combine(logFileDirectory, logFileName);

            ArchiveLogFile(logFilePath);

            if (string.IsNullOrEmpty(category))
            {
                category = "Category";
            }
            if (traceSource == null)
            {
                Trace.WriteLine(DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff ") + category + " " + ex.Message + Environment.NewLine + "Source:" + ex.Source + ", Type:" + ex.GetType().FullName + Environment.NewLine + ex.StackTrace + Environment.NewLine);
                //Trace.WriteLineIf(sourceSwitch.Level >= SourceLevels.Information, DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff ") + category + " " + ex.Message + Environment.NewLine + "Source:" + ex.Source + ", Type:" + ex.GetType().FullName + Environment.NewLine + ex.StackTrace + Environment.NewLine);
            }
            else
            {
                traceSource.TraceEvent(TraceEventType.Information, 0, DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff ") + category + " " + ex.Message + Environment.NewLine + "Source:" + ex.Source + ", Type:" + ex.GetType().FullName + Environment.NewLine + ex.StackTrace + Environment.NewLine);
                traceSource.Flush();
                //Calling a Write or WriteLine method after calling Close automatically reopens the stream.
                traceSource.Close();
            }
        }
        catch (Exception)
        {
        }

    }
}

Configuration file

The configuration file is located in the folder with the application executable and has the name of the application with the .config file name extension added. For example, the name of the configuration file for TraceSourceSample.exe is TraceSourceSample.exe.config.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<system.diagnostics>
		<sources>
			<source name="PickMasterUtility" switchName="RIS2Log" switchType="System.Diagnostics.SourceSwitch">
				<listeners>
					<add name="RIS2Writer"/>
					<remove name="Default"/>
				</listeners>
			</source>
		</sources>
		<switches>
			<add name="RIS2Log" value="Information"/>
		</switches>
		<sharedListeners>
			<add name="RIS2Writer" type="System.Diagnostics.TextWriterTraceListener" initializeData="log/RIS2.log">
				<filter type="System.Diagnostics.EventTypeFilter" initializeData="Information"/>
			</add>
		</sharedListeners>
	</system.diagnostics>
</configuration>