Несколько экземпляров TraceSource пишут в один FileLogTraceListener

Я пытаюсь добавить ведение журнала на основе TraceSource в свое приложение ASP.NET. Мне нужна возможность выборочно контролировать SourceLevels для разных компонентов кода, отсюда и потребность в нескольких источниках. Все экземпляры TraceSource будут записывать в один FileLogTraceListener. -производный слушатель.

Может ли эта стратегия создать проблемы с производительностью/одновременным доступом в многопоточной среде? Судя по описаниям MSDN, и TraceSource, и FileLogTraceListener кажутся потокобезопасными. У кого-нибудь есть опыт, который свидетельствует об обратном?

Является ли добавление слушателей через <sharedListers> в 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 "},
            };
        }
    }
}

person amo    schedule 25.03.2014    source источник


Ответы (2)


FileLogTraceListener будет записывать в совершенно новый файл, если существующий файл заблокирован. Таким образом, вы можете получить набор файлов журналов, которые могут быть вам нужны, а могут и нет.

Базы данных более устойчивы к параллельному доступу, но вы можете столкнуться с взаимоблокировкой, особенно если есть транзакции (и все пытаются писать в одну и ту же таблицу).

person MatthewMartin    schedule 14.04.2014
comment
Да, я вижу, что FileLogTraceListener в конечном итоге создает несколько файлов журнала (с суффиксом ~n.log), что не очень удобно для диагностики. Похоже, мне нужно будет синхронизировать доступ, используя глобальную блокировку. - person amo; 15.04.2014

Чтобы избежать создания нескольких файлов трассировки, вы можете удалить прослушиватель после сброса, чтобы освободить файл трассировки.

person rjlpz9119    schedule 16.03.2016