Sistem yang sedang saya kerjakan menggunakan arsitektur dan pesan yang digerakkan oleh peristiwa, sehingga sebagian besar tindakan dalam sistem kami adalah hasil dari suatu perintah dan hasilnya adalah acara (seperti kelas DTO yang dikirim, bukan acara delegasi standar). Kami melampirkan penangan acara yang tujuan utamanya adalah menangani pencatatan. Desain ini membantu kita untuk tidak mengulangi diri kita sendiri, dan juga tidak perlu memodifikasi kode yang ada untuk menambah / mengubah fungsionalitas.
Berikut adalah contoh dari salah satu kelas logging tersebut, yang menangani semua peristiwa yang akan dicatat dari bagian sempit aplikasi kami (yang berhubungan dengan satu sumber konten tertentu yang kami impor).
Saya tidak akan serta merta mengatakan ini adalah praktik terbaik, karena saya tampaknya berubah pikiran tentang apa dan bagaimana cara mencatat sering - dan setiap kali saya perlu menggunakan log untuk mendiagnosis masalah, saya pasti menemukan cara untuk melakukan perbaikan pada informasi yang saya rekam.
Saya akan mengatakan, bahwa merekam informasi yang bersangkutan (terutama dalam cara Ctrl-F / findableable) adalah bagian yang paling penting.
Bagian terpenting kedua adalah menjauhkan kode logging dari logika utama Anda - itu dapat membuat metode jelek dan panjang dan berbelit-belit dengan sangat cepat.
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));
}
}