C# 多个TraceSource实例写入单个FileLogTraceListener

C# 多个TraceSource实例写入单个FileLogTraceListener,c#,.net,multithreading,logging,system.diagnostics,C#,.net,Multithreading,Logging,System.diagnostics,我正在探索将基于TraceSource的日志记录添加到我的ASP.NET应用程序中。我需要有选择地控制不同代码组件的源代码级别的能力,因此需要多个源代码。所有TraceSource实例都将写入单个派生侦听器 这种策略能否在多线程环境中产生性能/并发访问问题? 从MSDN描述来看,TraceSource和FileLogTraceListener似乎都是线程安全的。有没有人有过与此相反的经历 在这种情况下,通过app.config/web.config中的添加侦听器与我在下面的代码中以编程方式添加侦

我正在探索将基于TraceSource的日志记录添加到我的ASP.NET应用程序中。我需要有选择地控制不同代码组件的源代码级别的能力,因此需要多个源代码。所有TraceSource实例都将写入单个派生侦听器

这种策略能否在多线程环境中产生性能/并发访问问题? 从MSDN描述来看,TraceSource和FileLogTraceListener似乎都是线程安全的。有没有人有过与此相反的经历

在这种情况下,通过app.config/web.config中的
添加侦听器与我在下面的代码中以编程方式添加侦听器相比,是否更可取

我使用了这个测试代码,它工作得非常好——写出了预期的日志条目数。只是想在我将此策略部署到生产中之前得到一些指导

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.VisualBasic.Logging;

namespace SourcesListeners
{
    class Program
    {
        [STAThread]
        static void Main()
        {
            const string baseFileName = @"test-log";
            var threads = 10*Environment.ProcessorCount;
            const int iterationsPerThread = 4000;

            var listener = new DailyRollingFileListener(@".\", baseFileName);
            {
                Parallel.For(0, threads, i =>
                {
                    var source = new TraceSource(string.Format("source-{0}", i), SourceLevels.All);
                    source.Listeners.Clear();
                    source.Listeners.Add(listener);
                    source.TraceEvent(TraceEventType.Information, 0, "Created");

                    for (var k = 0; k < iterationsPerThread; ++k)
                    {
                        source.TraceEvent(TraceEventType.Information, 0, "thread: {0}, iteration: {1}", i, k);
                    }
                });
            }
        }

        class DailyRollingFileListener : FileLogTraceListener
        {
            public DailyRollingFileListener(
                string customLocation, string baseFileName,
                bool autoFlush = true)
            {
                CustomLocation = customLocation;
                BaseFileName = baseFileName;
                AutoFlush = autoFlush;
                LogFileCreationSchedule = LogFileCreationScheduleOption.Daily;
                Append = false;
                MaxFileSize = 40*1024*1024;
            }

            public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
            {
                var entry = string.Format("{0:yyyy-MM-dd hh:mm:ss.fff}Z {1,4} {2,-5} {3} {4}",
                    eventCache.DateTime,
                    eventCache.ThreadId,
                    GetSeverity(eventType),
                    source,
                    message);
                base.WriteLine(entry);
            }

            public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args)
            {
                var message = args != null ? string.Format(format, args) : format;
                if (eventCache != null)
                {
                    TraceEvent(eventCache, source ?? string.Empty, eventType, id, message);
                }
                else
                {
                    base.WriteLine(string.Format("{0} {1} {2}", GetSeverity(eventType), source ?? string.Empty, message));
                }
            }

            private static string GetSeverity(TraceEventType eventType)
            {
                string value;
                return SeverityLevel.TryGetValue(eventType, out value) ? value : eventType.ToString().ToUpper();
            }

            private static readonly Dictionary<TraceEventType, string> SeverityLevel =
                new Dictionary<TraceEventType, string>
            {
                {TraceEventType.Critical, "FATAL"},
                {TraceEventType.Error, "ERROR"},
                {TraceEventType.Warning, "WARN "},
                {TraceEventType.Information, ""},
                {TraceEventType.Verbose, "DEBUG"},
                {TraceEventType.Start, "ENTRY"},
                {TraceEventType.Stop, "EXIT "},
            };
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Threading.Tasks;
使用Microsoft.VisualBasic.Logging;
命名空间源侦听器
{
班级计划
{
[状态线程]
静态void Main()
{
常量字符串baseFileName=@“测试日志”;
var threads=10*Environment.ProcessorCount;
const int iterationsPerThread=4000;
var listener=new dailrollingfilelistener(@“\”,baseFileName);
{
对于(0,线程,i=>
{
var source=new-TraceSource(string.Format(“source-{0}”,i),SourceLevels.All);
source.Listeners.Clear();
source.Listeners.Add(listener);
source.TraceEvent(TraceEventType.Information,0,“已创建”);
for(var k=0;k
如果现有文件被锁定,FileLogTraceListener将写入一个全新的文件。因此,您可以获得日志文件的集合,这些文件可能是您想要的,也可能不是


数据库对并发访问更具弹性,但您可能会遇到死锁,尤其是在有事务正在进行(并且每个人都试图写入同一个表)的情况下。

为了避免创建多个跟踪文件,您可以在刷新后处理侦听器以释放跟踪文件。

是,我看到FileLogTraceListener最终创建了多个日志文件(后缀为~n.log),这对于诊断来说不是很方便。看起来我需要使用全局锁同步访问。