Logback은 Java 기반의 Logging Framework로 매우 많은 기능을 갖고 있습니다.
오늘은 Logback을 통해서, 어떻게 Slack으로 message를 보낼 수 있을지 알아볼 것입니다.
Appender는 로그 이벤트를 특정한 대상에 출력하는 역할을 담당하는 것으로, Logback에서는 다양한 종류의 Appender를 제공하여 로그를 파일, 콘솔, 데이터베이스, 원격 서버 등 다양한 대상에 출력할 수 있습니다.
Appender를 통해서 로그 메시지의 형식을 지정하고, 필터링 조건을 적용하고, 로그 이벤트를 대상에 전달하는 일을 할 수 있습니다.
logback.xml 파일을 구성하고 관리할 수 있으며, 필요에 따라 다양한 Appender를 조합하여 로그를 다양한 대상에 동시에 출력하는 것도 가능합니다.
이번 Slack Appender는 Slack의 Incoming Webhook을 이용해 구현할 것이며, 먼저 Incoming Webhook 부터 알아 볼 것입니다.
Slack에서 제공하는 Slack 채널에 메시지를 보낼 수 있는 API 같은 것으로, 이 Incoming Webhook을 설정하면 외부에서도 요청을 통해 Slack에 메시지를 보낼 수 있습니다.
Slack Incoming Webhook을 설정하는 방법은 이 글을 참고하시면 좋을 것 같습니다.
위 글을 따라하신 후, 얻게 되는 Slack Webhook Url을 사용하면 됩니다.
logback에는 appender를 구현할 수 있는 AppenderBase라는 인터페이스가 존재하고, AppenderBase<ILoggingEvent> 를 구현하면 그것을 Appender로 사용할 수 있습니다.
아래 코드는 RestTemplate과 AppenderBase를 이용해 Slack Appender를 구현한 예시입니다.
class SlackAppender : AppenderBase<ILoggingEvent> {
private val webhookUrl = "webhookurl"
private val channel = "channel"
override fun start() {
if (webhookUrl.isEmpty() || channel.isEmpty()) {
addError("SlackAppender is not configured properly. Please set the webhookUrl and channel.")
return
}
super.start()
}
override fun append(event: ILoggingEvent) {
val restTemplate = RestTemplate()
val headers = HttpHeaders().apply {
contentType = MediaType.APPLICATION_JSON
}
val payload = mapOf(
"channel" to channel,
"text" to event.formattedMessage
)
val request = HttpEntity(payload, headers)
val response: ResponseEntity<String> = restTemplate.postForEntity(webhookUrl, request, String::class.java)
}
}
주의해야 할 것은 결국 slack logging은 slack에 http 통신을 통해 메시지를 남기는 것이기 때문에, 이것을 비동기로 처리하지 않는다면 logging에 의해 서비스 로직의 속도가 느려질 수 있다는 문제가 있습니다.
이를 위해 xml 설정시 AsyncAppender를 기반으로 동작할 수 있도록 logback.xml 파일을 설정해줘야 합니다.
<configuration>
<!-- 다른 config -->
<appender name="SlackAppender" class="com.test.SlackAppender" />
<appender name="AyncSlackAppender" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="SlackAppender" />
</appender>
<logger name="AsyncSlackLogger" level="INFO">
<appender-ref ref="AsyncSlackAppender" />
</root>
</configuration>
위와 같이 Appender를 구현하고, xml 파일을 설정했다면 실제로 다음과 같은 방식으로 Slack에 메시지를 보낼 수 있습니다.
@Service
class TestService {
private val slackLogger = LoggerFactory.getLogger("AsyncSlackLogger")
fun test() {
slackLogger.info("테스트입니다")
}
}