Вход в Скала - PullRequest
       47

Вход в Скала

159 голосов
/ 11 июня 2009

Что такое хороший способ входа в приложение Scala? Что-то, что согласуется с философией языка, не загромождает код, а также требует минимального обслуживания и ненавязчиво. Вот список основных требований:

  • простой
  • не загромождает код. Scala отлично подходит для своей краткости. Я не хочу, чтобы половина моего кода записывала операторы
  • формат журнала может быть изменен, чтобы соответствовать остальной части моего корпоративного журнала и программного обеспечения для мониторинга
  • поддерживает уровни ведения журнала (т.е. отладка, трассировка, ошибка)
  • может вести запись на диск, а также в другие места назначения (например, сокет, консоль и т. Д.)
  • минимальная конфигурация, если есть
  • работает в контейнерах (т. Е. Веб-сервер)
  • (необязательно, но приятно иметь) поставляется как часть языка или как артефакт maven, поэтому мне не нужно взламывать свои сборки, чтобы использовать его

Я знаю, что могу использовать существующие решения для ведения журналов Java, но они терпят неудачу, по крайней мере, в двух из вышеперечисленных, а именно в беспорядке и конфигурации.

Спасибо за ваши ответы.

Ответы [ 13 ]

117 голосов
/ 11 июня 2009

упаковщики slf4j

Большинство библиотек журналов Scala были некоторыми оболочками вокруг среды журналирования Java (slf4j, log4j и т. Д.), Но по состоянию на март 2015 г. все выжившие библиотеки журналов были slf4j. Эти библиотеки журналов предоставляют некоторый объект log, к которому вы можете обращаться info(...), debug(...) и т. Д. Я не большой поклонник slf4j, но сейчас он, кажется, является преобладающей структурой ведения журналов. Вот описание SLF4J :

Simple Logging Facade for Java или (SLF4J) служит простым фасадом или абстракцией для различных каркасов, например, java.util.logging, log4j и logback, позволяющие конечному пользователю подключить необходимую инфраструктуру ведения журналов во время развертывания.

Возможность изменять базовую библиотеку журналов во время развертывания дает уникальную характеристику всему семейству регистраторов slf4j, о которой вам необходимо знать:

  1. classpath в качестве конфигурации подход. Slf4j знает, какую библиотеку логов вы используете, загружая класс по какому-либо имени. У меня были проблемы, из-за которых slf4j не распознавал мой регистратор при настройке загрузчика классов.
  2. Поскольку простой фасад пытается быть общим знаменателем, он ограничен только реальными вызовами журнала. Другими словами, конфигурация не может быть выполнена с помощью кода.

В большом проекте, на самом деле, было бы удобно иметь возможность контролировать поведение журналирования транзитивных зависимостей, если бы каждый использовал slf4j.

Scala Logging

Scala Logging написано Хейко Сибергером как преемник его slf4s . Он использует макрос для расширения вызовов в выражение if, чтобы избежать потенциально дорогих вызовов журнала.

Scala Logging - это удобная и эффективная библиотека журналирования, заключающая в себе библиотеки журналирования, такие как SLF4J и потенциально другие.

Исторические регистраторы

  • Logula , обертка Log4J, написанная Coda Hale. Раньше нравился этот, но теперь заброшен.
  • configgy , оболочка java.util.logging, которая была популярна в ранние времена Scala. Сейчас заброшен.
61 голосов
/ 19 февраля 2013

С Scala 2.10+ Рассмотрим ScalaLogging от Typesafe. Использует макросы для доставки очень чистого API

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

Цитата из их вики:

К счастью, макросы Scala могут сделать нашу жизнь проще: ScalaLogging предлагает класс Logger с облегченными методами ведения журналов, которые будут расширены до вышеприведенной идиомы. Итак, все, что нам нужно написать:

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

После применения макроса код будет преобразован в описанную выше идиому.

Кроме того, ScalaLogging предлагает черту Logging, которая удобно предоставляет экземпляр Logger, инициализированный с именем класса, смешанным с:

import com.typesafe.scalalogging.slf4j.LazyLogging

class MyClass extends LazyLogging {
  logger.debug("This is very convenient ;-)")
}
14 голосов
/ 13 июня 2009

Использование slf4j и обертки - это хорошо, но использование встроенной интерполяции ломается, когда у вас есть более двух значений для интерполяции, поскольку тогда вам нужно создать массив значений для интерполяции.

Более похожее на Scala решение состоит в том, чтобы использовать thunk или кластер для задержки объединения сообщений об ошибках. Хорошим примером этого является регистратор лифта

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))
12 голосов
/ 25 августа 2012

Не используйте логулу

Я на самом деле последовал рекомендации Юджина, попробовал ее и обнаружил, что она имеет неуклюжую конфигурацию и подвержена ошибкам, которые не исправляются (например, эта ). Он не выглядит в хорошем состоянии и не поддерживает Scala 2.10 .

Используйте slf4s + slf4j-simple

Основные преимущества:

  • Поддерживает последнюю версию Scala 2.10 (на сегодняшний день это M7)
  • Конфигурация универсальна, но не может быть проще. Это делается с помощью системных свойств , которые вы можете установить, добавив что-то вроде -Dorg.slf4j.simplelogger.defaultlog=trace к команде выполнения или жесткому коду в вашем скрипте: System.setProperty("org.slf4j.simplelogger.defaultlog", "trace"). Нет необходимости управлять мусорными конфигурационными файлами!
  • Хорошо вписывается в IDE. Например, чтобы установить уровень трассировки «трассировка» в определенной конфигурации запуска в IDEA, просто перейдите на Run/Debug Configurations и добавьте -Dorg.slf4j.simplelogger.defaultlog=trace к VM options.
  • Простая настройка: просто опустите зависимости внизу этого ответа

Вот что вам нужно, чтобы запустить его с 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>
11 голосов
/ 28 июня 2015

Вот так у меня Scala Logging работает на меня:

Поместите это в ваш build.sbt:

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

Затем, после выполнения sbt update, выводится дружественное лог-сообщение:

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

Если вы используете Play, вы, конечно, можете просто import play.api.Logger для написания сообщений журнала: Logger.debug("Hi").

См. документы для получения дополнительной информации.

7 голосов
/ 11 июня 2009

Я немного потрудился над чертой Logging, равной scalax, и создал черту, которая также интегрировала библиотеку MessageFormat-based.

Тогда все выглядит примерно так:

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

Нам нравится подход.

Реализация:

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))  
}
6 голосов
/ 21 июня 2012

Я использую SLF4J + Logback classic и применяю его так:

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

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

Тогда вы можете использовать его в зависимости от вашего стиля:

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

но этот подход, конечно, использует экземпляр регистратора для каждого экземпляра класса.

4 голосов
/ 02 февраля 2011

Writer, Monoid и реализация Monad.

4 голосов
/ 11 июня 2009

Вы должны взглянуть на библиотеку scalax: http://scalax.scalaforge.org/ В этой библиотеке есть черта Logging, использующая sl4j в качестве бэкэнда. Используя эту черту, вы можете легко войти в систему (просто используйте поле logger в классе, унаследовавшем черту).

3 голосов
/ 11 июня 2009

Еще не пробовал, но Configgy выглядит многообещающе как для конфигурации, так и для ведения журнала:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...