logback
GoogleCloudPlatform
intra-mart
stackdriver
StackdriverLogging
More than 1 year has passed since last update.

intra-mart AccelPlatformのリクエストログをStackdriverに出力してみた。

SnapCrab_NoName_2017-7-29_1-37-28_No-00.png
SnapCrab_NoName_2017-7-29_2-49-7_No-00.png

さらに、StackdriverからPub/Sub, BigQuery, Cloud Storageにエクスポートしてみた。
シンクを作成すればいいだけなので簡単。
BigQuery, Cloud Storageへは1時間間隔で自動エクスポート、Pub/Subへは即時配信される模様。

SnapCrab_NoName_2017-7-29_18-35-23_No-00.png
SnapCrab_NoName_2017-7-29_18-36-27_No-00.png
SnapCrab_NoName_2017-7-29_18-40-50_No-00.png

Pub/Subに流したログはGoogle_pubsub input plugin | Logstashとかで受け取れるので他にも色々融通が利きそう。

以下、やったこと。

1. Google Cloud Console からプロジェクトを作成

既存のプロジェクトがあれば、新規に作成する必要は特になし。

2. JSON形式でサービスアカウントキーを作成し、保存
3. 必要なjarファイルを取得
3.1 以下の依存に対して mvn dependency:copy-dependencies などして取得可能
pom.xml
<dependency>
  <groupId>com.google.cloud</groupId>
  <artifactId>google-cloud-logging-logback</artifactId>
  <version>0.21.0-alpha</version>
</dependency>
4. 解決されるjarはこんな感じ
  • com.google.auth:google-auth-library-oauth2-http:jar:0.7.0
  • org.threeten:threetenbp:jar:1.3.3
  • io.netty:netty-handler:jar:4.1.11.Final
  • com.google.instrumentation:instrumentation-api:jar:0.4.2
  • org.codehaus.mojo:animal-sniffer-annotations:jar:1.14
  • com.google.auth:google-auth-library-credentials:jar:0.7.0
  • com.google.auto.value:auto-value:jar:1.2
  • io.netty:netty-codec:jar:4.1.11.Final
  • com.google.http-client:google-http-client-jackson2:jar:1.19.0
  • com.fasterxml.jackson.core:jackson-core:jar:2.1.3
  • com.google.cloud:google-cloud-core:jar:1.2.3
  • io.netty:netty-tcnative-boringssl-static:jar:2.0.3.Final
  • joda-time:joda-time:jar:2.9.2
  • io.grpc:grpc-protobuf:jar:1.4.0
  • com.google.http-client:google-http-client:jar:1.19.0
  • ch.qos.logback:logback-classic:jar:1.2.3
  • io.netty:netty-common:jar:4.1.11.Final
  • io.grpc:grpc-stub:jar:1.4.0
  • commons-logging:commons-logging:jar:1.1.1
  • org.json:json:jar:20160810
  • com.google.protobuf:protobuf-java-util:jar:3.3.0
  • io.netty:netty-codec-socks:jar:4.1.11.Final
  • io.grpc:grpc-netty:jar:1.4.0
  • com.google.protobuf:protobuf-java:jar:3.3.0
  • com.google.cloud:google-cloud-logging-logback:jar:0.20.3-alpha
  • io.netty:netty-handler-proxy:jar:4.1.11.Final
  • org.apache.httpcomponents:httpclient:jar:4.0.1
  • io.netty:netty-resolver:jar:4.1.11.Final
  • com.google.cloud:google-cloud-logging:jar:1.2.3
  • com.google.code.findbugs:jsr305:jar:1.3.9
  • commons-codec:commons-codec:jar:1.3
  • com.google.j2objc:j2objc-annotations:jar:1.1
  • com.google.cloud:google-cloud-core-grpc:jar:1.2.3
  • ch.qos.logback:logback-core:jar:1.2.3
  • com.google.api.grpc:proto-google-cloud-logging-v2:jar:0.1.13
  • io.netty:netty-transport:jar:4.1.11.Final
  • com.google.errorprone:error_prone_annotations:jar:2.0.18
  • com.google.api:gax:jar:1.4.2
  • com.google.api.grpc:proto-google-iam-v1:jar:0.1.13
  • com.google.guava:guava:jar:22.0
  • com.google.code.gson:gson:jar:2.7
  • io.grpc:grpc-auth:jar:1.4.0
  • io.netty:netty-codec-http:jar:4.1.11.Final
  • io.netty:netty-buffer:jar:4.1.11.Final
  • org.slf4j:slf4j-api:jar:1.7.25
  • com.google.api.grpc:proto-google-common-protos:jar:0.1.13
  • com.google.api:gax-grpc:jar:0.21.2
  • io.grpc:grpc-protobuf-lite:jar:1.4.0
  • org.apache.httpcomponents:httpcore:jar:4.0.1
  • io.netty:netty-codec-http2:jar:4.1.11.Final
  • io.grpc:grpc-core:jar:1.4.0
  • io.grpc:grpc-context:jar:1.4.0
  • com.google.api:api-common:jar:1.1.0
5. いくつかのjarを除去

いくつかはAccelPlatformがもつjarと競合していた。
jarjarで機械的にリパッケージしてしまうのが一番楽で早いと思われるが、恐らくその必要はない。

  • commons-codec-1.3.jar
  • commons-logging-1.1.1.jar
  • gson-2.7.jar
  • httpclient-4.0.1.jar
  • httpcore-4.0.1.jar
  • jackson-core-2.1.3.jar
  • joda-time-2.9.2.jar
  • logback-classic-1.2.3.jar
  • logback-core-1.2.3.jar

これらはAccelPlatformがもつjarで代用できるため、除去する。

  • guava-22.0.jar

AccelPlatformがもつjarのバージョンが古いせいで、このバージョンを使う必要がある。不安ならリパッケージだが、guavaは互換性に関しては優秀なので、そのままguava-22.0を使っても問題無いと判断した。

  • slf4j-api-1.7.25.jar

AccelPlatformがもつlog4j-over-slf4jで代用可能なためこれも除去でいいだろう。
必要なjarだが、デプロイする度に消えるのは嫌なのでresin/webapp-jarsの中に放り込んで置く。

6. GOOGLE_APPLICATION_CREDENTIALS

サービスアカウントキーのjsonファイルへのパスを、GOOGLE_APPLICATION_CREDENTIALS環境変数に設定しておく。
システムの環境変数に設定してもいいし、resinを起動するプロセスの親(コンソールやコマンドプロンプト)から

set GOOGLE_APPLICATION_CREDENTIALS=/hoge/foo/bar/service_account_key.json



export GOOGLE_APPLICATION_CREDENTIALS=/hoge/foo/bar/service_account_key.json

としておけばいいだろう。

7. logbackの設定ファイル
resin/webapps/imart/WEB-INF/conf/log/im_logger_request_stackdriver.xml
<included>

    <appender name="CLOUD" class="com.google.cloud.logging.logback.LoggingAppender">
        <log>request.log</log>
        <enhancer>hoge.MDCEnhancer</enhancer>
        <flushLevel>INFO</flushLevel>
    </appender>

    <logger name="REQUEST_LOG" additivity="false">
        <level value="info" />
        <appender-ref ref="CLOUD" />
    </logger>

</included>

こんな感じで設定ファイルを放り込んでおく。

8. MDCEnhancer

LoggingAppenderではencoderが使えないためMDCのエンハンサーを実装しておく。

MDCEnhancer.java
package hoge;

import java.util.Map;

import org.slf4j.MDC;

import com.google.cloud.logging.LogEntry.Builder;
import com.google.cloud.logging.LoggingEnhancer;
import com.google.cloud.logging.Payload.StringPayload;

import jp.co.intra_mart.common.aid.jdk.java.lang.StringUtil;

public class MDCEnhancer implements LoggingEnhancer {
    @Override
    public void enhanceLogEntry(final Builder builder) {
        final Map<String, String> map = MDC.getCopyOfContextMap();

        if (map != null) {
            builder.setLabels(map);

            final String userCd = map.get("user.cd");
            final String method = map.get("request.method");
            final String url = map.get("request.url");

            if (!StringUtil.isBlank(userCd) && !StringUtil.isBlank(method) && !StringUtil.isBlank(url)) {
                builder.setPayload(StringPayload.of(userCd + ' ' + method + ' ' + url));
            }
        }
    }
}

こいつもjarにコンパイル後resin/webapp-jarsの中に放り込んで置く。

とりあえずこんな感じ。
BigQueryが使えるのとGoogle Cloud Pub/Subで連携も容易になるのは大きいかな。