Вход в Scala
Что такое хороший способ сделать вход в приложение Scala? Что-то, что согласуется с философией языка, не загромождает код, а является низким уровнем обслуживания и ненавязчивым. Вот список основных требований:
- простой
- не загромождать код. Scala отлично подходит для своей краткости. Я не хочу, чтобы половина моего кода регистрировала операторы
- формат журнала может быть изменен, чтобы соответствовать остальной части моих корпоративных журналов и мониторинга программное обеспечение
- поддерживает уровни ведения журнала (т. е. отладки, трассировки, ошибки)
- может войти на диск, а также в другие места назначения (т. е. сокет, консоль и т. д.)
- минимальная конфигурация, если какой-либо
- строительство в контейнерах (т. е. веб-сервер)
- (необязательно, но приятно иметь) поставляется либо как часть языка, либо как артефакт maven, поэтому мне не нужно взломать мои сборки, чтобы использовать его
Я знаю, что могу использовать существующие решения для ведения журнала Java, но они терпят неудачу по крайней мере на двух из вышеперечисленных, а именно беспорядок и конфигурация.
Спасибо за ваши ответы.
13 ответов:
фантики slf4j
большинство библиотек журналов Scala были некоторыми оболочками вокруг Java logging framework (slf4j, log4j и т. д.), Но по состоянию на март 2015 года сохранившиеся библиотеки журналов-это все slf4j. эти библиотеки журналов предоставляют своего рода
logобъект, к которому можно обратитьсяinfo(...),debug(...)и т. д. Я не большой поклонник slf4j, но теперь, похоже, это преобладающая структура ведения журнала. Вот описание SLF4J:Простой Logging Facade for Java или (SLF4J) служит простым фасадом или абстракцией для различных фреймворков ведения журнала, например java.утиль.logging, log4j и logback, что позволяет конечному пользователю подключать нужную структуру ведения журнала во время развертывания.
возможность изменения базовой библиотеки журналов во время развертывания дает уникальную характеристику всему семейству регистраторов slf4j, о которой вам нужно знать:
- classpath as конфигурация подход. Способ slf4j знает, какую базовую библиотеку журналов вы используете, загружая класс по некоторому имени. У меня были проблемы, в которых slf4j не распознал мой регистратор, когда classloader был настроен.
- потому что простой фасад пытается быть общим знаменателем, он ограничен только фактическими вызовами журнала. Другими словами, конфигурация не может быть выполнена с помощью кода.
в большом проекте это может быть удобно иметь возможность контролировать поведение журнала транзитивных зависимостей, если все использовали slf4j.
Scala Logging
Scala Logging написано Хайко Сеебергер в качестве преемника его slf4s. Он использует макрос для расширения вызовов в выражение if, чтобы избежать потенциально дорогостоящего вызова журнала.
Scala Logging-это удобная и производительная библиотека журналов, обертывающая библиотеки журналов, такие как SLF4J и потенциально другие.
исторические лесорубы
С помощью Scala 2.10 + рассмотрим Скалалогирование по типам. Использует макросы для доставки очень чистого API
https://github.com/typesafehub/scala-logging
цитирую из Вики:
к счастью, макросы Scala могут быть использованы, чтобы сделать нашу жизнь проще: ScalaLogging предлагает класс
Loggerс облегченными методами ведения журнала, которые будут расширены до вышеуказанной идиомы. Так что все, что мы должны написать это:logger.debug(s"Some ${expensiveExpression} message!")после применения макроса код будет преобразован в описанную выше идиому.
кроме того, Скалалогирование предлагает признак
Logging, который удобно представленLoggerэкземпляр инициализируется с именем класса, смешанного в:import com.typesafe.scalalogging.slf4j.LazyLogging class MyClass extends LazyLogging { logger.debug("This is very convenient ;-)") }
использование slf4j и оболочки приятно, но использование его встроено в интерполяцию ломается, когда у вас есть более двух значений для интерполяции, с тех пор вам нужно создать массив значений для интерполяции.
более Scala как решение заключается в использовании thunk или кластера для задержки конкатенации сообщения об ошибке. Хорошим примером этого является регистратор Lift
который выглядит как это:
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))
не используйте Logula
Я на самом деле следовал рекомендации Евгения и попробовал его и узнал, что он имеет неуклюжую конфигурацию и подвергается ошибкам, которые не исправляются (например,этот). Он не выглядит в хорошем состоянии, и это не поддерживает Scala 2.10.
используйте slf4s + slf4j-simple
ключевые преимущества:
- поддерживает последнюю версию Scala 2.10(to дата это М7)
- конфигурация универсальна, но не может быть проще. Это делается с свойства системы, который вы можете установить либо добавляя что-то вроде
-Dorg.slf4j.simplelogger.defaultlog=traceдля выполнения команды или записать в ваш скрипт:System.setProperty("org.slf4j.simplelogger.defaultlog", "trace"). Не нужно управлять дрянными конфигурационными файлами!- прекрасно сочетается с IDEs. Например, чтобы установить уровень ведения журнала для "трассировки" в определенной конфигурации запуска в IDEA просто перейдите к
Run/Debug Configurationsи добавить-Dorg.slf4j.simplelogger.defaultlog=tracetoVM 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>
вот как я получил 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").посмотреть docs для получения дополнительной информации.
я вытащил немного работы из
Loggingчертscalax, и создал черту, которая также интегрировала aMessageFormat-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)) }
Я использую 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") }но этот подход использует экземпляр logger для каждого экземпляра класса.
вы должны взглянуть на библиотеку scalax : http://scalax.scalaforge.org/ В этой библиотеке есть функция ведения журнала, использующая sl4j в качестве бэкэнда. Используя эту особенность, вы можете войти довольно легко (просто используйте поле logger в классе, наследующем признак).
еще не пробовал, но Configgy выглядит многообещающе как для конфигурации, так и для ведения журнала:
после использования slf4s и logula на некоторое время, я написал
loglady, простая запись признака обертывания slf4j.он предлагает API, похожий на библиотеку журналов Python, что делает общие случаи (базовая строка, простое форматирование) тривиальными и позволяет избежать форматирования шаблона.
Мне очень удобно использовать какой-то Java logger, sl4j например, с простой оболочкой scala, которая приносит мне такой синтаксис
val #! = new Logger(..) // somewhere deep in dsl.logging. object User with dsl.logging { #! ! "info message" #! dbg "debug message" #! trace "var a=true" }на мой взгляд, очень полезное сочетание проверенных Java фреймворков ведения журнала и причудливого синтаксиса scala.
быстрые и легкие формы.
Scala 2.10 и старше:
import com.typesafe.scalalogging.slf4j.Logger import org.slf4j.LoggerFactory val logger = Logger(LoggerFactory.getLogger("TheLoggerName")) logger.debug("Useful message....")и строить.СБТ:
libraryDependencies += "com.typesafe" %% "scalalogging-slf4j" % "1.1.0"Scala 2.11+ и новее:
import import com.typesafe.scalalogging.Logger import org.slf4j.LoggerFactory val logger = Logger(LoggerFactory.getLogger("TheLoggerName")) logger.debug("Useful message....")и строить.СБТ:
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0"
Comments