Система, над которой я сейчас работаю, использует управляемую событиями архитектуру и обмен сообщениями, так что большинство действий в нашей системе являются результатом команды и приводят к событиям (как отправляемые классы DTO, а не как стандартное событие делегата). Мы прикрепляем обработчики событий, единственной целью которых является обработка журналов. Этот дизайн помогает нам не повторяться, а также не нужно изменять существующий код для добавления / изменения функциональности.
Вот пример одного такого класса журналирования, который обрабатывает все события, которые должны регистрироваться из узкой части нашего приложения (те, которые касаются одного конкретного источника контента, из которого мы импортируем).
Я не обязательно скажу, что это практический опыт, так как я, кажется, передумал, что и как часто регистрировать - и каждый раз, когда мне нужно использовать журнал для диагностики проблемы, я неизбежно нахожу способы усовершенствования Информация, которую я записываю.
Я скажу, однако, что запись соответствующей информации (особенно в режиме поиска Ctrl-F / find) является наиболее важной частью.
Вторая наиболее важная часть - это удаление кода регистрации из вашей основной логики - он может сделать метод уродливым, длинным и запутанным очень быстро.
public class MctLogger :
IEventHandler<StoryImported>,
IEventHandler<StoryScanned>,
IEventHandler<SourceDirectoryMissing>,
IEventHandler<SourceDirectoryAccessError>,
IEventHandler<CannotCreateScannedStoryDirectory>,
IEventHandler<CannotReadStoryDocument>,
IEventHandler<StorySkippedPastCutoff>,
IEventHandler<StorySkippedDuplicateUniqueId>,
IEventHandler<StorySkippedByFilter>
{
public void Observe(StoryImported e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryImported");
log.Info("Story Unique ID: {Story.UniqueId}, Content ID: {ContentId}, Title: {Story.Headline}".SmartFormat(e));
}
public void Observe(StoryScanned e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryScanned");
log.Info("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
}
public void Observe(SourceDirectoryMissing e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryMissing");
log.Error("Directory: " + e.Directory);
}
public void Observe(SourceDirectoryAccessError e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryAccessError");
log.Error(e.Exception, "Exception: " + e.Exception.Message);
}
public void Observe(CannotCreateScannedStoryDirectory e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotCreateScannedStoryDirectory");
log.Error(e.Exception, "Directory: {Directory}, Exception: {Exception.Message}".SmartFormat(e));
}
public void Observe(CannotReadStoryDocument e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotReadStoryDocument");
if (e.Exception == null) {
log.Warn("File: {FilePath}".SmartFormat(e));
}
else {
log.Warn(e.Exception, "File: {FilePath}, Exception: {Exception.Message}".SmartFormat(e));
}
}
public void Observe(StorySkippedPastCutoff e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedPastCutoff");
log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
}
public void Observe(StorySkippedDuplicateUniqueId e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedDuplicateUniqueId");
log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
}
public void Observe(StorySkippedByFilter e)
{
var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedByFilter");
log.Warn("Story Unique ID: {Story.UniqueId}, Reason: {Reason}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
}
}