Log4j SDK v2 の使用方法

Prev Next

Classic/VPC環境で利用できます。

ここでは Effective Log Search & Analytics NELO Log4j SDKの使用方法を説明します。NELOは Effective Log Search & Analyticsのプロジェクトコード名です。

Effective Log Search & Analytics Log4j SDK Dependencyを追加する

以下のように Dependencyを追加します。
圧縮ファイルを展開した後、coreモジュールと log4jモジュールのパスを <systemPath> に追加します。

<dependencies>
        <dependency>
            <groupId>nelo2-java-sdk-core</groupId>
            <artifactId>nelo2-java-sdk-core</artifactId>
            <version>1.6.6</version>
            <scope>system</scope>
            <systemPath>/nelo2-java-sdk-core-1.6.6.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>nelo2-java-sdk-log4j</groupId>
            <artifactId>nelo2-java-sdk-log4j</artifactId>
            <version>1.6.6</version>
            <scope>system</scope>
            <systemPath>/nelo2-java-sdk-log4j-1.6.6.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
            <version>0.9.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.2.6</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.3.1</version>
        </dependency>
</dependencies>

備考

  • この SDKは log4jの slf4Jバインドライブラリである slf4j-log4j12を含めて提供します。
    slf4jは特性上、同時に1つの bindingのみサポートするため、他の slf4jバインドのためのライブラリを一緒に使用できません。

  • 既存の使用中の参照ライブラリと nelo2 log4j SDKで参照するライブラリが重複する場合、問題が発生することがあります。
    この場合、より上位のバージョンを使用することをお勧めします。

Effective Log Search & Analytics log4j appenderの設定とオプション

log4j.xml内の共通 configurationは以下のように入力されます。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "" "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
    <!-- // define appenders // -->
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Threshold" value="DEBUG"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%m%n"/>
        </layout>
    </appender>
    <!-- // define loggers // -->
    <logger name="com" additivity="false">
        <level value="INFO"/>
        <appender-ref ref="STDOUT"/>
    </logger>
    <!-- // define root // -->
    <root>
        <level value="WARN"/>
        <appender-ref ref="STDOUT"/>
    </root>
</log4j:configuration>

Effective Log Search & Analytics NELO2 log4j appenderは以下のように入力されます。projectNameには Effective Log Search & Analyticsに登録したプロジェクトキーを入力します。

<!-- define nelo appender -->
<appender name="nelo" class="com.naver.nelo2.log4j.ThriftAppender">
    <param name="Threshold" value="ERROR"/>
    <param name="projectName" value="%YOUR_PROJECT_KEY%"/>
    <param name="collectorUrl" value="elsa-col.ncloud.com"/>
    <param name="port" value="10006"/>
    <param name="timeout" value="1200"/>
    <param name="enable" value="true"/>
    <param name="errorCodeType" value="default"/>
</appender>

オプションは次のような項目を設定できます。

  • Appender(転送プロトコルに応じて Appenderのクラス名を選択)

    • Thrift Appender : com.naver.nelo2.log4j.ThriftAppender

    • Http Appender : com.naver.nelo2.log4j.HttpAppender

  • projectName: プロジェクトキー。Effective Log Search & Analyticsのプロジェクト情報で作成したプロジェクトの IDを確認できます。

  • version: プロジェクトバージョン(英数字、-、_、.のみ許可し、先頭は英数字/_にすること)。

  • collectorUrl: Effective Log Search & Analyticsログ収集サーバの URL

    • ThriftAppender: elsa-col.ncloud.com

    • HttpAppender: http://elsa-col.ncloud.com/_store

  • port: Collectorサーバ port

    • Thrift Appender : 10006

    • Http Appender : 80

  • enable: 使用有無(デフォルト値 true)

  • logType: logTypeの設定

  • logSource: logSourceの設定

  • errorCodeType: エラーコードタイプ

    • default: log4jの基本情報のうち、Exception情報を使用。 Exception 정보가 전달되지 않은 경우 (log.error(message)의 형식으로 로그가 기록되는 경우)에는 에러 메시지 전체를 에러코드로 사용함

      例) NullPointerExceptionが発生した場合 => NullPointerException

    • message: エラーメッセージの最初から空白文字までのみ使用。

      例) ダウンロードエラー ダウンロードに失敗しました。=> ダウンロードエラー

    • action: URL의 Path 정보(Lucy intercepter가 적용되어 있어야 함)

      例) http://xxx.com/board/list?id=100 => /board/list

    • mdc: SLF4J MDCの「errorCode」項目値を設定して使用する。

      例) MDC.put(“errorCode”, “Login”) => Login

  • debug: Effective Log Search & Analyticsのデバッグ情報を表示。デフォルト値は false。

    • このオプション値は全域的に適用され、「true」が「false」より優先されます。つまり、複数のアペンダーが宣言されており、そのうち1つの debug値が trueの場合、全てのアペンダーからコンソールにデバッグログを出力します。
  • timeout: 転送時に使用する socketのタイムアウト、デフォルト値5000ms(5秒)

  • keepAlive: 転送時に使用する socketの keepAliveタイムアウト、デフォルト値60000ms(1分)、最大値180000ms(3分)

  • isBulkEnabled: bulkモードを使用するかどうか、デフォルト値が true、falseの場合に各ログを個別に転送

  • bulkSize: bulkモードを使用する場合、1つのバルクリクエストに転送する最大ログ数、デフォルト値1000、最大値100000

  • bulkInterval: bulkモードを使用する場合、バルクリクエストを呼び出す周期、デフォルト値1000ms(1秒)、最大値10000ms(10秒)

  • alwaysIncludeLocation: SDKが「Location」フィールドを全てのログに追加するかどうかのデフォルト値は trueです。

    • false: logLevelが「ERROR」のログの「Location」フィールドを確認して設定します。
    • true: 全てのログに対する Locationフィールドを確認して設定します。これは「false」に比べてロギングパフォーマンスに悪い影響を与えることがあります。
  • mdcConversionRule: MDC keyをリネームするルールです。

    • format: key1:newKey1;key2:newkey2;...

      例) mdcConversionRuleを time:date;fullname:nameに設定し、この keyが存在する時に MDC keyの _time_を dateに、fullnameを nameにリネームするということです。

bulk / single

NELO2 log4j SDKはログを1件ずつ転送する singleモードと、まとまった単位で転送する bulkモードをサポートします。

bulkモードは1.4.0バージョンからサポートしており、xml appender設定で isBulkEnabledを true/falseにして bulk / singleモードを使用できます(デフォルト値 true)。

パフォーマンスに関するリファレンスはプロトコルに沿って以下の表をご参照ください。

1分間単一スレッドで 1kb sizeのログを転送する場合の throughput

  • thrift

    • single mode : 2615.54 logs/sec
    • bulk mode : 6642.97 logs/sec
  • http

    • single mode : 592.97 logs/sec
    • mode : 4665.26 logs/sec

上記のパフォーマンステストに使用した装置のスペックは、次の通りです。

  • ログ転送サーバ: 2GHZ 12core cpu、48G mem、加山 IDCの位置
  • ログ収集サーバ: 2.26GHZ 12core cpu、48G mem、加山 IDCの位置

備考

  • 負荷に応じて転送パフォーマンスは異なります。
    テストは負荷がない状況で実行され、実際に使用中のインスタンスに送信する際には比較的低いパフォーマンスを示します。
    インスタンス負荷に応じたパフォーマンスの体験は、bulkモードに比べて singleモードでより大きく表示されます。
    そのため、デフォルト値である bulkモードを使用することをお勧めします。

  • 収集サーバが許可する最大パケットのサイズは30mbです。
    クライアントサーバのログパターンを検討し、適切な bulkSizeを設定します(デフォルト値1000)。

AsyncAppender

次のように log4jでサポートする AsyncAppenderを利用し、同じ方式の結果が得られます。

注意すべき設定値には、次のような項目があります。bufferSizeのデフォルト値は128ですが、いくつかのアプリケーションでは十分でないことがあります。

そして、locationInfoのデフォルト値は falseであり、この場合 AsyncAppenderはログの発生場所情報を無視します。

以下の AsyncAppender設定例をご参照ください。

<appender name="nelo-async" class="org.apache.log4j.AsyncAppender">
    <param name="Threshold" value="ERROR"/>
    <param name="blocking" value="false"/>
    <param name="locationInfo" value="true"/>
    <param name="bufferSize" value="2048"/>
    <appender-ref ref="nelo"/>
</appender>

設定値の詳細情報は次の公式ドキュメントをご参照ください。

AsyncAppenderの使用方法

デフォルトで使用する ThriftAppenderに追加として Nelo2AsyncAppenderを使用し、実際のログ転送を別途スレッドで行うように設定できます。

そのためには、以下のように xmlファイルを設定して使用します。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "" "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
    <!-- // define appenders // -->
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Threshold" value="DEBUG"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%m%n"/>
        </layout>
    </appender>
    <!-- define nelo appender -->
    <appender name="nelo" class="com.naver.nelo2.log4j.ThriftAppender">
        <param name="Threshold" value="ERROR"/>
        <param name="projectName" value="프로젝트 키"/>
        <param name="collectorUrl" value="elsa-col.ncloud.com"/>
        <param name="port" value="10006"/>
        <param name="timeout" value="1200"/>
        <param name="enable" value="true"/>
        <param name="errorCodeType" value="default"/>
    </appender>
    <!-- define nelo-async appender -->
    <appender name="nelo-async"
              class="org.apache.log4j.AsyncAppender">
        <param name="Threshold" value="ERROR"/>
        <param name="blocking" value="false"/>
        <param name="locationInfo" value="true"/>
        <param name="bufferSize" value="2048"/>
        <appender-ref ref="nelo"/>
    </appender>
    <!-- // define loggers // -->
    <logger name="com" additivity="false">
        <level value="ERROR"/>
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="nelo-async"/>
    </logger>
    <!-- // define root // -->
    <root>
        <level value="WARN"/>
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="nelo-async"/>
    </root>
</log4j:configuration>

Effective Log Search & Analytics log4j SDKの使用例

次は Effective Log Search & Analytics log4j SDKを実際に使用したコードの例です。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private static Logger logger = LoggerFactory.getLogger(log4jTest.class);
...
    logger.debug("Effective Log Search & Analytics log4j SDK Debug Message");
    try {
        String npe = null;
        npe.toString();
    } catch(Exception e) {
        logger.error("Effective Log Search & Analytics log4j SDK Exception", e);
    }

制限事項

  • log4j 2.0バージョンで上記のガイドの内容を公式的にサポートしません。
  • async appenderを使用する場合、転送速度に比べてログ発生速度が速いと queue sizeを超過して発生したログは転送されません。
  • async appenderとデフォルト appenderは以下の基準に沿って選択することをお勧めします。
    • ログ損失を最小化したい場合: デフォルト appender
    • Effective Log Search & Analyticsシステム障害の際にアプリケーションのパフォーマンス低下が懸念される場合: async appender

トラブルシューティング

1. Effective Log Search & Analyticsでログを転送したが、それをウェブで確認できない場合

ログを Effective Log Search & Analytics収集サーバに転送した後、結果メッセージにエラーがない場合は projectNameが正しいか確認します。projectNameはプロジェクトキーであり、プロジェクト管理で確認できます。

そして実際のエラーデータが転送されたか確認します。設定ファイル(log4j.xml)で Effective Log Search & Analytics NELO appenderの debugプロパティを trueに設定して実行した後、以下のような転送ログが出力されることを確認します。

<!-- define nelo appender -->
<appender name="nelo" class="com.naver.nelo2.log4j.ThriftAppender">
    <param name="Threshold" value="ERROR"/>
    <param name="projectName" value="%YOUR_PROJECT_KEY%"/>
    <param name="collectorUrl" value="elsa-col.ncloud.com"/>
    <param name="port" value="10006"/>
    <param name="timeout" value="1200"/>
    <param name="enable" value="true"/>
    <param name="errorCodeType" value="default"/>
    <param name="debug" value="true"/>
</appender>

[NELO2] Log Append : sent event, return value :
…

FAQ

1. バッチプログラム(あるいは簡単なテストプログラム)で AsyncAppenderを使用するには?

batchプログラムの最後に数秒間待機するコードを追加します。

try {
    Thread.sleep(3000L);
} catch (InterruptedException ignore){}

AsyncAppenderは、内部にログを記録する別途のデーモンスレッドで非同期でログを転送します。

Java batch programでは main threadがすぐに終了するため、log4jAsyncAppenderのデーモンスレッドが作成されてログを転送する前に batchアプリケーションが終了します。

デーモンスレッドに関係なく、生存している一般スレッドがない場合に JVMはすぐに終了します。

そのため、上記のようにプログラム最後に待機するコードを追加してすべてのログを転送してから終了するようにします。

2. Java stack traceを Log4jに含めるには?

Action / BO / DAO / Java batch programなどで log4jを利用して stack traceを出力するには、log.error(e.getMessage(), e);の形式を使用します。

SLF4J Loggerはメソッドの引数として Throwableのみ取得するロギングメソッドはサポートしません。

String[] aa = null;
try {
    aa[0] = "111";
} catch (NullPointerException e) {
//	log.error(e); //SLF4Jではサポートしないメソッド。
    log.error(e.getMessage(), e); ///stacktrace出力
}

3. log4j(Effective Log Search & Analyticsを含む) loggingによるパフォーマンス低下を最小化するには?

log4j.xmlの logger設定で nameと levelを使用して filteringを最大化します。

以下のように logger設定で comや orgを DEBUG levelに設定すると、loggerで多くの ILoggingEvent(log4j)が余計に作成されます。

nelo log4j appenderで Thresholdが ERRORに設定されているため、実際のログ転送は行われませんが、まず loggerで ILoggingEventを作成して appenderに送ります。

パフォーマンスが低下する設定(開発用のみで使用)

<!-- Logger -->
<logger name="com" additivity="false">
    <level value="debug"/>
    <appender-ref ref="STDOUT" />
    <appender-ref ref="nelo-log4j" />
</logger>

<!-- Logger -->
<logger name="org" additivity="false">
    <level value="debug"/>
    <appender-ref ref="STDOUT" />
    <appender-ref ref="nelo-log4j" />
</logger>

<!-- Root Logger -->
<root level="warn">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="nelo-log4j" />
</root>

パフォーマンスを検討した設定(運用向けに使用)

<!-- Logger -->
<logger name="com" additivity="false">
    <level value="error"/>
    <appender-ref ref="STDOUT" />
    <appender-ref ref="nelo-log4j" />
</logger>

<!-- Root Logger -->
<root level="warn">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="nelo-log4j" />
</root>

4. WASで使用する際に安定的に終了するには?

エラーログが転送中の状況で WAS(Tomcatなど)が終了される場合は、たまに WASが正常に終了されないことがあります。

このような現象を防ぐには、WAS終了時に LoggerContextインスタンスに対して stop()メソッドを呼び出して nelo2 java appenderを closeすると安定的に終了できます。

備考

Springでは Log4Jに対しては org.springframework.web.util.Log4jConfigListenerを提供しますが、Logbackに対しては安定的な終了をサポートする Listenerを提供していません。

このような動作が必要な場合、アプリケーション内で次のコードを追加すると実装できます。

public class YOUR_CLASS_NAME implements ServletContextListener {
    public void contextDestroyed(ServletContextEvent arg0) {
        // shutdown log4j, at destroy time
        LogManager.shutdown();
    }
    public void contextInitialized(ServletContextEvent arg0) {
        // do not any operation, at initial time
    }
}

5. thrift bulk転送時に timeoutが発生する場合

収集サーバに正常にログを転送できなかった場合、以下のようなログを確認できます。

[NELO2] sendMessage (1426319665440) sendBulk failed..  Error occur : java.net.SocketTimeoutException: Read timed out

この場合、xml appender設定で timeoutを増やし bulkSizeを縮めることで1つのパケットに入るデータを減らします。

6. メモリ使用量に関する注意事項

現在提供される SDKは bulk転送モードをデフォルトで使用し、bulkSizeはデフォルト値が1000です。

1つの Effective Log Search & Analyticsログは projectNameなどの複数のフィールドを含めているため、ログボディが非常に短い場合にも1kb程度のメモリを使用します。

そのため、デフォルト設定の場合に Nelo2バルクは(ログサイズ+1kb)*1000程度のメモリを使用します。

Javaプロセスを起動する場合、最大ヒープを-Xmxオプションに指定できます。この時、前述した追加メモリ使用量も検討してください。

特に bulkSizeオプションをより大きく指定する場合は、特にご注意ください。