開発部のTです。
今回はlogbackの機能を使って、intra-martでエラーが発生した時にSlackにエラー内容を投稿する方法を紹介します。
Slackの設定
SlackのIncoming Webhooks機能を使って、 特定のチャンネルにintra-martのエラー内容を投稿するためのWebhook URLを発行します。 (手順の紹介は省きます)
自社ではエラーが発生すると、:imp:
の絵文字で投稿するように設定しています。
Appenderの実装
Appenderによって、エラーログをSlack APIの仕様に基づいたJSON形式に変換し、Webhook URLに対してPOST送信します。 長文のエラーログをSlackに投稿できるように、attachments属性にエラーログを設定しています。
以下Appenderのソースです。
package jp.co.gsol.logback.appender; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Layout; import ch.qos.logback.core.UnsynchronizedAppenderBase; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.arnx.jsonic.JSON; public class SlackAppender extends UnsynchronizedAppenderBase<ILoggingEvent> { private static final String PRETEXT = "【社内システム】iAPエラーログ"; private String url; private String channel; private Layout<ILoggingEvent> layout; private int timeout = 10000; @Override protected void append(final ILoggingEvent event) { try { final URL apiUrl = new URL(url); final StringWriter w = new StringWriter(); w.append("payload=").append(URLEncoder.encode(createAttachmentsStr(layout.doLayout(event)), "UTF-8")); final byte[] bytes = w.toString().getBytes("UTF-8"); final HttpURLConnection con = (HttpURLConnection) apiUrl.openConnection(); con.setRequestMethod("POST"); con.setDoOutput(true); con.setConnectTimeout(timeout); con.setReadTimeout(timeout); con.setFixedLengthStreamingMode(bytes.length); con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); final OutputStream os = con.getOutputStream(); os.write(bytes); os.flush(); os.close(); } catch (IOException e) { addError(channel + "投稿時にエラーが発生しました", e); } } /** * ログフォーマットをJSON形式に変換 * @param text * @return */ private String createAttachmentsStr(final String text) { List<Map<String, Object>> attachments = new ArrayList<>(); Map<String, Object> attachment = new HashMap<>(); attachment.put("pretext", PRETEXT); attachment.put("text", text); attachments.add(attachment); Map<String, Object> map = new HashMap<>(); map.put("attachments", attachments); return JSON.encode(map); } public String getUrl() { return url; } public void setUrl(final String url) { this.url = url; } public String getChannel() { return channel; } public void setChannel(final String channel) { this.channel = channel; } public Layout<ILoggingEvent> getLayout() { return layout; } public void setLayout(final Layout<ILoggingEvent> layout) { this.layout = layout; } public int getTimeout() { return timeout; } public void setTimeout(int timeout) { this.timeout = timeout; } }
im_logger.xmlの設定
im_logger.xmlにSlackAppenderの設定を行います。
intra-martのログ仕様書に基づいて、
ログ出力したい情報を<layout>
タグに設定します。<url>
タグにはSlackのWebhook URLを設定します。
以下、自社のim_logger.xmlの設定の抜粋です。
<appender name="SLACK" class="jp.co.gsol.logback.appender.SlackAppender"> <channel>#in-house-error-log</channel> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] thread: [%thread] level: [%-5level] logger: [%logger{255}] tenant id: [%X{tenant.id}] log id: [%X{log.id}] request id: [%X{request.id}] user type: [%X{user.type}] authenticated: [%X{authenticated}] user cd: [%X{user.cd}] log message code: [%X{log.message.code}] message: %msg%n %ex{full} </pattern> </layout> <url>https://hooks.slack.com/services/XXXXXXX/YYYYYYY/ZZZZZZZZZZZZZZZZZZZZZ</url> </appender> <appender name="ASYNC_SLACK" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="SLACK" /> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> </appender> <root> <level value="info" /> <appender-ref ref="ASYNC_SLACK" /> </root>
Slackに投稿される内容
intra-martでエラーが発生すると、Slackに↓の様な投稿が自動で行われます。
投稿を展開するとExceptionの詳細が見れます。
Exceptionが長すぎると、途中で省略されてしまうので、いつか修正したいです。
以上、intra-martのエラー発生時にSlackに投稿する方法の紹介でした。