【问题标题】:Multiple TraceSource instances writing to single FileLogTraceListener多个 TraceSource 实例写入单个 FileLogTraceListener
【发布时间】:2014-05-03 14:00:28
【问题描述】:

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

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

在这种情况下,是通过 app.config / web.config 中的<sharedListers> 添加侦听器而不是像我在下面的代码中那样以编程方式添加侦听器吗?

我使用了这个完美运行的测试代码 - 写出预期的日志条目数。在我将这个策略部署到生产环境之前,我只是想要一些指导。

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 "},
            };
        }
    }
}

【问题讨论】:

    标签: c# .net multithreading logging system.diagnostics


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      如果现有文件被锁定,FileLogTraceListener 将写入一个全新的文件。因此,您可以获得日志文件的集合,这可能是您想要的,也可能不是。

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

      【讨论】:

      • 是的,我看到 FileLogTraceListener 最终会创建多个日志文件(带有 ~n.log 后缀),这对于诊断来说不是很方便。看来我需要使用全局锁来同步访问。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-24
      • 1970-01-01
      • 2014-08-18
      • 1970-01-01
      • 2017-05-05
      • 2011-09-02
      相关资源
      最近更新 更多