Dari perspektif desain, praktik apa yang terbaik untuk penebangan? [Tutup]

11

Saya ingin menambahkan logging ke aplikasi yang sedang saya kerjakan. Saya telah menambahkan logging sebelumnya, itu bukan masalah di sini.

Tetapi dari perspektif desain dalam bahasa berorientasi objek, apa praktik terbaik untuk logging yang mengikuti OOP dan pola?

Catatan: Saat ini saya melakukan ini dalam C #, jadi contoh dalam C # dipersilahkan. Saya juga ingin melihat contoh di Jawa dan Ruby.


Sunting: Saya menggunakan log4net. Saya hanya tidak tahu apa cara terbaik untuk memasangnya.

Edgar Gonzalez
sumber

Jawaban:

6

Praktik terbaik yang saya sarankan adalah menggunakan log4j daripada menggulirkan sendiri. (Yang telah porting dari Jawa ke C # dan Ruby, jadi itu berlaku untuk semua 3 bahasa yang Anda minati.)

Jika Anda membaca halaman manual itu, Anda akan menemukan beberapa praktik terbaik lainnya. Seperti menjadi ringan, dapat dikonfigurasi di luar aplikasi Anda, dapat naik dan turun logging untuk berbagai bagian aplikasi Anda secara mandiri, dan sebagainya.

btilly
sumber
5

Di tempat saya bekerja, kami menulis banyak aplikasi desktop .NET. Kami biasanya menerapkan 2 peristiwa dalam komponen kami, satu untuk mencatat informasi dan lainnya untuk mencatat pengecualian (meskipun kami sering membiarkan pengecualian muncul alih-alih meningkatkan peristiwa yang terpisah. Itu tergantung pada situasi). Dengan menggunakan arsitektur ini, tidak ada perpustakaan kami yang perlu tahu bagaimana logging diterapkan atau bagaimana informasi tersebut digunakan, disimpan atau dirawat. Kami kemudian memiliki aplikasi yang menangani acara logging dengan cara yang sesuai untuk aplikasi itu. Beberapa tahun yang lalu arsitektur ini membuat kami beralih dari menggunakan MS Enterprise Library logging ke komponen logging BitFactory transisi yang sangat sederhana.

Ali
sumber
+1 untuk menggunakan pola Acara / Pengamat: ubah pengamat, Anda telah mengubah logging
Matthieu M.
2

Secara pribadi, saya mengambil kerangka pilihan logging (dalam kasus saya, Entlib karena saya bekerja dengan .NET) dan menulis aspek AOP untuk logging.

Anda kemudian dapat mengaitkan metode / properti / kelas / namespaces dan menambahkan logging ke mereka tanpa mengacaukan sumbernya.

Steven Evers
sumber
Kedengarannya sangat menarik, tetapi saya memiliki keraguan tentang apa yang Anda bisa log dan bagaimana informasi log akan (yaitu lebih dari "hanya" instrumentasi metode). Senang melihat contoh kerja dari pendekatan ini untuk melihat apa yang bisa dan tidak bisa dilakukan. Terutama karena saya baru memulai aplikasi baru dan ingin melihat di mana / seberapa jauh saya bisa membawa ini.
Marjan Venema
@marjan Venema: Dokumentasi tajam postingan memiliki contoh aspek yang mencatat / memasukkan metode. doc.sharpcrafters.com/postsharp/2.0/##PostSharp.chm/html/… Dalam kasus Post sharp, ia menganyam kode dari atribut ke sumber saat build time, sehingga tidak mempengaruhi kinerja seperti yang dilakukan beberapa orang lain.
Steven Evers
1

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));
    }
}
quentin-starin
sumber
1

Seperti yang orang lain katakan, gunakan log4jatau log4netatau kerangka kerja logging lainnya yang dibangun dengan baik.

Saya cenderung sangat tidak suka kode logging menghalangi logika bisnis. Itu sebabnya saya gunakan Log4PostSharp. Itu berarti saya bisa menggunakan Pemrograman Berorientasi Aspek untuk menjelaskan metode seperti ini:

[Log(LogLevel.Info, "Counting characters.")]
int CountCharacters(string arg) 
{
    return arg.Length;
}

Atau setiap metode dalam perakitan seperti ini:

[assembly: Log(AttributeTargetTypes = "*", 
 EntryLevel = LogLevel.Debug, ExitLevel = LogLevel.Debug, 
 ExceptionLevel = LogLevel.Error)]
Peter K.
sumber
0

Saya tidak yakin apakah ada kerangka kerja yang melakukan hal ini, tetapi dari perspektif desain, saya akan memodelkan informasi yang perlu dimasukkan ke dalam tiga kategori utama:

  1. penelusuran tingkat metode
  2. pengecualian logging
  3. pengembang informasi run-time tambahan percaya bahwa sangat penting untuk menyelidiki jika terjadi kegagalan run-time (atau perilaku apa pun yang terkait dengan situasi run-time only).

Untuk dua kategori pertama, kerangka penebangan ideal saya harus menanganinya sebagai proses pembuatan pos dan transparan bagi pengembang. Akan lebih baik jika secara deklaratif menambahkan logging ke majelis, seperti berikut ini:

Trace YourNamespace.* [public methods|constructors]
{  # options
   ignore trivial methods,
   format: "{time stamp}: {method name}({parameter list})",
   condition: "{Context.Instance.UserID in (12432,23432)}",
}

Exception YourNamespace.Program.Main [unhandled exceptions]
{
  format: "{time stamp}: {Context.Instance.UserId} {exception}",
  action: die,  # options are throw, swallow,
}

Untuk kategori ke-3, programmer hanya bisa membuat satu atau lebih metode "logging" khusus dan memanfaatkan penelusuran untuk kategori pertama. Metode logging tidak lebih dari melayani titik rintisan di mana aturan penelusuran dapat diterapkan.

Codism
sumber