Scala'da oturum açma


169

Scala uygulamasında günlük kaydı yapmanın iyi bir yolu nedir? Dil felsefesi ile uyumlu olan bir şey, kodu karmaşıklaştırmaz ve az bakım gerektiren ve göze batmayan bir şeydir. Temel bir gereksinim listesi:

  • basit
  • kodu karıştırmaz. Scala kısalığı için mükemmeldir. Kodumun yarısının ifadeleri günlüğe kaydetmesini istemiyorum
  • günlük biçimi, kurumsal günlüklerimin ve izleme yazılımımın geri kalanına uyacak şekilde değiştirilebilir
  • günlük düzeylerini destekler (örneğin, hata ayıklama, izleme, hata)
  • diske ve diğer hedeflere (soket, konsol vb.) giriş yapabilir
  • varsa minimum yapılandırma
  • kapsayıcılarda çalışır (web sunucusu gibi)
  • (isteğe bağlı, ancak sahip olmak güzel) dilin bir parçası veya bir maven artefaktı olarak geliyor, bu yüzden onu kullanmak için yapılarımı kesmek zorunda değilim

Mevcut Java günlükleme çözümlerini kullanabileceğimi biliyorum, ancak yukarıdakilerden en az ikisinde, yani dağınıklık ve yapılandırmada başarısız oluyorlar.

Cevaplarınız için teşekkürler.

Yanıtlar:


119

slf4j sarmalayıcılar

Scala günlük kayıt kitaplıklarının çoğu, Java günlük kayıt çerçevesi (slf4j, log4j vb.) Etrafındaki bazı paketleyicilerdir, ancak Mart 2015 itibarıyla, hayatta kalan günlük kitaplıklarının tümü slf4j'dir. Bu günlük kütüphaneleri çeşit sağlamak logArayabileceğin hangi nesneye info(...), debug(...)vb ben slf4j büyük bir hayranı değilim, ama şimdi baskın günlük çerçeve gibi görünüyor. SLF4J açıklaması :

Java için Basit Logging Facade veya (SLF4J), java.util.logging, log4j ve logback gibi çeşitli günlükleme çerçeveleri için basit bir cephe veya soyutlama işlevi görür ve son kullanıcının istediği günlükleme çerçevesini dağıtım zamanında takmasına olanak tanır.

Dağıtım zamanında temel günlük kitaplığını değiştirme yeteneği, tüm bilmeniz gereken tüm slf4j günlük kaydedici ailesine benzersiz bir özellik kazandırır:

  1. yapılandırma yaklaşımı olarak sınıfyolu . Slf4j'nin hangi temel günlükleme kütüphanesini kullandığınızı bilmesi, bir sınıfı bir ada göre yüklemektir. Classfloader özelleştirildiğinde slf4j benim logger tanımıyor sorunları yaşadım.
  2. Çünkü basit cephe ortak paydayı olmaya çalışır, sadece fiili günlük çağrılarına sınırlı. Başka bir deyişle, yapılandırma kod üzerinden yapılamaz.

Büyük bir projede, herkes slf4j kullansaydı, geçişli bağımlılıkların günlük tutma davranışını kontrol edebilmek uygun olabilir.

Scala Günlüğü

Scala Logging , Heiko Seeberger tarafından slf4'lerinin halefi olarak yazılmıştır . Potansiyel olarak pahalı günlük çağrısını önlemek için ifadeleri if ifadesine genişletmek için makro kullanır.

Scala Logging, SLF4J ve potansiyel olarak diğerleri gibi günlük kütüphanelerini saran kullanışlı ve performanslı bir günlük kütüphanesidir.

Tarihsel günlük kaydediciler

  • Logula , Coda Hale tarafından yazılmış bir Log4J ambalajı. Bunu sevdim, ama şimdi terk edildi.
  • Scala'nın ilk günlerinde popüler olan bir java.util.logging sarmalayıcısı olan configgy . Şimdi terk edildi.

1
Söylemeliyim ki, Logula'yı seviyorum ... nihayet beni tornavidayı kulağımdan bıçaklamak istemeyen bir logger. XML yok ve BS yok, başlangıçta sadece bir scala yapılandırması var
Arg

Heiko Seeberger'in SLF4S'sinin bakımı artık yapılmıyor. Kendi hedeflememi Scala 2.10 ve en son SLF4J'yi yaptım. http://slf4s.org/
Matt Roberts

3
Logula, Github'daki README'ye göre terk edildi.
Erik Kaplun

Oncue Journal, kavram olarak Scala Logging'e benzer, ancak günlük mesajları, özel bir iş parçacığı havuzundan SLF4J'yi çağıran bir aktöre gönderilir. CPU zamanını (çok daha iyi) gecikme için değiştirir. github.com/oncue/journal
Gary Coady

64

Scala 2.10+ ile Typesafe tarafından ScalaLogging'i düşünün. Çok temiz bir API sunmak için makrolar kullanır

https://github.com/typesafehub/scala-logging

Wiki'sinden alıntılar:

Neyse ki Scala makroları hayatımızı kolaylaştırmak için kullanılabilir: ScalaLogging, sınıfa Loggeryukarıdaki deyime kadar genişletilecek hafif günlükleme yöntemleri sunar . Yani yazmamız gereken tek şey:

logger.debug(s"Some ${expensiveExpression} message!")

Makro uygulandıktan sonra, kod yukarıda açıklanan deyime dönüştürülmüş olacaktır.

Ek olarak ScalaLogging , sınıfın adıyla karıştırılmış Loggingbir Loggerörneği uygun bir şekilde sağlayan özelliği sunar :

import com.typesafe.scalalogging.slf4j.LazyLogging

class MyClass extends LazyLogging {
  logger.debug("This is very convenient ;-)")
}

12
Kullanın class MyClass with Logging.
Andrzej Jozwik

1
Özelliklerde günlüğe kaydetmenin kullanılmasının, özelliğin günlükçü için karıştırıldığı sınıfla aynı ada sahip olmasına neden olduğunu lütfen unutmayın. Gerekirse, kaydedicinin adını manuel olarak sağlamak için makro rahatlığı yerine kaydediciyi manuel olarak alabileceğinizi düşünüyorum. Ama lütfen, yanılıyorsam beni düzeltin.
mkko

1
Bu, MyClass'ın hata ayıklama, bilgi uyarısı vb. İçin genel yöntemleri olduğu anlamına mı geliyor? Eğer öyleyse, sınıfa özel bir logger başlatmanın ekstra manuel çalışmasını tercih ederim. Günlükleme yöntemleri bir sınıf arabirimine sızmamalıdır.
ChucK

2
boş zamanlarınızda kullanabileceğiniz bir kayıt alanı elde edersiniz. Ayrıntılar için github.com/typesafehub/scalalogging/blob/master/… adresine bakın
fracca

2
2.x Scala 2.11 gerektirir; umarım pratikte çok fazla fark yoktur; Scala 2.10.x için var "com.typesafe" %% "scalalogging-slf4j" % "1.1.0".
Erik Kaplun

14

Slf4j ve bir sarıcı kullanmak güzeldir ancak enterpolasyonda yerleşik olarak kullanılması enterpolasyon için ikiden fazla değeriniz olduğunda bozulur, çünkü o zaman enterpolasyon yapmak için bir değerler dizisi oluşturmanız gerekir.

Daha Scala benzeri bir çözüm, hata mesajının birleştirilmesini geciktirmek için bir thunk veya küme kullanmaktır. Buna iyi bir örnek Lift'in logger'ı

Log.scala Slf4jLog.scala

Bu şöyle görünür:

class Log4JLogger(val logger: Logger) extends LiftLogger {
  override def trace(msg: => AnyRef) = if (isTraceEnabled) logger.trace(msg)
}

Msg'nin isimle çağrı olduğunu ve isTraceEnabled doğru olmadığı sürece değerlendirilmeyeceğini unutmayın, bu nedenle güzel bir mesaj dizesi oluşturmanın maliyeti yoktur. Bu, slf4j'nin hata mesajının ayrıştırılmasını gerektiren enterpolasyon mekanizması etrafında çalışır. Bu modelle, hata mesajına istediğiniz sayıda değeri enterpolasyon yapabilirsiniz.

Bu Log4JLogger'ı sınıfınıza karıştıran ayrı bir özelliğiniz varsa, bunu yapabilirsiniz

trace("The foobar from " + a + " doesn't match the foobar from " +
      b + " and you should reset the baz from " + c")

onun yerine

info("The foobar from {0} doesn't match the foobar from {1} and you should reset the baz from {c},
     Array(a, b, c))

2
scala sınıflarında günlük deyimleri için doğru satır numaraları almak mümkün mü ?????
11:58

13

Logula kullanma

Aslında Eugene önerisi takip ve denedim ve beceriksiz bir tasarıma sahiptir ve (gibi sabit alamadım hatalar, tabi ki öğrendim bu bir ). Bakımlı görünmüyor ve Scala 2.10'u desteklemiyor .

Slf4s + slf4j-simple kullanın

Temel faydaları:

  • En yeni Scala 2.10'u destekler (bugüne kadar M7)
  • Yapılandırma çok yönlü ancak daha basit olamazdı. O ile bitti sistem özelliklerine gibi bir şey ekleyerek ya ayarlayabilirsiniz, -Dorg.slf4j.simplelogger.defaultlog=tracekomut dosyanızda yürütme komutu veya kodlamalısınız: System.setProperty("org.slf4j.simplelogger.defaultlog", "trace"). Değersiz yapılandırma dosyalarını yönetmeye gerek yok!
  • IDE'lerle güzel uyum sağlar. Örnek IDEA belirli çalışma yapılandırmasında "iz" Günlük düzeyini ayarlamak için için sadece gidin Run/Debug Configurationsve eklemek -Dorg.slf4j.simplelogger.defaultlog=traceiçin VM options.
  • Kolay kurulum: bu cevabın alt kısmındaki bağımlılıkları bırakın

Maven ile çalıştırmanız için ihtiyacınız olan şey:

<dependency>
  <groupId>com.weiglewilczek.slf4s</groupId>
  <artifactId>slf4s_2.9.1</artifactId>
  <version>1.0.7</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <version>1.6.6</version>
</dependency>

2.10'u destekleyen slf4'leri nerede bulabilirsiniz? Github.com/weiglewilczek/slf4s adresine bakıyorum ve "Desteklenen Scala sürümleri 2.8.0, 2.8.1, 2.9.0-1 ve 2.9.1." .. yanlış yere mi bakıyorum?
nairbv

@Brian Cevapta önerilen 2.9.1'i kullanın. 2.10.0-M7
Nikita Volkov ile

2.9.1 kullanıyorum, sadece vurgulanan "temel fayda" ve bunun ne anlama geldiğini merak ediyordum.
nairbv

Kütüphane kütüphanelerinin artılarını ve eksilerini dikkatlice araştırdıktan sonra, bana hangi bağımlılığın içe aktarılacağını söyleyeni seçiyorum. Teşekkürler efendim.
teo

11

Bu bende nasıl Scala Günlüğü benim için çalışma:

Bunu şunun içine koy build.sbt:

libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2",
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"

Sonra, bir yaptıktan sonra sbt update, bu kolay bir günlük mesajı yazdırır:

import com.typesafe.scalalogging._
object MyApp extends App with LazyLogging {
  logger.info("Hello there")
}

Oynat kullanıyorsanız yapabilirsiniz elbette sadece import play.api.Loggerlog mesajları yazmak için: Logger.debug("Hi").

Daha fazla bilgi için dokümanlara bakın .


Sadece log4j.propertiesproje kaynak klasörü içinde oluşturduktan sonra benim için çalıştı .
Nadjib Mami

7

Ben iş formunun bir Biti çekti Loggingait özelliği scalaxve ayrıca entegre bir özellik yarattı MessageFormat-basedkütüphane.

Sonra şeyler şöyle görünür:

class Foo extends Loggable {
    info( "Dude, I'm an {0} with {1,number,#}", "Log message", 1234 )
}

Yaklaşımı seviyoruz.

Uygulama:

trait Loggable {

    val logger:Logger = Logging.getLogger(this)

    def checkFormat(msg:String, refs:Seq[Any]):String =
        if (refs.size > 0) msgfmtSeq(msg, refs) else msg 

    def trace(msg:String, refs:Any*) = logger trace checkFormat(msg, refs)

    def trace(t:Throwable, msg:String, refs:Any*) = logger trace (checkFormat(msg, refs), t)

    def info(msg:String, refs:Any*) = logger info checkFormat(msg, refs)

    def info(t:Throwable, msg:String, refs:Any*) = logger info (checkFormat(msg, refs), t)

    def warn(msg:String, refs:Any*) = logger warn checkFormat(msg, refs)

    def warn(t:Throwable, msg:String, refs:Any*) = logger warn (checkFormat(msg, refs), t)

    def critical(msg:String, refs:Any*) = logger error checkFormat(msg, refs)

    def critical(t:Throwable, msg:String, refs:Any*) = logger error (checkFormat(msg, refs), t)

}

/**
 * Note: implementation taken from scalax.logging API
 */
object Logging {  

    def loggerNameForClass(className: String) = {  
        if (className endsWith "$") className.substring(0, className.length - 1)  
        else className  
    }  

    def getLogger(logging: AnyRef) = LoggerFactory.getLogger(loggerNameForClass(logging.getClass.getName))  
}

Sevimli, bu işe almak için bazı sorunlar yaşıyorum olsa da - özellikle, çıkış (varsayılan slf4j yapılandırmada) her zaman aşağıdaki gibi görünüyor, sınıf aslında aslında uzanan Loggable: 22 Tem 2011 03:02:17 redacted.util.Loggable $ class info BİLGİ: Bazı mesajlar ... Buna rastlama şansın var mı?
Tomer Gabel

7

SLF4J + Logback classic kullanıyorum ve şu şekilde uyguluyorum:

trait Logging {
  lazy val logger = LoggerFactory.getLogger(getClass)

  implicit def logging2Logger(anything: Logging): Logger = anything.logger
}

Sonra tarzınıza daha uygun olanı kullanabilirsiniz:

class X with Logging {
    logger.debug("foo")
    debug("bar")
}

ancak bu yaklaşım elbette her sınıf örneği için bir logger örneği kullanır.


4

Scalax kütüphanesine bir göz atmalısınız: http://scalax.scalaforge.org/ Bu kütüphanede, arka uç olarak sl4j kullanan bir Günlük kaydı özelliği vardır. Bu özelliği kullanarak kolayca giriş yapabilirsiniz (sadece özelliği devralan sınıftaki günlükçü alanını kullanın).




3

Hızlı ve kolay formlar.

Scala 2.10 ve üstü:

import com.typesafe.scalalogging.slf4j.Logger
import org.slf4j.LoggerFactory
val logger = Logger(LoggerFactory.getLogger("TheLoggerName"))
logger.debug("Useful message....")

Ve build.sbt:

libraryDependencies += "com.typesafe" %% "scalalogging-slf4j" % "1.1.0"

Scala 2.11+ ve daha yenisi:

import import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
val logger = Logger(LoggerFactory.getLogger("TheLoggerName"))
logger.debug("Useful message....")

Ve build.sbt:

libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0"

2

Bir süre slf4s ve logula kullandıktan sonra, slf4j logladysarma basit bir günlük kaydı özelliği yazdı .

Genel vakaları (temel dize, basit biçimlendirme) önemsiz hale getiren ve kazan plakasını biçimlendirmeyi önleyen Python'un günlük kütüphanesine benzer bir API sunar.

http://github.com/dln/loglady/


2

Bana böyle bir sözdizimi getiren basit scala sarıcı ile bir tür java logger, sl4j kullanarak çok uygun buluyorum

val #! = new Logger(..) // somewhere deep in dsl.logging.

object User with dsl.logging {

  #! ! "info message"
  #! dbg "debug message"
  #! trace "var a=true"

}

Bence java kanıtlanmış günlükleme çerçeveleri ve scala'nın fantezi sözdiziminin çok yararlı karışımı.


@sschaef, oh, evet. Afedersiniz. Neredeyse unutuyordum. Birkaç gün boyunca bu konuyla büyük bir mücadele oldu, ama bunun gerçekten imkansız olduğu anlaşılıyor. #! ! yerine "bilgi mesajı". Cevabımı düzenleyeceğim.
Alex Povar
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.