IT박스

스칼라에 로그인

itboxs 2020. 6. 2. 19:07
반응형

스칼라에 로그인


스칼라 애플리케이션에서 로깅을 수행하는 좋은 방법은 무엇입니까? 언어 철학과 일치하고 코드를 어지럽히 지 않으며 유지 보수가 적고 눈에 거슬리지 않는 것이 있습니다. 기본 요구 사항 목록은 다음과 같습니다.

  • 단순한
  • 코드를 어지럽히 지 않습니다. 스칼라는 간결함이 뛰어납니다. 내 코드의 절반이 문장을 로깅하는 것을 원하지 않습니다.
  • 나머지 엔터프라이즈 로그 및 모니터링 소프트웨어에 맞게 로그 형식을 변경할 수 있습니다.
  • 로깅 수준 지원 (예 : 디버그, 추적, 오류)
  • 다른 대상뿐만 아니라 디스크에 기록 할 수 있습니다 (예 : 소켓, 콘솔 등)
  • 최소 구성 (있는 경우)
  • 컨테이너 (예 : 웹 서버)에서 작동
  • (선택적이지만 좋은) 언어의 일부 또는 메이븐 인공물로 제공되므로 사용하기 위해 빌드를 해킹 할 필요가 없습니다.

기존 Java 로깅 솔루션을 사용할 수 있지만 위의 두 가지, 즉 혼란과 구성에서 실패합니다.

답장을 보내 주셔서 감사합니다.


slf4j 포장지

스칼라의 대부분의 로깅 라이브러리는 Java 로깅 프레임 워크 (slf4j, log4j 등)를 감싸는 래퍼이지만 2015 년 3 월 현재 남아있는 로그 라이브러리는 모두 slf4j입니다. 이러한 로그 라이브러리는 일종의 제공 log호출 할 수있는에 개체 info(...), debug(...)등 내가 SLF4J의 큰 팬이 아니에요,하지만 지금은 주된 로깅 프레임 워크가 될 것으로 보인다. SLF4J에 대한 설명은 다음과 같습니다 .

Java 또는 SLF4J (Simple Logging Facade for Java)는 다양한 로깅 프레임 워크 (예 : java.util.logging, log4j 및 logback)에 대한 간단한 외관 또는 추상화 역할을하여 최종 사용자가 배치시 원하는 로깅 프레임 워크를 플러그인 할 수 있도록합니다.

배치시 기본 로그 라이브러리를 변경하는 기능은 전체 slf4j 로거 제품군에 고유 한 특성을 가져옵니다.

  1. 구성 방식 으로서의 클래스 경로 . slf4j가 사용중인 기본 로깅 라이브러리를 아는 방법은 이름으로 클래스를로드하는 것입니다. 클래스 로더를 사용자 정의 할 때 slf4j가 로거를 인식하지 못하는 문제가 있습니다.
  2. 단순한 파사드 는 공통 분모가 되려고하기 때문에 실제 로그 호출로만 제한됩니다. 즉, 코드를 통해 구성을 수행 할 수 없습니다.

대규모 프로젝트에서는 모든 사람이 slf4j를 사용하는 경우 전이 종속성의 로깅 동작을 제어하는 ​​것이 실제로 편리 할 수 ​​있습니다.

스칼라 로깅

Scala Logging 은 Heiko Seeberger가 자신의 slf4s 의 후계자로 작성했습니다 . 매크로를 사용하여 잠재적으로 비싼 로그 호출을 피하기 위해 if 표현식으로 호출을 확장합니다.

스칼라 로깅은 SLF4J 및 잠재적으로 다른 것들과 같은 로깅 라이브러리를 감싸는 편리하고 성능이 뛰어난 로깅 라이브러리입니다.

역사 로거

  • Logula , Coda Hale이 작성한 Log4J 래퍼. 이것을 좋아했지만 이제는 버렸습니다.
  • configgy , 스칼라 초기에 널리 사용되었던 java.util.logging 래퍼. 이제 버려졌습니다.

Scala 2.10 이상에서는 Typesafe에 의한 ScalaLogging을 고려하십시오. 매크로를 사용하여 매우 깨끗한 API 제공

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

그들의 위키에서 인용 :

다행히 Scala 매크로를 사용하여 우리의 삶을 편하게 만들 수 있습니다. ScalaLogging은 Logger위의 관용구로 확장되는 가벼운 로깅 방법을 제공합니다 . 우리가 작성해야 할 것은 다음과 같습니다.

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

매크로가 적용된 후 코드는 위에서 설명한 관용구로 변환됩니다.

또한 ScalaLogging은 클래스 이름으로 초기화 LoggingLogger인스턴스 를 편리하게 제공하는 특성 을 제공합니다 .

import com.typesafe.scalalogging.slf4j.LazyLogging

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

slf4j와 래퍼를 사용하는 것은 좋지만 보간해야 할 값이 두 개 이상인 경우 보간에 내장 된 보간이 사용되어 고장납니다. 그러므로 보간 할 값 배열을 만들어야합니다.

스칼라와 같은 솔루션은 썽크 또는 클러스터를 사용하여 오류 메시지의 연결을 지연시키는 것입니다. 좋은 예는 Lift의 로거입니다.

Log.scala Slf4jLog.scala

이것은 다음과 같습니다

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

msg는 이름 별 호출이며 isTraceEnabled가 true가 아니면 평가되지 않으므로 멋진 메시지 문자열을 생성하는 데 비용이 들지 않습니다. 이 오류 메시지를 구문 분석해야 slf4j의 보간 메커니즘을 해결합니다. 이 모델을 사용하면 여러 값을 오류 메시지에 보간 할 수 있습니다.

이 Log4JLogger를 클래스에 혼합하는 별도의 특성이 있다면 할 수 있습니다

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

대신에

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

Don't use Logula

I've actually followed the recommendation of Eugene and tried it and found out that it has a clumsy configuration and is subjected to bugs, which don't get fixed (such as this one). It doesn't look to be well maintained and it doesn't support Scala 2.10.

Use slf4s + slf4j-simple

Key benefits:

  • Supports latest Scala 2.10 (to date it's M7)
  • Configuration is versatile but couldn't be simpler. It's done with system properties, which you can set either by appending something like -Dorg.slf4j.simplelogger.defaultlog=trace to execution command or hardcode in your script: System.setProperty("org.slf4j.simplelogger.defaultlog", "trace"). No need to manage trashy config files!
  • Fits nicely with IDEs. For instance to set the logging level to "trace" in a specific run configuration in IDEA just go to Run/Debug Configurations and add -Dorg.slf4j.simplelogger.defaultlog=trace to VM options.
  • Easy setup: just drop in the dependencies from the bottom of this answer

Here's what you need to be running it with Maven:

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

This is how I got Scala Logging working for me:

Put this in your build.sbt:

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

Then, after doing an sbt update, this prints out a friendly log message:

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

If you are using Play, you can of course simply import play.api.Logger for writing log messages: Logger.debug("Hi").

See the docs for more info.


I pulled a bit of work form the Logging trait of scalax, and created a trait that also integrated a MessageFormat-based library.

Then stuff kind of looks like this:

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

We like the approach so far.

Implementation:

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

I use SLF4J + Logback classic and apply it like this:

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

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

Then you can use it whichever fits your style better:

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

but this approach of course uses a logger instance per class instance.


You should have a look at the scalax library : http://scalax.scalaforge.org/ In this library, there is a Logging trait, using sl4j as backend. By using this trait, you can log quite easily (just use the logger field in the class inheriting the trait).


Writer, Monoid and a Monad implementation.


Haven't tried it yet, but Configgy looks promising for both configuration and logging:

http://github.com/robey/configgy/tree/master


After using slf4s and logula for a while, I wrote loglady, a simple logging trait wrapping slf4j.

It offers an API similar to that of Python's logging library, which makes the common cases (basic string, simple formatting) trivial and avoids formatting boilerplate.

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


I find very convenient using some kind of java logger, sl4j for example, with simple scala wrapper, which brings me such syntax

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

object User with dsl.logging {

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

}

In my opinion very usefull mixin of java proven logging frameworks and scala's fancy syntax.


Quick and easy forms.

Scala 2.10 and older:

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

And build.sbt:

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

Scala 2.11+ and newer:

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

And build.sbt:

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

참고URL : https://stackoverflow.com/questions/978252/logging-in-scala

반응형