Log4j SDK v2 の使用方法

この章では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は特性上、同時に一つの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に登録したプロジェクトのIDを入力してください。

<!-- define nelo appender -->
<appender name="nelo" class="com.naver.nelo2.log4j.ThriftAppender">
    <param name="Threshold" value="ERROR"/>
    <param name="projectName" value="%YOUR_PROJECT_ID%"/>
    <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: プロジェクトID。Effective Log Search & Analyticsのプロジェクト情報で生成したプロジェクトのIDを確認できます。
  • version : プロジェクトバージョン(英文字、数字、-, , .のみ許可されて英文字/数字/로で始まらなければなりません)。
  • collectorUrl: Effective Log Search & Analyticsログ収集サーバのURL

  • 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'に優先されます。つまり、複数のアペンダーが宣言されており、その中の一つの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キーの名前を変更するためのルール。

    • format: key1:newKey1;key2:newkey2;...
      例) mdcConversionRuleを time:date;fullname:name に設定します。このルールはMDCキー 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に比べてsinglモードでより大きく現れます。 従って基本値である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="プロジェクトID"/>
        <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システム障害の際にアプリ性能の低下が懸念される場合: asnyc appender

トラブルシューティング

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

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

また、実際エラーデータが転送されたか確認します。設定ファイル(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_ID%"/>
    <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を縮めることによってパケットに入るデータを減らす必要があります。

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

現在提供されるSDKはbulkの転送モードを基本に使用し、bulkSizeは基本値が1000です。

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

従って、基本設定の場合、 Nelo2バルクは (ログサイズ+1kb)*1000分のメモリーを占めます。

Javaプロセスを起動する際、最大のヒップを -Xmxオプションに指定できます。この際に上で言及した付加的なメモリー使用量も考慮してください。

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

に対する検索結果は~件です。 ""

    に対する検索結果がありません。 ""

    処理中...