일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Hyperledger fabric gossip protocol
- Golang
- 스위프트
- 엔터프라이즈 블록체인
- 파이썬
- hyperledger fabric
- Actor
- play2 강좌
- Adapter 패턴
- 파이썬 데이터분석
- 이더리움
- Akka
- play 강좌
- CORDA
- 스칼라 강좌
- 하이브리드앱
- akka 강좌
- 스칼라
- 하이퍼레저 패브릭
- 파이썬 강좌
- 그라파나
- 주키퍼
- 블록체인
- Play2
- 안드로이드 웹뷰
- 파이썬 동시성
- 스칼라 동시성
- 파이썬 머신러닝
- Play2 로 웹 개발
- 플레이프레임워크
- Today
- Total
HAMA 블로그
예제로 보는 아카(akka) - 16. 로깅 (Logging) 본문
- Scala 2.11.8 기반
- Akka 2.4.11 기반
- Java 8 (akka 2.4 부터는 java 8 요구함. scala 2.11 은 java 7도 괜찮지만~)
로깅 (Logging)
실전에서 로깅은 매우 중요합니다. 아카 프레임워크는 내부 로깅 시스템도 있으며 외부 로깅프레임워크 또한 지원 하는데요. 이렇게 혼재하다보니 처음에 아카를 할 때 로깅에 애를 먹을 수 도 있습니다. 다음 예를 따라해보면서 감을 익혀 보겠습니다.
* self4j 나 logback 그 자체에 대한 정보는 다른글을 참고하세요.
* 모두 테스트하여 제대로 작동되는 것을 확인하였습니다.
* 하지만 이게 최선의 방법이라거나 제가 설명한 내용이 100% 정확하다는 보장은 못해드립니다. OTL.
0. 기본 프로젝트 생성
가장 기본적인 프로젝트를 하나 만듭니다. 아래와 같이 간단한 코드를 작성합니다.
class HelloWorld extends Actor {
override def receive: Receive = {
case msg : String => println(s"hi $msg")
}
}
object maintest extends App{
println("application start") <-------- (1)
val system = ActorSystem("helloAkka")
val actor = system.actorOf(Props[HelloWorld])
actor ! "hama"
}
처음엔 편하게 (1) println 을 이용하여 로그를 출력합니다. stdout 으로 출력됩니다.
1. 로깅 - 내부로깅 akka.event.Logging 사용
import akka.event.Logging class HelloWorld extends Actor {
val log = Logging(context.system, this)
override def receive: Receive = {
case msg : String => log.info(s"hi $msg")
}
}
- 이번에는 Logging 을 사용하여 출력 합니다.
- 이 경우는 Akka 내부에 가지고 있는 로깅객체를 이용합니다. akka.evnet.Logging 을 임포트 하였습니다.
- 인자로 ActorSystem 이 필요합니다.
- 이것도 역시 stdout 으로 출력됩니다.
2. 로깅 - 내부 로깅 ActorLogging 사용
import akka.actor.ActorLogging class HelloWorld extends Actor with ActorLogging{
override def receive: Receive = {
case msg : String => log.info(s"hi $msg")
}
}
- 이번에는 ActorLogging 을 상속받아서 사용합니다.
- akka.actor.ActorLogging 을 임포트 하였습니다.
- 이것도 역시 stdout 으로 출력됩니다.
resources/application.conf 를 만들고 아래와 같이 넣어주면
akka {
loggers = ["akka.event.Logging$DefaultLogger"]
loglevel = "error"
}
- error 이상만 출력되도록 했기 때문에 위에 로깅이 출력되지 않습니다.
- loglevel = "debug" 로 하면 잘 출력되겠지요. debug 까지 출력됩니다.( debug - info - warning - error )
아래 처럼 {} (placeholder) 를 이용하여 여러 정보를 간편히 넣을 수 있습니다.
log.info(s"hi $msg and {} , {} ", "one", "two")
3. 로깅 - 외부 프레임워크 사용해서 file 에도 쓰기
build.sbt 에 외부 로깅프레임워크에 대한 의존성을 추가합니다.
libraryDependencies ++= Seq(
"ch.qos.logback" % "logback-classic" % "1.1.7",
"com.typesafe.akka" % "akka-slf4j_2.11" % "2.4.8")
* 읽을거리 : logback 을 사용해야 하는 이유
resources/application.conf 에는 아래와 같이 넣어주시구요.
akka {
# event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
loggers = ["akka.event.slf4j.Slf4jLogger"]
loglevel = "DEBUG"
}
원격 actor 일 경우는 다음과 같습니다.
Provider {
akka {
loggers = ["akka.event.slf4j.Slf4jLogger"]
loglevel = "DEBUG"
actor.provider = "akka.remote.RemoteActorRefProvider"
remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "192.168.1.45"
port = 24321
}
}
}
* 즉 remote 액터가 설정되있으면 여기도 loggers 설정해줘야 remote 액터들의 로그도 logback.xml 설정대로 작동됩니다.
* 로깅 전략
resources/logback.xml 을 만들어서 아래와 같이 넣어주십시요.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<encoder>
<pattern>%X{akkaTimestamp} %-5level[%thread] %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logs/akka.log</file>
<append>true</append>
<encoder>
<pattern>%date{yyyy-MM-dd} %X{akkaTimestamp} %-5level[%thread] %logger{1} - %msg%n</pattern>
</encoder>
</appender>
<logger name="akka" level="DEBUG" />
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
- logs/akka.log 파일에 로그가 출력됩니다.
- DEBUG 레벨 이상 모두 로깅됩니다.
위의 FILE Appender 의 경우 하나의 파일에 계속 로깅을 합니다. 따라서 로그파일을 압축시키거나 날짜별로 관리해줄 필요가 생깁니다. 이때는 다른 Appender 를 만들어서 사용하면 됩니다.
* 파일 용량별 구분 Appender
<!-- 용량이 차면 압축해주는 로깅 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/hello.log</file>
<encoder>
<pattern>%date %level %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<maxIndex>10</maxIndex>
<FileNamePattern>logs/hello.log.%i.gz</FileNamePattern>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
</appender>
- 위의 경우는 10MB 이내의 10개의 압축파일을 만들며 , 그 이후에는 압축하지 않고 계속 하나의 파일에 쓰게 됩니다.
* 날짜별 구분 파일 Appender
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{dd-MM-yyyy}.log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date %level %msg%n</pattern>
</encoder>
</appender>
- 날짜별로 하나의 로그파일을 저장해 둡니다.
- 최근 30일치의 로그를 남겨둡니다. 즉 하루가 지나면 가장 옛날 로그파일 하나를 지웁니다.
팁 : 파일이름 뒤에 .zip .gz 처럼 압축형식을 적어주면 자동으로 압축해서 보관합니다.
* 로그 사용 방법
기존 처럼 아래와 같이 사용하시면 됩니다.
import akka.actor.ActorLogging class HelloWorld extends Actor with ActorLogging{
override def receive: Receive = {
case msg : String => log.info(s"hi $msg")
}
}
기존에는 stdout 에만 출력되었다면 이제는 file에도 출력됩니다. logs/로그파일명.log 파일을 확인하세요.
2016-12-26 INFO [helloAkka-akka.actor.default-dispatcher-4] a.e.s.Slf4jLogger - Slf4jLogger started
2016-12-26 08:41:11.329UTC DEBUG[helloAkka-akka.actor.default-dispatcher-4] a.e.EventStream - logger log1-Slf4jLogger started
2016-12-26 08:41:11.331UTC DEBUG[helloAkka-akka.actor.default-dispatcher-4] a.e.EventStream - Default Loggers started
2016-12-26 08:41:11.350UTC INFO [helloAkka-akka.actor.default-dispatcher-4] HelloWorld - hi hama
4. ActorLogging 과 scala-logging 의 혼용
액터 내에서 로거 인스턴스를 제공해야 할 때 ActorLogging 을 사용하는 것은 자연스러운 일입니다. 그러나 때때로 scala-logging(예 : LazyLogging 또는 StrictLogging)으로 로깅하는 것을 볼 수 있습니다. 일반적으로 액터 모델이 Dataflow or Reactive Stream 을 만나는 코드에서 볼 수 있는데요. 이 두 솔루션을 서로 같이 사용할 수 있을까요? 자세한 내용을 살펴 보겠습니다.
ActorLogging은 Akka와 깊이 통합되어 있습니다. 기본적으로 Mapping Diagnostic Context (DiagnosticActorLogging 참조)에는 액터 트리에있는 액터의 전체 경로를 비롯하여 많은 유용한 정보가 있습니다. 또한 로깅 설정 중 일부는 Akka 구성과 공유되기 때문에 application.conf에서 akka.loglevel을 변경하면 액터가 보고하는 로그에 영향을 미칩니다. 또한 ActorLogging에서 제공하는 로그 인스턴스는 액터 내부에서 사용되기 때문에 지연 된 계산 (예 : Futures)에 전달하지 말아야한다는 점도 중요합니다.
반면 scala-logging 은 보다 일반적인 솔루션입니다. Akka와의 연결이 없으므로 액터의 적절한 컨텍스트를 제공 할 수 없습니다. 또한 로깅 구성은 Akka 설정과 완전히 분리되어 있습니다. 로거 인스턴스를 보호 할 필요가 없으므로 필요할 때마다 전달할 수 있습니다.
요약하면, Actor 본문 내부에서 로깅이 발생할 때마다 ActorLogging을 사용하여 로깅 정보의 컨텍스트를 유지합니다. 다른 모든 장소에서는 스칼라 로깅을 사용하십시오.
예)
의존성 추가
libraryDependencies += "com.typesafe.scala-logging" % "scala-logging-slf4j_2.11" % "2.1.2"
ActorLogging 과 LazyLogging 을 함께 사용하는 모습
import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
import com.typesafe.scalalogging.slf4j.LazyLogging
/**
* Created by hama on 2016-12-26.
*/
class HelloWorld extends Actor with ActorLogging with LazyLogging {
override def receive: Receive = {
case msg : String =>
log.info(s"hi $msg")
logger.info("strictLogging...........................")
}
}
참고)
'Akka' 카테고리의 다른 글
예제로 보는 아카(akka) - 18. 서비스로 설치 ( Deploying ) (0) | 2016.12.27 |
---|---|
예제로 보는 아카(akka) - 17. 설치 ( Deploying ) (0) | 2016.12.26 |
액터 없이 Akka 사용하기 (0) | 2016.12.02 |
내가 Akka Actors 를 좋아하지 않는 이유 [번역] (0) | 2016.12.02 |
액터 모델의 문제점 (0) | 2016.12.02 |