Kaydediciler neden sınıf başına bir kaydedici kullanılmasını önerir?


88

NLog belgelerine göre:

Çoğu uygulama, sınıf başına bir kaydedici kullanır; burada günlükçünün adı, sınıfın adıyla aynıdır.

Bu, log4net'in çalışmasıyla aynıdır. Bu neden iyi bir uygulama?


1
hmm. Görünüşe göre burada iki sorun var - biri sınıf başına gerçek bir günlük nesnesine sahip olmak ve diğeri günlük adının sınıfla aynı olması.
Peter Recore

Yanıtlar:


59

Log4net ile, sınıf başına bir kaydedici kullanmak, günlük mesajının kaynağını (yani günlüğe yazan sınıf) yakalamayı kolaylaştırır. Sınıf başına bir kaydediciniz yoksa, bunun yerine tüm uygulama için tek bir kaydediciniz varsa, günlük mesajlarının nereden geldiğini bilmek için daha fazla yansıtma hilesine başvurmanız gerekir.

Aşağıdakileri karşılaştırın:

Sınıf başına günlük

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

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

Uygulama başına bir kaydedici (veya benzeri)

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

-- or --

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

İkinci örneği kullanarak, Logger'ın kimin aradığını görmek için bir yığın izleme oluşturması veya kodunuzun her zaman arayanı iletmesi gerekir. Sınıf başına kaydedici stiliyle bunu yine de yaparsınız, ancak bunu çağrı başına bir kez yapmak yerine sınıf başına bir kez yapabilir ve ciddi bir performans sorununu ortadan kaldırabilirsiniz.


Teşekkürler, bu işleri netleştirmeye yardımcı oluyor. Sadece sınıf adını ve yöntemi mesaja manuel olarak koyuyorduk (yani "ImageCreator.CreateThumbnail () çağrıldı"), ancak günlükçü bunu halledebilirse daha iyi olur.
Daniel T.

1
Bilginize, sınıf başına (yani statik) yerine örnek başına bir Kaydediciye sahip olmak "daha iyi" bir uygulama haline geldi çünkü bu, iş parçacığı bilgileri gibi bilgileri yakalamayı kolaylaştırır. Açıkçası bu bir zevk meselesi, "zor ve hızlı bir kural" değil, ama bunu bir kenara atmak istedim.
Will Hartung

7
@will, bunu biraz daha açıklayabilir misin? Sınıf başına bir Kaydedici kullanarak günlük kaydı yaparken, her zaman iş parçacığı kimliğini kaydederim, böylece günlükçü geçerli iş parçacığı bilgilerini alabilir. Diğer herhangi bir iş parçacığı bilgisi kaydedici tarafından da mevcut olacaktır.
Jeremy Wiebe

@Jeremy Wiebe: Tek sebep bu mu? Tüm uygulama için tek bir global değişken türü günlükçü kullanırsam işlevsel olarak sorun olmaz mı?
gmoniava

1
@Giorgi Hayır, sanmıyorum. Sınıf başına bir kaydediciyi biraz daha az alakalı hale getiren CallerInformation öznitelikleriyle bu günlerde bu bilgilerin çoğunu edinebilirsiniz - msdn.microsoft.com/en-us/library/hh534540.aspx
Jeremy Wiebe

16

NLog'da "dosya başına günlük kaydedici" kullanmanın avantajı: günlükleri ad alanına ve sınıf adına göre yönetme / filtreleme olanağınız vardır. Misal:

<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, bunu yapmak için çok kullanışlı bir kod parçacığına sahiptir. nloggerPasajı aşağıdaki kodu oluşturur:

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

Yani yalnızca birkaç tuş vuruşu ve sınıf başına günlük kaydediciniz var. Kaydedicinin adı olarak ad alanını ve sınıf adını kullanacaktır. Sınıf kaydedicinize farklı bir ad ayarlamak için şunu kullanabilirsiniz:

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

Ve @JeremyWiebe'nin dediği gibi, bir mesajı günlüğe kaydetmeye çalışan sınıfın adını almak için hileler kullanmak zorunda değilsiniz: Kaydedicinin adı (genellikle sınıfın adıdır) kolayca dosyaya kaydedilebilir (veya başka bir hedef) ${logger}düzende kullanarak .


5

Bu seçim için birkaç neden görebiliyorum.

  • Günlük çıkış biçiminize günlükçünün adını eklerseniz, belirli bir günlük ifadesinin nereden geldiğini her zaman bilirsiniz.
  • Belirli kaydedicileri açıp kapatarak veya seviyelerini ayarlayarak ayrıntılı bir düzeyde hangi günlük ifadelerini gördüğünüzü kontrol edebilirsiniz.

4

NLog durumunda da bir performans avantajı vardır. Çoğu kullanıcı kullanacak

Logger logger = LogManager.GetCurrentClassLogger()

Yığın izlemeden mevcut sınıfa bakmak biraz (ama fazla değil) performans gerektirir.


3

Çoğu durumda, sınıfın adı kaydedici için iyi bir ad sağlar. Günlük dosyalarını tararken, günlük mesajını görebilir ve bunu doğrudan bir kod satırıyla ilişkilendirebilirsiniz.

Bunun en iyi yaklaşım olmadığı iyi bir örnek, Hibernate'in SQL günlükleridir. "Hibernate.SQL" veya buna benzer bir adında paylaşılan bir kaydedici var, burada bir dizi farklı sınıf tek bir günlükçü kategorisine ham SQL yazıyor.


2

Geliştirme açısından, her seferinde bir kaydedici nesnesi oluşturmanız gerekmiyorsa en kolayıdır. Öte yandan, yapmazsanız, daha ziyade yansıma kullanarak dinamik olarak yaratırsanız, performansı yavaşlatacaktır. Bunu çözmek için, günlükçüyü dinamik olarak eşzamansız olarak oluşturan aşağıdaki kodu kullanabilirsiniz:

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);

        }
    }
}

1

Akla hemen iki neden geliyor:

  1. Her sınıf için ayrı bir günlüğe sahip olmak, belirli bir sınıfa ait tüm günlük mesajlarını / hatalarını bir arada gruplamayı kolaylaştırır.
  2. Bir sınıf içinde bir günlüğe sahip olmak, sınıf dışında erişilemeyen dahili ayrıntıları (örneğin, özel durum, bir sınıfın uygulanmasına ilişkin bilgiler, vb.) Günlüğe kaydetmenize olanak tanır.

2
Sınıf düzeyinde veya genel olarak tanımlanmış olmasına bakılmaksızın sınıfta bir günlük kaydediciniz vardır. Küresel kaydediciler, görünürlük açısından sınıfın "dışında" değildir. Hala söz konusu sınıfın içinden global logger'a başvuruyorsunuz, böylece tam görünürlük elde edersiniz.
Robert

0

Muhtemelen, kapsüllemeyi bozmadan yalnızca sınıf tarafından görülebilen yöntemleri günlüğe kaydedebilmek istediğiniz için, bu, günlük işlevini bozmadan sınıfı başka bir uygulamada kullanmayı da kolaylaştırır.


1
Bu sınıfı başka bir uygulamada kullanmayı zorlaştırır. İsteseniz de istemeseniz de günlük kitaplığına başvurmanız gerekir.
Piotr Perak

0

Ekleyicileri ad alanına veya sınıfa göre yapılandırmayı kolaylaştırır.


0

NLOG kullanıyorsanız, çağrı sitesini yapılandırmada belirtebilirsiniz, bu, günlük ifadesinin bulunduğu sınıf adını ve yöntemi kaydeder.

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

Daha sonra kaydedici adınız veya derleme adınız için bir sabit kullanabilirsiniz.

Sorumluluk reddi: NLOG'un bu bilgileri nasıl topladığını bilmiyorum, benim tahminim yansıma olacaktır, bu yüzden performansı değerlendirmeniz gerekebilir. NLOG v4.4 veya sonraki bir sürümünü kullanmıyorsanız Async yöntemleriyle ilgili birkaç sorun vardır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.