Logger.getLogger (MyClass.class) log4j kaydedicilerini başlatmanın en iyi yolu mudur?


13

Bu Mkyong öğreticisi günlükçülerin bu şekilde başlatılmasını önerir:

@Controller
public class WelcomeController {

    private static final Logger logger = Logger.getLogger(WelcomeController.class);

   // etc

}

Şimdi muhtemelen bir logger'ı kullandığınız diğer tüm sınıflar günlükçülerini aynı şekilde başlatacaktır.

Sorum şu - bunu yapmanın en iyi yolu bu mu? Görünüşe göre ... tekrarlayan.


2
Bununla ilgili ayrıntılı ne buluyorsunuz (Java'nın sözdizimini bir kenara bırakarak)? Kaydediciyi tutmak için bir değişken oluşturmanız ve kaydedicinin getLogger()adını almanız gerekir.
kdgregory

2
@kdgregory her sınıfta aynı şeyi yaptığım gerçeği.
dwjohnston


3
Taşınacak çok eski, ancak bu soru konu dışı ve StackOverflow için daha uygun.
Andres F.

1
@AndresF. Bence buraya koydum çünkü teknik bir konudan ziyade kod stili / tasarım desenleri hakkında bir soru daha.
dwjohnston

Yanıtlar:


16

Yorumunuz "ayrıntılı" ifadesinin, bu kod satırını her sınıfta tekrar etme ihtiyacını ifade ettiğini söylüyor. İlk cevabım, büyük resimde, her sınıfa iki satır kod (değişken tanımı ve içe aktarma ifadesi) eklemek o kadar büyük bir anlaşma değil. Özellikle de davranışları olan sınıflara eklemeniz ve bu nedenle günlük kaydı yapmanız gerektiğinden. Bununla birlikte, kullandığınız belirli kod satırı, hataları kopyalayıp yapıştırma eğilimindedir (daha sonra daha fazla).

Ancak, alternatifler istediğiniz için, bunları kullanmak isteyebileceğiniz veya istemeyeceğiniz nedenlerle birkaç tane.

Tüm uygulama için tek bir günlükçü kullanın

Hangi sınıfın rapor ettiğini umursamıyorsanız veya gerekli tüm içeriği iletiye koymak istiyorsanız, basit bir tekli günlükçü işi yapacaktır:

LoggerSingleton.getInstance().debug("MyController is running")

Bence, bir günlükleme çerçevesinin en büyük faydalarından biri, yalnızca günlük iletilerini farklı hedeflere yönlendirmek için ayrı günlükçü örnekleri tarafından sağlanan içeriğe sahip olmaktır. Ben sadece bir satır kod kaydetmek için vazgeçmek olmaz (hala ithalat gerekir).

Artı, bu, kullanım noktasında ayrıntı düzeyini arttırır, bu da çok daha fazla tuş vuruşuna neden olur.

Kaydedicilerinizi kullanım noktasında oluşturun

Bunu değişkeni ortadan kaldırdığı için atıyorum. Bunun hakkında yorum yapmam gerektiğini sanmıyorum. Bir logger örneği almak için tercih ettiğim tekniği göstermesine rağmen.

Logger.getLogger(getClass()).debug("blah blah blah");

Kaydediciyi enjekte etmek için bir fasulye son işlemcisi kullanın

Örneğinizde Spring kullanılıyor ve Spring fasulye başlangıç ​​koduna bağlanmanıza izin veriyor. Çekirdeği bir loggerüye değişkeni için inceleyen ve bir Loggertane bulduğunda bir örnek oluşturan bir post-işlemci oluşturabilirsiniz .

Böyle bir post-işlemci sadece birkaç düzine kod satırı olsa da, uygulamanızdaki başka bir hareketli parça ve bu nedenle başka bir potansiyel hata kaynağıdır. Bunlardan mümkün olduğunca azını tercih ederim.

Bir karışım kullanın

Scala ve Groovy , davranışları kapsüllemenizi sağlayan özellikler sunar . Tipik bir Scala deseni, bir Loggingözellik oluşturmak ve daha sonra günlük kaydı gerektiren sınıfa eklemektir:

class MyController with Logging

Ne yazık ki, bu dilleri değiştirmek zorunda olduğunuz anlamına gelir. Java 8 kullanmadığınız sürece, bu durumda Logging"varsayılan yöntem" ile bir arayüz oluşturabilirsiniz :

public interface Logging {
    default Logger getLogger() {
        return Logger.getLogger(getClass());
    } 
}

Şimdi, sınıf kodunuz içinde,

getLogger().debug("blah blah blah");

Kolay olsa da, bunun birkaç dezavantajı vardır. Bir kere, onu kullanan her sınıfın arayüzünü kirletir, çünkü tüm arayüz yöntemleri herkese açıktır. Sadece Spring tarafından başlatılan ve enjekte edilen sınıflar için, özellikle arayüz / uygulama ayrımını takip ederseniz, o kadar da kötü değil.

Daha büyük sorun, her çağrıda gerçek logger örneğini aramak zorunda olmasıdır. Hangi hızlı, ama gereksiz.

Ve hala bir içe aktarma ifadesine ihtiyacınız var.

Kaydediciyi bir üst sınıfa taşıma

Tekrarlayacağım: Tekrarlanan logger tanımlarını ayrıntılı olarak bulamıyorum, ancak bunu yaparsanız, bunları ortadan kaldırmak için en iyi yaklaşım olduğunu düşünüyorum.

public abstract class AbstractController {
    protected Logger logger = Logger.getLogger(getClass());
}

Artık denetleyici sınıflarınız devralınır AbstractControllerve loggerdeğişkene erişimleri vardır . @ControllerEk açıklamayı somut sınıfa koymanız gerektiğini unutmayın .

Bazı insanlar bunu kalıtımın sapkınlığı olarak bulacaklardır. Sınıf AbstractControlleryerine adlandırarak onları eritmeye çalıştım AbstractProjectClass. Bir ilişki olup olmadığına kendiniz karar verebilirsiniz .

Diğer insanlar, statik değişken yerine örnek değişkeninin kullanımına itiraz eder. Sınıf adına açıkça başvurmanız gerektiğinden, IMO statik kaydedicileri kopyalayıp yapıştırma hatalarına eğilimlidir; getClass()kaydedicinizin her zaman doğru olmasını sağlar.


Bence miras sınıfında getClass (), MethodHandles.lookup (). LookupClass () jdk 7
yuxh 15:19

@luxh - bunun için bir açıklamanız var mı?
kdgregory


@yuxh - bu sorudaki (bağladığınız cevapta yer almayan) MethodHandles'ın tek sözü, açıklama isteyen bir açıklama ile benzer bir desteklenmeyen iddiadır. Daha iyi bir iddia için yetkili bir desteğiniz var mı? MethodHandles.lookup().lookupClass()Object.getClass()
kdgregory

MethodHandles.lookup().lookupClass()statik değişkenler için kullanılabilir, kopyala-yapıştır hatalarına yatkın değildir ve hızlıdır: stackoverflow.com/a/47112323/898747 Bu ekstra bir inport anlamına gelir, ancak günlükçülerimin statik olmasını çok seviyorum, bu yüzden en azından bir mention :)
FableBlaze

0

@Kdgregory tarafından sağlanan yanıtı genişletmek için Groovy, @Slf4j( groovy.util.logging.Slf4j) logbelirtilmemişse varsayılan olarak varsayılan adı alan bir logger ile başa çıkmak için sınıfta bir AST dönüşümü gerçekleştiren bir ek açıklama olarak kutunun dışına ( ) sağlar .

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.