Mengapa penebang merekomendasikan penggunaan logger per kelas?

88

Sesuai dokumentasi NLog:

Sebagian besar aplikasi akan menggunakan satu pencatat per kelas, di mana nama pencatat sama dengan nama kelas.

Ini adalah cara yang sama seperti log4net beroperasi. Mengapa ini praktik yang baik?

Daniel T.
sumber
1
hmm. tampaknya ada dua masalah di sini - satu memiliki objek log aktual per kelas, dan yang lainnya memiliki nama log yang sama dengan kelasnya.
Peter Recore

Jawaban:

59

Dengan log4net, menggunakan satu pencatat per kelas membuatnya mudah untuk menangkap sumber pesan log (mis. Kelas yang menulis ke log). Jika Anda tidak memiliki satu pencatat per kelas, tetapi memiliki satu pencatat untuk seluruh aplikasi, Anda perlu menggunakan lebih banyak trik refleksi untuk mengetahui dari mana pesan log tersebut berasal.

Bandingkan berikut ini:

Log per kelas

using System.Reflection;
private static readonly ILog _logger = 
    LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);    

public void SomeMethod()
{
    _logger.DebugFormat("File not found: {0}", _filename);
}

Satu logger per aplikasi (atau serupa)

Logger.DebugFormat("File not found: {0}", _filename); // Logger determines caller

-- or --

Logger.DebugFormat(this, "File not found: {0}", _filename); // Pass in the caller

Menggunakan contoh kedua, Logger perlu membuat pelacakan tumpukan untuk melihat siapa yang memanggilnya atau kode Anda harus selalu diteruskan ke pemanggil. Dengan gaya logger-per-class, Anda masih melakukan ini, tetapi Anda dapat melakukannya sekali per kelas, bukan sekali per panggilan dan menghilangkan masalah kinerja yang serius.

Jeremy Wiebe
sumber
Terima kasih, itu membantu memperjelas banyak hal. Kami hanya memasukkan nama kelas dan metode ke dalam pesan secara manual (yaitu "ImageCreator.CreateThumbnail () dipanggil"), tetapi akan lebih baik jika logger dapat menanganinya.
Daniel T.
1
Untuk diketahui, praktiknya menjadi "lebih baik" untuk memiliki Logger per instance, daripada per kelas (yaitu statis) karena itu membuatnya lebih mudah untuk menangkap informasi seperti informasi thread. Jelas ini masalah selera, bukan "aturan keras dan cepat", tapi saya ingin membuangnya begitu saja.
Will Hartung
7
@Apakah, dapatkah Anda menjelaskannya sedikit lagi? Saat masuk menggunakan Pencatat per Kelas, saya selalu mencatat ID utas sehingga pencatat bisa mendapatkan informasi utas saat ini. Info utas lainnya juga akan tersedia untuk logger.
Jeremy Wiebe
@ Jeremy Wiebe: Apakah ini satu-satunya alasan? Secara fungsional tidak ada masalah jika saya menggunakan variabel global tunggal tipe logger untuk seluruh aplikasi?
gmoniava
1
@ Giorgi Tidak, kurasa tidak. Anda bisa mendapatkan banyak informasi ini hari ini dengan atribut CallerInformation yang membuat satu logger per kelas menjadi sedikit kurang relevan - msdn.microsoft.com/en-us/library/hh534540.aspx
Jeremy Wiebe
16

Keuntungan menggunakan "logger per file" di NLog: Anda memiliki kemungkinan untuk mengelola / memfilter log dengan namespace dan nama kelas. Contoh:

<logger name="A.NameSpace.MyClass"      minlevel="Debug" writeTo="ImportantLogs" /> 
<logger name="A.NameSpace.MyOtherClass" minlevel="Trace" writeTo="ImportantLogs" /> 
<logger name="StupidLibrary.*"          minlevel="Error" writeTo="StupidLibraryLogs" />

<!-- Hide other messages from StupidLibrary -->
<logger name="StupidLibrary.*" final="true" /> 

<!-- Log all but hidden messages -->
<logger name="*" writeTo="AllLogs" /> 

NLogger memiliki potongan kode yang sangat berguna untuk melakukan ini. The nloggerpotongan akan membuat kode berikut:

private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

Jadi hanya sedikit penekanan tombol dan Anda memiliki logger per kelas. Ini akan menggunakan namespace dan nama kelas sebagai nama logger. Untuk menyetel nama yang berbeda ke logger kelas Anda, Anda dapat menggunakan ini:

private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");

Dan, seperti yang dikatakan @JeremyWiebe, Anda tidak perlu menggunakan trik untuk mendapatkan nama kelas yang mencoba memasukkan pesan: Nama logger (biasanya nama kelas) dapat dengan mudah masuk ke file (atau target lain) dengan menggunakan ${logger}in layout.

CoperNick
sumber
5

Saya dapat melihat beberapa alasan untuk pilihan ini.

  • Anda akan selalu tahu dari mana pernyataan log tertentu berasal, jika Anda menyertakan nama logger dalam format keluaran log Anda.
  • Anda dapat mengontrol pernyataan log apa yang Anda lihat pada tingkat yang sangat detail dengan mengaktifkan atau menonaktifkan penebang tertentu, atau menyetel levelnya.
Peter Recore
sumber
4

Ada juga keuntungan kinerja dalam kasus NLog. Sebagian besar pengguna akan menggunakan

Logger logger = LogManager.GetCurrentClassLogger()

Mencari kelas saat ini dari pelacakan tumpukan membutuhkan beberapa (tetapi tidak banyak) kinerja.

Julian
sumber
3

Dalam banyak kasus, nama kelas memberikan nama yang bagus untuk logger. Saat memindai file log, Anda dapat melihat pesan log dan mengaitkannya secara langsung dengan sebaris kode.

Contoh yang bagus di mana ini bukan pendekatan terbaik, adalah log SQL Hibernate. Ada logger bersama bernama "Hibernate.SQL" atau semacamnya, di mana sejumlah kelas yang berbeda menulis SQL mentah ke kategori logger tunggal.

Eric Hauser
sumber
2

Dari sudut pandang pengembangan, paling mudah jika Anda tidak perlu membuat objek logger setiap saat. Di sisi lain, jika Anda tidak melakukannya, tetapi Anda membuatnya secara dinamis menggunakan refleksi, itu akan memperlambat kinerja. Untuk mengatasi ini, Anda dapat menggunakan kode berikut yang membuat logger secara dinamis secara asinkron:

using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinForms
{
    class log
    {

        public static async void Log(int severity, string message)
        {
            await Task.Run(() => LogIt(severity, message));
        }

        private static void LogIt(int severity, string message)
        {
            StackTrace st = new StackTrace();
            StackFrame x = st.GetFrame(2);     //the third one goes back to the original caller
            Type t = x.GetMethod().DeclaringType;
            Logger theLogger = LogManager.GetLogger(t.FullName);

            //https://github.com/NLog/NLog/wiki/Log-levels
            string[] levels = { "Off", "Trace", "Debug", "Info", "Warn", "Error", "Fatal" };
            int level = Math.Min(levels.Length, severity);
            theLogger.Log(LogLevel.FromOrdinal(level), message);

        }
    }
}
as9876
sumber
1

Dua alasan segera muncul di benak:

  1. Memiliki log terpisah untuk setiap kelas memudahkan pengelompokan semua pesan / error log yang berkaitan dengan kelas tertentu.
  2. Memiliki log di dalam kelas memungkinkan Anda untuk mencatat detail internal yang mungkin tidak dapat diakses di luar kelas (misalnya, status privat, informasi yang berhubungan dengan implementasi kelas, dll.).
Dan Tao
sumber
2
Anda memiliki logger di kelas terlepas dari apakah itu ditentukan di tingkat kelas atau secara global. Logger global tidak berada "di luar" kelas dari perspektif visibilitas. Anda masih mereferensikan logger global dari dalam kelas tersebut sehingga Anda memiliki visibilitas penuh.
Robert
0

Mungkin karena Anda ingin dapat membuat log metode yang hanya terlihat oleh kelas tanpa merusak enkapsulasi, hal ini juga memudahkan penggunaan kelas dalam aplikasi lain tanpa merusak fungsionalitas logging.

Rodrick Chapman
sumber
1
Itu membuat sulit untuk menggunakan kelas itu di aplikasi lain. Anda harus mereferensikan perpustakaan logging apakah Anda suka atau tidak.
Piotr Perak
0

Memudahkan untuk mengonfigurasi appender berdasarkan namespace atau kelas.

dotjoe
sumber
0

Jika Anda menggunakan NLOG Anda dapat menentukan situs panggilan di konfigurasi, ini akan mencatat nama kelas dan metode di mana pernyataan pencatatan berada.

<property name="CallSite" value="${callsite}" />

Anda kemudian dapat menggunakan konstanta untuk nama logger Anda atau nama rakitan.

Penafian: Saya tidak tahu bagaimana NLOG mengumpulkan informasi ini, dugaan saya akan menjadi refleksi jadi Anda mungkin perlu mempertimbangkan kinerjanya. Ada beberapa masalah dengan metode Async jika Anda tidak menggunakan NLOG v4.4 atau yang lebih baru.

pengguna6271979
sumber