Logger slf4j'nin dize birleştirme yerine {} ile biçimlendirmenin avantajları


104

{}Dize birleştirme yerine kullanmanın herhangi bir avantajı var mı ?

Slf4j'den bir örnek

logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);

onun yerine

logger.debug("Temperature set to"+ t + ". Old temperature was " + oldT);

Bunun hız optimizasyonuyla ilgili olduğunu düşünüyorum çünkü bir yapılandırma dosyasına bağlı olarak çalışma zamanında parametrelerin değerlendirilmesinden (ve dize birleştirme) kaçınılabilir. Ancak yalnızca iki parametre mümkündür, bu durumda bazen dize birleştirmeden başka seçenek yoktur. Bu konuda görüşlere ihtiyaç var.

Yanıtlar:


76

Bu , dize birleştirme performansı ile ilgilidir. Yoğun günlük kaydı ifadeleriniz varsa bu potansiyel olarak önemlidir.

(SLF4J 1.7'den önce) Ancak yalnızca iki parametre mümkündür

Günlük ifadelerinin büyük çoğunluğunun 2 veya daha az parametresi olduğundan, sürüm 1.6'ya kadar olan SLF4J API (yalnızca) kullanım durumlarının çoğunu kapsar. API tasarımcıları, API 1.7 sürümünden bu yana varargs parametreleriyle aşırı yüklenmiş yöntemler sağlamıştır.

2'den fazlasına ihtiyaç duyduğunuz ve 1.7 öncesi SLF4J ile sıkışıp kaldığınız durumlar için, ya dize birleştirme veya new Object[] { param1, param2, param3, ... }. Performansın o kadar önemli olmadığı konusunda yeterince az kişi olmalı.


2
Kullanılmayan dizge birleştirme (yani hata ayıklama ifadeleri) önlenmelidir. (Aşırı ayrıntılı ama verimli) günlük düzeyi denetimini veya (daha ince, ancak belki de küçük ek yük) nesne dizisi parametresini kullanın. (Her şeyin eşit olmasını tercih ederim.) String concat'in önemli olmayacağını / performansı etkilemeyeceğini söylemek zor. Nesne dizisi yaratımı teoride satır içi ve optimize edilmiş olabilir ve "gerçekten" bir fark yaratmayabilir (arzulu düşünceye karşı). (Erken optimizasyon değil, sadece bir şeyi ilk seferde doğru / daha iyi yapma meselesi.)
michael

System.out.println () 'nin slf4j günlükçüsüne benzer şekilde izlemesi için neden aşırı yüklenmiş değişiklikler yapılmaz, böylece dize birleştirmeyi önler?
a3.14_Infinity

45

Kısa versiyon: Evet, daha az kodla daha hızlı!

Dize birleştirme, gerekli olup olmadığını bilmeden çok fazla iş yapar (geleneksel "hata ayıklama etkin" testi log4j'den bilinir) ve {} toString () çağrısını ve dize yapısını geciktirmeye izin verdiği için mümkünse bundan kaçınılmalıdır olayın yakalanması gerekip gerekmediğine karar verildikten sonra. Logger formatının tek bir dizgeye sahip olmasıyla kod bence daha temiz hale geliyor.

İstediğiniz sayıda argüman sağlayabilirsiniz. Sljf4j'nin eski bir sürümünü kullanıyorsanız ve ikiden fazla argümanınız {}varsa, new Object[]{a,b,c,d}bunun yerine bir diziyi iletmek için sözdizimini kullanmanız gerektiğine dikkat edin . Örneğin bkz. Http://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object []) .

Hızla ilgili olarak: Ceki, listelerden birinde bir süre önce bir kıyaslama yaptı.


6
not: en son javadoc, daha yeni var-arg sözdizimini gösterir debug(String format, Object... arguments). Bkz. Slf4j.org/faq.html#logging_performance
michael

Birleştirme performansına ek olarak .toString () değerlendirmesinden bahsedildiği için oy verildi. Bu, kaydedicinin içinde olan bir şeydir ve günlükçü, bu yöntemi çağırmanın gerekli olup olmadığına karar verebilir. Günlüğe kaydetme düzeyi çubuğu karşılanmadığında gerçekleşmez.
Chetan Narsude

6

String Java'da değişmez olduğundan, sol ve sağ String'in her birleştirme çifti için yeni String'e kopyalanması gerekir. Öyleyse, yer tutucuyu seçseniz iyi olur.


2
Bu, tek bir çift varsa doğrudur, ancak genellikle yanlıştır, çünkü derleyici birleştirmeyi dize oluşturucu çağrılarına dönüştürür ve çok fazla ayırma yapmayan çok daha hızlı kodla sonuçlanır.
cdeszaq

3

Başka bir alternatif de String.format(). Bunu jcabi-log'da kullanıyoruz (slf4j etrafında statik yardımcı program sarmalayıcısı).

Logger.debug(this, "some variable = %s", value);

Çok daha bakımı yapılabilir ve genişletilebilir. Üstelik tercüme etmesi kolay.


3
Daha sürdürülebilir olduğunu düşünmüyorum. valuedeğişiklik türü varsa, geri dönüp günlük ifadesini de değiştirmeniz gerekir. IDE'lerin size yardımcı olmayacağı bir şey. Kaydediciler hata ayıklamaya yardımcı olmalı ve yoluna çıkmamalıdır. :-)
Chetan Narsude

3
@ChetanNarsude IntelliJ 2016 en azından bana biçim dizesinin biçimlendirme argümanlarına uymadığını söyler. Örneğin: String.format("%d", "Test")IntelliJ uyarısını üretir Argument type 'String' does not match the type of the format specifier '%d'.. Yine de, yukarıdaki çözümle çalışırken bu akıllı yanıtı sağlayabileceğinden emin değilim.
ezmek

bunun hızı nedir?
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen içeride oldukça ilkel, ancak elbette statik bir kaydediciden daha yavaş
yegor256

Slf4j paketleniyor mu? bu slf4j kullanım amacını bozmaz mı? Ayrıca, birçok kişinin String.format'ı, günlük düzeyi değerlendirilmeden önce dizenin biçimlendirilmesi için kötüye kullandığını gördüm, örneğin: logger.info (String.format ("merhaba% s", kullanıcı adı)).
Juan Bustamante

2

Yazarın bakış açısına göre, ana neden dizge birleştirme ek yükünü azaltmaktır. Kaydedicinin belgelerini okudum, şu kelimeleri bulabilirsiniz:

/**
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the DEBUG level. However, this variant incurs the hidden
* (and relatively small) cost of creating an <code>Object[]</code> before 
  invoking the method,
* even if this logger is disabled for DEBUG. The variants taking
* {@link #debug(String, Object) one} and {@link #debug(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*/
*
 * @param format    the format string
 * @param arguments a list of 3 or more arguments
 */
public void debug(String format, Object... arguments);
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.