Logger özel statik olmalı mı yoksa olmamalı mı


103

Logger statik ilan edilmeli mi, olmamalı mı? Genellikle bir kaydedici için iki tür bildirim gördüm:

    korumalı Günlük kaydı = yeni Log4JLogger (aClass.class);

veya

    özel statik Günlük günlüğü = yeni Log4JLogger (aClass.class);

Hangisi kullanılmalı? her ikisinin profesyonelleri ve eksileri nelerdir?


1
Günlüğe kaydetme, kesişen bir konudur. Yönleri kullanın ve soru tartışmalı.
Dave Jarvis

4
staticsınıf başına bir referanstır. statik olmayan, örnek başına bir referanstır (+ başlatma). Bu nedenle, bazı durumlarda, tonlarca örneğiniz varsa, ikincisi önemli bir bellek etkisine neden olur. Statik olmayanı asla sık bir nesnede kullanmayın. Ben her zaman statik versiyonu kullanırım. ( büyük harfle yazılmalıdır LOG)
ÇIKTI - Anony-Mousse

2
daha önce önerildiği gibi, AOP ve ek açıklamaları kullanın, örneğin: jcabi.com/jcabi-aspects/annotation-loggable.html
yegor256

1
RobertHume statik versiyonu olan sabit kullanıyorsanız. Tam da bu yüzden büyük harfle yazılmalıdır.
ÇIKTI - Anony-Mousse

2
Hayır, bu private static final Log logküçük harf olmalıdır . Kaydedici sabit değildir, kaydedici statik bir nihai nesnedir (değiştirilebilen). Şahsen ben her zaman kullanırım logger.
osundblad

Yanıtlar:


99

Statik olmayan formun avantajı, doğru sınıf adının kullanılacağından endişe etmeden onu aşağıdaki gibi (soyut) bir temel sınıfta bildirebilmenizdir:

protected Log log = new Log4JLogger(getClass());

Bununla birlikte dezavantajı, açıkça, sınıfın her örneği için tamamen yeni bir kaydedici örneğinin yaratılacağıdır. Bu kendi başına pahalı olmayabilir, ancak önemli bir ek yük getirir. Bundan kaçınmak istiyorsanız, staticbunun yerine formu kullanmak istersiniz . Ancak dezavantajı, bunu her bir sınıfta bildirmeniz ve her sınıfta, getClass()statik bağlamda kullanılamayacağı için logger'ın yapımı sırasında doğru sınıf adının kullanıldığına dikkat etmeniz gerektiğidir . Ancak, ortalama bir IDE'de bunun için bir otomatik tamamlama şablonu oluşturabilirsiniz. Örn. logger+ ctrl+space.

Öte yandan, bir fabrika tarafından kaydediciyi elde ederseniz, bu da önceden başlatılmış günlükleri önbelleğe alabilir, o zaman statik olmayan formun kullanılması bu kadar fazla ek yük getirmez. Örneğin Log4j'de LogManagerbu amaç için bir vardır.

protected Log log = LogManager.getLogger(getClass());

6
abstract Log getLogger();Soyut sınıfta beyan edin. Belirli bir örnek için statik günlükçüyü döndürerek bu yöntemi uygulayın. private final static Log LOG = LogManager.getLogger(Clazz.class);IDE sınıfı şablonunuza ekleyin .
ÇIKTI - Anony-Mousse

2
Slf4j için:protected Logger log = LoggerFactory.getLogger(getClass());
Markus Pscheidt

3
@BalusC getClass () yöntemini getLogger yöntemine iletmenin sorunu, geçerli örneğin sınıfını döndürmesidir. Normalde günlüğün kodun bulunduğu sınıfla ilişkilendirilmesi daha çok istenir. Örneğin, günlük kodu Parent sınıfındaysa, yürütme örneği Parent'in alt sınıfı olan Child sınıfının bir örneği olsa bile günlük kaydının Parent ile ilişkilendirilmesini isteriz. GetClass () yanlış, Çocuk ile ilişkilendirilecek ile
Inorg

@inor: "yanlış mı"? Sınıfı soyutlamak istemiyorsanız, ilk olarak miras alınan getClass () 'ı kullanmamalısınız. Mantığın tam olarak hangi alt sınıfta gerçekleştirildiği bilgileri ortaya çıkardığı için onu doğru ve yararlı bulan geliştiriciler vardır.
BalusC

2
@ BalusC getLogger (getClass ()) her zaman alt sınıfın adının yanlış kaydedilmesine neden olur. Günlük kaydı sınıfları, Clazz sınıfındaki kod tarafından yapılan günlük kaydını ilişkilendirmek için her zaman getLogger (Clazz.class) yapmalıdır. Hangi alt sınıfların yürütüldüğünü bilmek isteyen geliştiriciler (Örneğin, SubClazz Clazz'ı genişletir) SubClazz'da yapmalıdır: getLogger (SubClazz.class) ve şöyle bir şey yapmalıdır: log.info ("<temel sınıfımdaki bir şeyi arama>");
inor

45

Tüm kaydedicilerin statik olması gerektiğini düşünürdüm; ancak wiki.apache.org adresindeki bu makale, sınıf yükleyici sızıntılarıyla ilgili bazı önemli bellek sorunlarını ortaya çıkarmaktadır. Bir günlükçüyü statik olarak bildirmek, bildiren sınıfın (ve ilişkili sınıf yükleyicilerin) paylaşılan bir sınıf yükleyici kullanan J2EE konteynerlerinde çöp toplanmasını engeller. Uygulamanızı yeterli sayıda yeniden dağıtırsanız bu, PermGen hatalarına neden olur.

Bu sınıf yükleyici sızıntısı sorununu çözmek için, günlükleri statik olmayan olarak bildirmekten başka bir yol görmüyorum.


4
Statik alanın da bellek sızıntısı sorunu yaşayacağından şüphelendim. Statik olmayan, diğerlerinin söylediği gibi performans sorununa sahip olabilir. O halde ideal yol nedir?
liang

@piepera, atıfta bulunduğunuz makalede açıklanan ana sorun, "özel statik Günlük log =" kullanan bir sınıfın, sözde birden fazla kişinin soyundan gelen bir ClassLoader aracılığıyla dağıtıldığı durumu düşünün. bağımsız "uygulamalar" ". Bunu bir sorun olarak görmüyorum çünkü bu özel durumda başvurular "ortak bir zemine" sahiptir ve bu "ortak payda" sınıf için kayıt seviyesi belirlenir ve evet, tüm başvurular için geçerlidir ... Bu düşünceyle sınıf bu uygulamaların [yüklenen] dışında olduğunu
inor

17

En önemli fark, günlük dosyalarınızı nasıl etkilediğidir: günlükler hangi kategoriye gider?

  • İlk seçiminizde, bir alt sınıfın günlükleri üst sınıf kategorisine girer. Bu bana çok mantıksız geliyor.
  • İlk durumunuzun bir çeşidi var:

    korumalı Günlük kaydı = yeni Log4JLogger (getClass ());

    Bu durumda, günlük kategoriniz, oturum açan kodun hangi nesne üzerinde çalıştığını belirtir.

  • İkinci seçiminizde (özel statik), günlük kategorisi, günlük kodunu içeren sınıftır. Normalde günlüğe kaydedilen şeyi yapan sınıf.

Bu son seçeneği şiddetle tavsiye ederim. Diğer çözümlere göre şu avantajları vardır:

  • Günlük ile kod arasında doğrudan bir ilişki vardır. Bir günlük mesajının nereden geldiğini bulmak kolaydır.
  • Birinin kayıt düzeylerini ayarlaması gerekiyorsa (bu, kategori başına yapılır), bunun nedeni genellikle belirli bir sınıf tarafından yazılan bazı belirli mesajlarla ilgilenmeleri (veya ilgilenmemeleri) içindir. Kategori, mesajları yazan sınıf değilse, seviyeleri ayarlamak daha zordur.
  • Statik yöntemlerle giriş yapabilirsiniz
  • Kaydedicilerin yalnızca sınıf başına bir kez başlatılması (veya aranması) gerekir, bu nedenle oluşturulan her örnek için değil, başlangıçta.

Ayrıca dezavantajları da vardır:

  • Mesajları günlüğe kaydettiğiniz her sınıfta bildirilmesi gerekir (süper sınıf günlükçülerin yeniden kullanımı yoktur).
  • Günlükçüyü başlatırken doğru sınıf adını girmeye dikkat etmeniz gerekir. (Ama iyi IDE'ler bununla sizin için ilgilenir).

4

Kontrolün ters çevrilmesini kullanın ve logger'ı kurucuya iletin. Kaydediciyi sınıfın içinde oluşturursanız, birim testlerinizle büyük bir zaman geçireceksiniz. Birim testleri yazıyorsun, değil mi?


5
Hem işe yaramaz hem de inanılmaz derecede kırılgan ses ürettiğiniz günlük kaydını inceleyen birim testleri.
Michael

1
Test edilen sisteme bağlı olarak kullanışlılık. Bazen erişiminiz olan tek şey günlük kaydıdır.
Wayne Allen

@Wayne Allen birim testleri yaparken, tanımı gereği test sonuçlarınız da var. Birinin test ettiği ancak test sonuçlarının olmadığı bir durum mu öneriyorsunuz? sadece günlükler var mı?
inor

sınıf içinde günlükçüyü oluşturmak sorun yaratmaz. Sınıf kendi günlükçüsünü yarattığı için UT'ye zor gelen basit bir örnek gösterebilir misiniz?
inor

1
Elbette. E-postalar gönderen bir kaydediciye ne dersiniz? Testlerinizi her çalıştırdığınızda bunu yapmak istemeyin. Artı yan etkiyi nasıl ortaya koyuyorsunuz?
Wayne Allen
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.