Пам'ятка по логування в scala і взагалі світі java, записки програміста

Жодне серйозне додаток не обходиться без логування, будь то сайтик, GUI або навіть що-небудь під Android. У світі Java ситуація з логування на перший погляд дещо заплутана. Є якісь SLF4J, якийсь Logback, для чогось потрібно створювати XML-файли, ось це все. Але, як це часто буває, якщо сісти, і не поспішаючи у всьому розібратися, насправді все виявляється дуже просто і логічно.

У випадку зі Scala є заслуговує на увагу бібліотека scala-logging. є обгорткою над SLF4J. Використовуючи макроси Scala. вона додає перевірку перед записом рядка в лог, чи буде при поточних настройках цей рядок насправді кудись записана.

Тобто, ви пишете:

log. debug # 40; s "Test $ msg" # 41;

... а після розгортання макросу це перетворюється в:

if # 40; log. isDebugEnabled # 41; log. debug # 40; s "Test $ msg" # 41;

В результаті, якщо налагоджувальні логи відключені, не буде виділятися і звільнятися пам'ять під рядок, не буде виконуватися інтерполяція, і так далі. Таким чином отримуємо істотно бо більшу продуктивність.

Давайте спробуємо прикрутити логирование до нашого REST-сервісу на базі Finagle. У build.sbt дописуємо залежності:

"Ch.qos.logback"% "logback-classic"% "1.1.3",
"Com.typesafe.scala-logging" %% "scala-logging"% "3.1.0"

У конструкторі класу FinagleServiceExample створюємо логер:

import com. typesafe. scalalogging. _
import org. slf4j. LoggerFactory

private val logger = Logger # 40; LoggerFactory. getLogger # 40; this. getClass # 41; # 41;

Після чого беремо і просто пишемо логи:

logger. info # 40; s "service started" # 41;
logger. debug # 40; s "reading $ key" # 41;
logger. error # 40; s "bad request: $ req" # 41;

Існують такі рівні логування, від меншого до більшого: TRACE, DEBUG, INFO, WARN, ERROR. В налаштуваннях, мова про які піде нижче, вибирається ефективний рівень. При виборі певного ефективного рівня в лог потрапляють усі повідомлення даного рівня і вище. Наприклад, якщо обраний ефективний рівень INFO, в логах ви побачите все INFO, WARN і ERROR повідомлення. Крім того, є особливий ефективний рівень OFF, який відключає всі логирование.

Logback шукає файл з настройками за такими правилами:

  1. Якщо в classpath є logback.groovy, використовується він;
  2. Інакше в classpath шукається файл logback-test.xml;
  3. Якщо немає і його, пробуємо знайти logback.xml;
  4. Якщо і він не знайдений, використовуємо стандартні параметри, тобто, пишемо просто в консоль;

Давайте покладемо в src / test / resources файл logback-test.xml такого змісту:





. % -5level [% thread]% logger -% msg% n





Як нескладно здогадатися, тут ми говоримо Logback писати всі повідомлення рівня DEBUG і вище в STDOUT, використовуючи заданий формат. Якщо тепер запустити тести, у висновку ви дійсно побачите все DEBUG, INFO і ERROR логи. Можете замінити рівень в рядку на INFO або ERROR і переконатися, що логів стає менше.

В каталозі src / main / resources створимо logback.xml трохи іншого змісту:





.ate% -5level [% thread]% logger -% msg% n



finagle-example.log


.ate% -5level [% thread]% logger -% msg% n






Ці настройки теж в особливих пояснень не потребують. Ми говоримо писати як в консоль, так і в файл, використовуючи трохи інший формат логів. Можна зібрати standalone jar, використовуючи команду:

... потім запустити його, сказавши:

java -jar. / Target / scala- 2.11 / finagle-example-assembly- 0.1 .jar

... і перевірити, що Logback успішно підхоплює налаштування.

Можна перевизначити налаштування без пересборки jar, сказавши:

java -Dlogback.configurationFile = path / to / logback.xml \
-jar. / Target / scala- 2.11 / finagle-example-assembly- 0.1 .jar

Можна змусити Logback автоматично перечитувати документацію, змінивши перший рядок в logback.xml приблизно так:

Можна фільтрувати логи по класах і пакетам, при цьому щодо ієрархій працює інтуїтивна семантика:

У appender-секціях можна вказувати мінімальний рівень повідомлень:


INFO

Список конкретних пакетів і класів можна направляти в задані аппендери:



Можна налаштувати ротацію і архівацію логів:

class = "ch.qos.logback.core.rolling.RollingFileAppender">

/path/to/application.log

.ate% -5level [% thread]% logger -% msg% n

class = "ch.qos.logback.core.rolling.FixedWindowRollingPolicy">

/path/to/application.%i.log.zip
1
10

class = "ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">

2MB

class = "ch.qos.logback.core.rolling.RollingFileAppender">

/path/to/application.log

.ate% -5level [% thread]% logger -% msg% n

class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

/path/to/application-..log.gz

10

Як бачите, все дуже гнучко, дуже потужно і не сказати, щоб супер складно.

А чим ви пишете логи?