2009-09-24 3 views
0

Мы пытаемся настроить серверный процесс, чтобы каждый раз, когда он получал запрос, он регистрировал этот запрос в NEW filename.Изменение log4net FileAppender во время регистрации

Процесс, как правило, однопоточный, но мы не можем гарантировать, что ни одна другая нить где-то в коде не будет пытаться писать что-то в log4net.

То, что казалось, работает это:

В первый раз мы получаем запрос, мы настраиваем «PerRequest» FileAppender следующим образом:

fileAppender = new FileAppender(); 
log.InfoFormat("Initializing log4net per request logging"); 
log4net.Layout.PatternLayout layout = new Layout.PatternLayout("%date %property{processid} %property{username} %-5level %logger - %message%newline"); 
fileAppender.Layout = layout; 
layout.ActivateOptions(); 
fileAppender.AppendToFile = true; 
fileAppender.Name = "PerRunLogger"; 
fileAppender.File = makeNewRequestLogName(); // Returns a unique filename (uses a Guid) 
log.InfoFormat("Configured PerRequest logger to log to '{0}'", fileAppender.File); 
fileAppender.ActivateOptions(); 
log4net.Config.BasicConfigurator.Configure(fileAppender); 

Тогда каждый раз, когда мы получаем новый запрос, мы Выполните следующие действия:

fileAppender.File = makeNewRequestLogName(); 
log.InfoFormat("Configured PerRequest logger to log to '{0}'", fileAppender.File); 
fileAppender.ActivateOptions(); 

в конце запроса, мы «настроить» регистратор PerRequest для входа в один файл, так как мы не смогли найти удовлетворительный способ отключить его ..

Это работало очень хорошо ... Но при большой нагрузке мы начали замечать, что в файле журнала PerRequest часто бывают огромные куски «отсутствующих» строк журнала. например что-то вроде этого:

2009-09-23 19:17:17,133 4332 hollingp DEBUG PostProcessInfrastructure.PostProcessRunner - Started post processing 
* normal log lines here, omitted for brevity * 
2009-09-23 19:17:36,414 4332 hollingp DEBUG PluginRegistry.PostProcessVersions.PostProcessPluginCacheVersion - About to run pub_GetPostProcessingVersion stored proc 

*Normally lots of log lines here, but every now and then, NOTHING * 

2009-09-23 19:17:37,742 4332 hollingp DEBUG PostProcessInfrastructure.PostProcessRunner - Finished post processing 

Там нет хорошего объяснения того, что мы видим в лог-файл - нет пути код (даже если исключение), что могло бы объяснить «недостающее» бревном линии - что-то (довольно много всего) должен был быть зарегистрирован на этом потоке между строкой в ​​19:17:36 и строкой в ​​19:17:37.

По общему признанию, вся эта техника является немного изворотливой, но мы не могли придумать другой способ сделать это.

Итак, первый вопрос: есть ли лучший способ достичь того, чего мы хотим?

Второй вопрос: может ли кто-нибудь объяснить, что может произойти? Подозрение заключается в том, что существует некоторая безопасность потока/блокировка, которая должна выполняться, но где? Что нужно заблокировать, если это так?

Там нет риска другого процесса пытается войти в тот же файл, потому что, как комментарий в коде указывает на то, мы выделяем имя файла журнала с помощью GUID - нет никаких шансов, что другой процесс пытается войти в тот же файл ... Но другой поток? Мы не можем это исключить.

ответ

2

От log4net FAQ:

Многие разработчики столкнулись с проблемой различения вывода журнала, происходящих из того же класса, но с разными запросами клиентов. Они придумывают изобретательные механизмы, чтобы развернуть выход журнала в разные файлы. В большинстве случаев это неправильный подход.

Проще использовать свойство контекста или стек (ThreadContext). Как правило, при запуске обработки запроса клиента ThreadContext.Properties ["ID"] = "XXX" запрашивает конкретную информацию клиента, такую ​​как имя хоста клиента, идентификатор или любую другую различающуюся информацию. После этого вывод журнала будет автоматически включать данные контекста, чтобы вы могли отличать журналы от разных клиентских запросов, даже если они выводятся в один и тот же файл.

Дополнительную информацию см. В разделах ThreadContext и PatternLayout.

+0

Да, я думаю, это лучший ответ ... но любопытное дерьмо, что они не поставляют своего рода «мультиплексирование», которое может переключиться на разные имена файлов на основе свойств контекста. «grepping» через массу файлов журналов, пытающихся собрать все строки, связанные с одним конкретным запросом, является кошмаром поддержки. Более длинный срок, мы собираемся построить сервер журналов, который расщепляет вещи для нас. –

+0

Правда, но это сокращается в обоих направлениях - если вы когда-нибудь сталкиваетесь с проблемой, когда основная причина - это несколько параллельных сеансов, взаимодействующих каким-то образом, этот комбинированный журнал будет бесценным. И вместо того, чтобы писать полномасштабный пользовательский сервер журналов, вы можете довольно просто написать инструмент командной строки для разделения файла журнала. Затем, когда у вас есть журнал, который вы хотите проанализировать, просто отбросьте его на .exe, и он выплевывает отдельные журналы. –

+0

Этот «инструмент командной строки» для разметки журналов может занять * длинные * минуты для запуска, хотя –

2

Итак, первый вопрос: есть ли лучший способ достичь того, чего мы хотим?

Нужно ли это отдельный файл за запрос?

Если нет, то как создать собственный собственный шаблон и сделать детали запроса частью шаблона журнала? An example Google нашел.

Если да, то как насчет расширения RollingFileAppender и измените условие нового файла, чтобы вместо того, чтобы быть связанным с размером файла (или что-то еще), оно основано на запросе?

Предполагаю, вы уже экспериментировали с LockingModel?

+0

Спасибо, что посмотрим, есть ли способ «взломать» RollingFileAppender таким образом. –