航海日誌名詞、/lɑɡ bʊk/: 船の航海日誌からの測定値と、航海のその他の重要な詳細が記録される本。
Logbookは、さまざまなクライアント側およびサーバー側のテクノロジの完全なリクエストと応答のログ記録を可能にする拡張可能な Java ライブラリです。これは、a) Web アプリケーション開発者が、アプリケーションが送受信する HTTP トラフィックをログに記録できるようにすることにより、b) 後で簡単に永続化して分析できる方法で、特別なニーズを満たします。これは、従来のログ分析、監査要件の満たし、または個々の履歴トラフィックの問題の調査に役立ちます。
Logbook は、ほとんどの一般的なセットアップですぐに使用できる状態になっています。珍しいアプリケーションやテクノロジであっても、ライブラリ/フレームワークなどを接続するために必要なインターフェイスを実装するのは簡単である必要があります。それに。
次の依存関係をプロジェクトに追加します。
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-core</ artifactId >
< version >${logbook.version}</ version >
</ dependency >
Spring 5 / Spring Boot 2 の下位互換性のために、次のインポートを追加してください。
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-servlet</ artifactId >
< version >${logbook.version}</ version >
< classifier >javax</ classifier >
</ dependency >
Logbook の追加モジュール/アーティファクトは常に同じバージョン番号を共有します。
あるいは、部品表をインポートすることもできます。
< dependencyManagement >
< dependencies >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-bom</ artifactId >
< version >${logbook.version}</ version >
< type >pom</ type >
< scope >import</ scope >
</ dependency >
</ dependencies >
</ dependencyManagement >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-core</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-httpclient</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-jaxrs</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-json</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-netty</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-okhttp</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-okhttp2</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-servlet</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-spring-boot-starter</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-ktor-common</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-ktor-client</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-ktor-server</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-ktor</ artifactId >
</ dependency >
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-logstash</ artifactId >
</ dependency >
リクエストとレスポンスを記録するには、ログブック ロガーをトレース レベルに設定する必要があります。 Spring Boot 2 (Logback を使用) では、次の行をapplication.properties
に追加することでこれを実現できます。
logging.level.org.zalando.logbook: TRACE
すべての統合には、すべての構成を保持し、必要なすべての部分を接続するLogbook
のインスタンスが必要です。すべてのデフォルトを使用して作成することもできます。
Logbook logbook = Logbook . create ();
または、 LogbookBuilder
使用してカスタマイズされたバージョンを作成します。
Logbook logbook = Logbook . builder ()
. condition ( new CustomCondition ())
. queryFilter ( new CustomQueryFilter ())
. pathFilter ( new CustomPathFilter ())
. headerFilter ( new CustomHeaderFilter ())
. bodyFilter ( new CustomBodyFilter ())
. requestFilter ( new CustomRequestFilter ())
. responseFilter ( new CustomResponseFilter ())
. sink ( new DefaultSink (
new CustomHttpLogFormatter (),
new CustomHttpLogWriter ()
))
. build ();
ログブックには、リクエスト/レスポンスのログを記録する方法が非常に厳密に定められていました。
これらの制限の一部はカスタムHttpLogWriter
実装で軽減できますが、決して理想的なものではありませんでした。
バージョン 2.0 以降、ログブックにはその中核に戦略パターンが含まれるようになりました。影響を理解するには、 Strategy
インターフェイスのドキュメントを必ず読んでください。
ログブックにはいくつかの組み込み戦略が含まれています。
BodyOnlyIfStatusAtLeastStrategy
StatusAtLeastStrategy
WithoutBodyStrategy
バージョン 3.4.0 以降、Logbook にはAttribute Extractorと呼ばれる機能が装備されています。属性は基本的に、リクエストやレスポンスから抽出してログに記録できるキーと値のペアのリストです。このアイデアは、認可ヘッダーの JWT トークンからサブジェクト クレームを抽出する機能が要求された問題 381 から生まれました。
AttributeExtractor
インターフェイスには 2 つのextract
メソッドがあります。1 つはリクエストからのみ属性を抽出できるメソッド、もう 1 つはリクエストとレスポンスの両方を利用できるメソッドです。どちらもHttpAttributes
クラスのインスタンスを返します。これは基本的には派手なMap<String, Object>
です。マップ値はObject
型であるため、意味のある方法でログに表示するには、適切なtoString()
メソッドが必要であることに注意してください。あるいは、ログ フォーマッタは独自のシリアル化ロジックを実装することでこの問題を回避できます。たとえば、組み込みのログ フォーマッタJsonHttpLogFormatter
ObjectMapper
使用して値をシリアル化します。
以下に例を示します。
final class OriginExtractor implements AttributeExtractor {
@ Override
public HttpAttributes extract ( final HttpRequest request ) {
return HttpAttributes . of ( "origin" , request . getOrigin ());
}
}
次に、この属性エクストラクターを登録してログブックを作成する必要があります。
final Logbook logbook = Logbook . builder ()
. attributeExtractor ( new OriginExtractor ())
. build ();
これにより、リクエスト ログには次のような内容が含まれます。
"attributes":{"origin":"LOCAL"}
より高度な例については、 JwtFirstMatchingClaimExtractor
クラスとJwtAllMatchingClaimsExtractor
クラスを参照してください。前者は、要求 JWT トークンからクレーム名のリストに一致する最初のクレームを抽出します。後者は、要求 JWT トークンからクレーム名のリストに一致するすべてのクレームを抽出します。
複数のAttributeExtractor
を組み込む必要がある場合は、 CompositeAttributeExtractor
クラスを使用できます。
final List < AttributeExtractor > extractors = List . of (
extractor1 ,
extractor2 ,
extractor3
);
final Logbook logbook = Logbook . builder ()
. attributeExtractor ( new CompositeAttributeExtractor ( extractors ))
. build ();
ログブックはいくつかの異なるフェーズで機能します。
各フェーズは、カスタマイズに使用できる 1 つ以上のインターフェイスによって表されます。すべてのフェーズには適切なデフォルトがあります。
HTTP メッセージをログに記録し、その本文を含めるのはかなりコストのかかる作業であるため、特定のリクエストのログを無効にすることは非常に意味があります。一般的な使用例は、ロード バランサーからのヘルス チェックリクエスト、または開発者によって通常発行される管理エンドポイントへのリクエストを無視することです。
条件の定義は、リクエスト (およびそれに対応するレスポンス) をログに記録するかどうかを決定する特別なPredicate
を記述するのと同じくらい簡単です。あるいは、事前定義された述語を使用して組み合わせることができます。
Logbook logbook = Logbook . builder ()
. condition ( exclude (
requestTo ( "/health" ),
requestTo ( "/admin/**" ),
contentType ( "application/octet-stream" ),
header ( "X-Secret" , newHashSet ( "1" , "true" ):: contains )))
. build ();
除外パターン ( /admin/**
など) は、URL のクエリ文字列を考慮せずに、Ant のパス パターン スタイルに大まかに従っています。
フィルタリングの目的は、HTTP リクエストとレスポンスの特定の機密部分がログに記録されないようにすることです。これには通常、 Authorizationヘッダーが含まれますが、特定のプレーンテキスト クエリやフォーム パラメータ (例:パスワード )にも適用される場合があります。
ログブックはさまざまなタイプのフィルターをサポートしています。
タイプ | で動作します | に適用されます | デフォルト |
---|---|---|---|
QueryFilter | クエリ文字列 | リクエスト | access_token |
PathFilter | パス | リクエスト | 該当なし |
HeaderFilter | ヘッダー (単一のキーと値のペア) | 両方 | Authorization |
BodyFilter | Content-Type と本文 | 両方 | json: access_token とrefresh_token 形式: client_secret 、 password 、およびrefresh_token |
RequestFilter | HttpRequest | リクエスト | バイナリ、マルチパート、ストリームの本体を置き換えます。 |
ResponseFilter | HttpResponse | 応答 | バイナリ、マルチパート、ストリームの本体を置き換えます。 |
QueryFilter
、 PathFilter
、 HeaderFilter
、およびBodyFilter
比較的高レベルであり、すべてのケースの ~90% ですべてのニーズをカバーするはずです。より複雑なセットアップの場合は、低レベルのバリアント、つまりそれぞれRequestFilter
とResponseFilter
( ForwardingHttpRequest
/ ForwardingHttpResponse
と組み合わせて) にフォールバックする必要があります。
次のようにフィルターを構成できます。
import static org . zalando . logbook . core . HeaderFilters . authorization ;
import static org . zalando . logbook . core . HeaderFilters . eachHeader ;
import static org . zalando . logbook . core . QueryFilters . accessToken ;
import static org . zalando . logbook . core . QueryFilters . replaceQuery ;
Logbook logbook = Logbook . builder ()
. requestFilter ( RequestFilters . replaceBody ( message -> contentType ( "audio/*" ). test ( message ) ? "mmh mmh mmh mmh" : null ))
. responseFilter ( ResponseFilters . replaceBody ( message -> contentType ( "*/*-stream" ). test ( message ) ? "It just keeps going and going..." : null ))
. queryFilter ( accessToken ())
. queryFilter ( replaceQuery ( "password" , "<secret>" ))
. headerFilter ( authorization ())
. headerFilter ( eachHeader ( "X-Secret" :: equalsIgnoreCase , "<secret>" ))
. build ();
フィルターは必要なだけ構成でき、連続して実行されます。
JSON パス フィルタリングを JSON 本文に適用できます。以下にいくつかの例を示します。
import static org . zalando . logbook . json . JsonPathBodyFilters . jsonPath ;
import static java . util . regex . Pattern . compile ;
Logbook logbook = Logbook . builder ()
. bodyFilter ( jsonPath ( "$.password" ). delete ())
. bodyFilter ( jsonPath ( "$.active" ). replace ( "unknown" ))
. bodyFilter ( jsonPath ( "$.address" ). replace ( "X" ))
. bodyFilter ( jsonPath ( "$.name" ). replace ( compile ( "^( \ w).+" ), "$1." ))
. bodyFilter ( jsonPath ( "$.friends.*.name" ). replace ( compile ( "^( \ w).+" ), "$1." ))
. bodyFilter ( jsonPath ( "$.grades.*" ). replace ( 1.0 ))
. build ();
フィルタリングの適用前と適用後の次の例を見てください。
{
"id" : 1 ,
"name" : " Alice " ,
"password" : " s3cr3t " ,
"active" : true ,
"address" : " Anhalter Straße 17 13, 67278 Bockenheim an der Weinstraße " ,
"friends" : [
{
"id" : 2 ,
"name" : " Bob "
},
{
"id" : 3 ,
"name" : " Charlie "
}
],
"grades" : {
"Math" : 1.0 ,
"English" : 2.2 ,
"Science" : 1.9 ,
"PE" : 4.0
}
}
{
"id" : 1 ,
"name" : " Alice " ,
"active" : " unknown " ,
"address" : " XXX " ,
"friends" : [
{
"id" : 2 ,
"name" : " B. "
},
{
"id" : 3 ,
"name" : " C. "
}
],
"grades" : {
"Math" : 1.0 ,
"English" : 1.0 ,
"Science" : 1.0 ,
"PE" : 1.0
}
}
ログブックは、相関 ID を使用してリクエストと応答を関連付けます。これにより、通常はログ ファイル内の別の場所に配置される一致関連のリクエストと応答が可能になります。
相関 ID のデフォルトの実装がユースケースにとって不十分な場合は、カスタム実装を提供できます。
Logbook logbook = Logbook . builder ()
. correlationId ( new CustomCorrelationId ())
. build ();
フォーマットは、基本的にリクエストとレスポンスがどのように文字列に変換されるかを定義します。フォーマッタはリクエストとレスポンスがどこに記録されるかを指定しません。ライターがその作業を行います。
Logbook には、 HTTPとJSONという 2 つの異なるデフォルト フォーマッタが付属しています。
HTTP は、 DefaultHttpLogFormatter
によって提供されるデフォルトの書式設定スタイルです。これは主に、運用環境での使用ではなく、ローカルの開発とデバッグに使用するように設計されています。これは、JSON ほど機械可読性が低いためです。
Incoming Request: 2d66e4bc-9a0d-11e5-a84c-1f39510f0d6b
GET http://example.org/test HTTP/1.1
Accept: application/json
Host: localhost
Content-Type: text/plain
Hello world!
Outgoing Response: 2d66e4bc-9a0d-11e5-a84c-1f39510f0d6b
Duration: 25 ms
HTTP/1.1 200
Content-Type: application/json
{ "value" : " Hello world! " }
JSON は、 JsonHttpLogFormatter
によって提供される代替書式スタイルです。 HTTP とは異なり、これは主に運用環境での使用を目的として設計されており、パーサーやログの利用者が簡単に利用できます。
次の依存関係が必要です。
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-json</ artifactId >
</ dependency >
{
"origin" : " remote " ,
"type" : " request " ,
"correlation" : " 2d66e4bc-9a0d-11e5-a84c-1f39510f0d6b " ,
"protocol" : " HTTP/1.1 " ,
"sender" : " 127.0.0.1 " ,
"method" : " GET " ,
"uri" : " http://example.org/test " ,
"host" : " example.org " ,
"path" : " /test " ,
"scheme" : " http " ,
"port" : null ,
"headers" : {
"Accept" : [ " application/json " ],
"Content-Type" : [ " text/plain " ]
},
"body" : " Hello world! "
}
{
"origin" : " local " ,
"type" : " response " ,
"correlation" : " 2d66e4bc-9a0d-11e5-a84c-1f39510f0d6b " ,
"duration" : 25 ,
"protocol" : " HTTP/1.1 " ,
"status" : 200 ,
"headers" : {
"Content-Type" : [ " text/plain " ]
},
"body" : " Hello world! "
}
注: application/json
タイプ (およびapplication/*+json
) の本体は、結果として得られる JSON ツリーにインライン化されます。つまり、JSON 応答本文はエスケープされず、文字列として表されます。
{
"origin" : " local " ,
"type" : " response " ,
"correlation" : " 2d66e4bc-9a0d-11e5-a84c-1f39510f0d6b " ,
"duration" : 25 ,
"protocol" : " HTTP/1.1 " ,
"status" : 200 ,
"headers" : {
"Content-Type" : [ " application/json " ]
},
"body" : {
"greeting" : " Hello, world! "
}
}
Common Log Format (CLF) は、Web サーバーがサーバー ログ ファイルを生成するときに使用する標準化されたテキスト ファイル形式です。この形式はCommonsLogFormatSink
を通じてサポートされています。
185.85.220.253 - - [02/Aug/2019:08:16:41 0000] "GET /search?q=zalando HTTP/1.1" 200 -
Extended Log Format (ELF) は、Common Log Format (CLF) と同様に標準化されたテキスト ファイル形式で、ログ ファイルを生成するときに Web サーバーによって使用されますが、ELF ファイルはより多くの情報と柔軟性を提供します。この形式はExtendedLogFormatSink
を通じてサポートされています。 W3C ドキュメントも参照してください。
デフォルトのフィールド:
date time c-ip s-dns cs-method cs-uri-stem cs-uri-query sc-status sc-bytes cs-bytes time-taken cs-protocol cs(User-Agent) cs(Cookie) cs(Referrer)
デフォルトのログ出力例:
2019-08-02 08:16:41 185.85.220.253 localhost POST /search ?q=zalando 200 21 20 0.125 HTTP/1.1 "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0" "name=value" "https://example.com/page?q=123"
ユーザーは、 ExtendedLogFormatSink
のコンストラクターを通じて、デフォルトのフィールドをカスタム フィールドでオーバーライドできます。
new ExtendedLogFormatSink ( new DefaultHttpLogWriter (), "date time cs(Custom-Request-Header) sc(Custom-Response-Header)" )
Http ヘッダー フィールド: cs(Any-Header)
およびsc(Any-Header)
の場合、ユーザーはリクエストから抽出したいヘッダーを指定できます。
その他のサポートされているフィールドはExtendedLogFormatSink.Field
の値にリストされており、カスタム フィールド式に含めることができます。
cURL は、リクエストを実行可能なcURL
コマンドとしてレンダリングするCurlHttpLogFormatter
によって提供される代替書式スタイルです。 JSON とは異なり、主に人間向けに設計されています。
curl -v -X GET ' http://localhost/test ' -H ' Accept: application/json '
HTTP を参照するか、応答の独自のフォールバックを提供します。
new CurlHttpLogFormatter ( new JsonHttpLogFormatter ());
Splunk は、リクエストとレスポンスをキーと値のペアとしてレンダリングするSplunkHttpLogFormatter
によって提供される代替フォーマット スタイルです。
origin=remote type=request correlation=2d66e4bc-9a0d-11e5-a84c-1f39510f0d6b protocol=HTTP/1.1 sender=127.0.0.1 method=POST uri=http://example.org/test host=example.org scheme=http port=null path=/test headers={Accept=[application/json], Content-Type=[text/plain]} body=Hello world!
origin=local type=response correlation=2d66e4bc-9a0d-11e5-a84c-1f39510f0d6b duration=25 protocol=HTTP/1.1 status=200 headers={Content-Type=[text/plain]} body=Hello world!
書き込みでは、フォーマットされたリクエストとレスポンスが書き込まれる場所を定義します。 Logbook には、Logger、Stream、Chunking の 3 つの実装が付属しています。
デフォルトでは、リクエストとレスポンスはorg.zalando.logbook.Logbook
カテゴリとログ レベルtrace
を使用するslf4jロガーで記録されます。これはカスタマイズできます。
Logbook logbook = Logbook . builder ()
. sink ( new DefaultSink (
new DefaultHttpLogFormatter (),
new DefaultHttpLogWriter ()
))
. build ();
別の実装では、要求と応答をPrintStream
に記録します ( System.out
やSystem.err
など)。これは通常、運用環境で実行する場合には不適切な選択ですが、短期的なローカル開発や調査には役立つ場合があります。
Logbook logbook = Logbook . builder ()
. sink ( new DefaultSink (
new DefaultHttpLogFormatter (),
new StreamHttpLogWriter ( System . err )
))
. build ();
ChunkingSink
長いメッセージを小さなチャンクに分割し、別のシンクに委任しながら個別に書き込みます。
Logbook logbook = Logbook . builder ()
. sink ( new ChunkingSink ( sink , 1000 ))
. build ();
HttpLogFormatter
とHttpLogWriter
の組み合わせはほとんどのユースケースに適していますが、制限があります。 Sink
インターフェイスを直接実装すると、データベースのような構造化された永続ストレージへのリクエスト/応答の書き込みなど、より洗練された使用例が可能になります。
CompositeSink
使用すると、複数のシンクを 1 つに結合できます。
LogbookFilter
フィルター チェーン内のFilter
としてweb.xml
ファイルに登録する必要があります (xml アプローチではすべてのデフォルトが使用され、構成できないことに注意してください)。
< filter >
< filter-name >LogbookFilter</ filter-name >
< filter-class >org.zalando.logbook.servlet.LogbookFilter</ filter-class >
</ filter >
< filter-mapping >
< filter-name >LogbookFilter</ filter-name >
< url-pattern >/*</ url-pattern >
< dispatcher >REQUEST</ dispatcher >
< dispatcher >ASYNC</ dispatcher >
</ filter-mapping >
またはプログラム的にServletContext
経由で:
context . addFilter ( "LogbookFilter" , new LogbookFilter ( logbook ))
. addMappingForUrlPatterns ( EnumSet . of ( REQUEST , ASYNC ), true , "/*" );
注意: ERROR
ディスパッチはサポートされていません。 REQUEST
またはASNYC
ディスパッチ内でエラー応答を生成することを強くお勧めします。
LogbookFilter
、デフォルトで、他のリクエストと変わらないapplication/x-www-form-urlencoded
本文を持つリクエストを処理します。つまり、リクエスト本文がログに表示されます。このアプローチの欠点は、 HttpServletRequest.getParameter*(..)
メソッドを使用できないことです。詳細については、問題 #94 を参照してください。
Logbook 1.5.0 では、 logbook.servlet.form-request
システム プロパティを使用して、Logbook がこの状況にどのように対処するかを定義する 3 つの戦略のいずれかを指定できるようになりました。
価値 | 長所 | 短所 |
---|---|---|
body (デフォルト) | 本文が記録されています | ダウンストリーム コードではgetParameter*() を使用できません |
parameter | 本体はログに記録されます(ただしパラメータから再構築されます)。 | ダウンストリーム コードではgetInputStream() を使用できません |
off | ダウンストリーム コードはgetInputStream() とgetParameter*() のどちらを使用するかを決定できます。 | 本文が記録されていません |
安全なアプリケーションには通常、少し異なる設定が必要です。一般に、不正なリクエスト、特に本文のログ記録は避ける必要があります。これは、攻撃者がすぐにログファイルを大量に消費する可能性があり、その結果、貴重なディスク領域が流出する可能性があるためです。アプリケーションが別のフィルター内で承認を処理すると仮定すると、次の 2 つの選択肢があります。
LogbookFilter
セキュリティ フィルターの後に配置することで、前の設定を簡単に実現できます。後者はもう少し洗練されています。 LogbookFilter
インスタンスが 2 つ必要になります。1 つはセキュリティ フィルターの前に、もう 1 つはその後にあります。
context . addFilter ( "SecureLogbookFilter" , new SecureLogbookFilter ( logbook ))
. addMappingForUrlPatterns ( EnumSet . of ( REQUEST , ASYNC ), true , "/*" );
context . addFilter ( "securityFilter" , new SecurityFilter ())
. addMappingForUrlPatterns ( EnumSet . of ( REQUEST ), true , "/*" );
context . addFilter ( "LogbookFilter" , new LogbookFilter ( logbook ))
. addMappingForUrlPatterns ( EnumSet . of ( REQUEST , ASYNC ), true , "/*" );
最初のログブック フィルタは、未承認のリクエストのみを記録します。 2 番目のフィルターは、いつものように、承認されたリクエストをログに記録します。
logbook-httpclient
モジュールには、 HttpClient
で使用するHttpRequestInterceptor
とHttpResponseInterceptor
の両方が含まれています。
CloseableHttpClient client = HttpClientBuilder . create ()
. addInterceptorFirst ( new LogbookHttpRequestInterceptor ( logbook ))
. addInterceptorFirst ( new LogbookHttpResponseInterceptor ())
. build ();
LogbookHttpResponseInterceptor
HttpAsyncClient
と互換性がないため、応答をログに記録する別の方法があります。
CloseableHttpAsyncClient client = HttpAsyncClientBuilder . create ()
. addInterceptorFirst ( new LogbookHttpRequestInterceptor ( logbook ))
. build ();
// and then wrap your response consumer
client . execute ( producer , new LogbookHttpAsyncResponseConsumer <>( consumer ), callback )
logbook-httpclient5
モジュールには、 HttpClient
で使用するExecHandler
が含まれています。
CloseableHttpClient client = HttpClientBuilder . create ()
. addExecInterceptorFirst ( "Logbook" , new LogbookHttpExecHandler ( logbook ))
. build ();
ロギング後に圧縮が実行され、ロギングの前に解凍が実行されるように、ハンドラーを最初に追加する必要があります。
重大な変更を回避するために、 HttpClient
で使用するHttpRequestInterceptor
およびHttpResponseInterceptor
もあります。これは、圧縮 (または他の ExecHandler) が使用されない限り正常に動作します。
CloseableHttpClient client = HttpClientBuilder . create ()
. addRequestInterceptorFirst ( new LogbookHttpRequestInterceptor ( logbook ))
. addResponseInterceptorFirst ( new LogbookHttpResponseInterceptor ())
. build ();
LogbookHttpResponseInterceptor
HttpAsyncClient
と互換性がないため、応答をログに記録する別の方法があります。
CloseableHttpAsyncClient client = HttpAsyncClientBuilder . create ()
. addRequestInterceptorFirst ( new LogbookHttpRequestInterceptor ( logbook ))
. build ();
// and then wrap your response consumer
client . execute ( producer , new LogbookHttpAsyncResponseConsumer <>( consumer ), callback )
注記
JAX-RS 2.xのサポート
JAX-RS 2.x (レガシー) サポートは Logbook 3.0 から 3.6 で削除されました。
Logbook 3.7 では、JAX-RS 2.x のサポートが再開されました。
ただし、適切な Logbook モジュールを使用するには、 javax
分類子を追加する必要があります。
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-jaxrs</ artifactId >
< version >${logbook.version}</ version >
< classifier >javax</ classifier >
</ dependency >
また、次の依存関係がクラスパス上にあることを確認する必要があります。デフォルトでは、 logbook-jaxrs
jersey-client 3.x
をインポートしますが、これは JAX-RS 2.x と互換性がありません。
logbook-jaxrs
モジュールには以下が含まれます。
HTTP リクエストを行うアプリケーションに使用されるLogbookClientFilter
client . register ( new LogbookClientFilter ( logbook ));
HTTP サーバーで使用するLogbookServerFilter
resourceConfig . register ( new LogbookServerFilter ( logbook ));
logbook-jdkserver
モジュールは JDK HTTP サーバーのサポートを提供し、以下が含まれます。
組み込みサーバーで使用するLogbookFilter
httpServer . createContext ( path , handler ). getFilters (). add ( new LogbookFilter ( logbook ))
logbook-netty
モジュールには以下が含まれます。
HttpClient
で使用されるLogbookClientHandler
:
HttpClient httpClient =
HttpClient . create ()
. doOnConnected (
( connection -> connection . addHandlerLast ( new LogbookClientHandler ( logbook )))
);
HttpServer
で使用するLogbookServerHandler
:
HttpServer httpServer =
HttpServer . create ()
. doOnConnection (
connection -> connection . addHandlerLast ( new LogbookServerHandler ( logbook ))
);
Spring WebFlux のユーザーは、次のオプションのいずれかを選択できます。
NettyWebServer
を作成します ( HttpServer
を渡します)NettyServerCustomizer
を登録するReactorClientHttpConnector
を作成します ( HttpClient
渡します)WebClientCustomizer
を登録するlogbook-spring-webflux
を使用するMicronaut のユーザーは、Logbook を Micronaut と統合する方法に関する公式ドキュメントに従うことができます。
logbook-okhttp2
モジュールには、 OkHttpClient
のバージョン 2.x で使用するInterceptor
が含まれています。
OkHttpClient client = new OkHttpClient ();
client . networkInterceptors (). add ( new LogbookInterceptor ( logbook ));
gzip 圧縮された応答を期待している場合は、さらにGzipInterceptor
登録する必要があります。 OkHttp に組み込まれた透過的な gzip サポートは、圧縮されたバイナリ応答をログブックに記録させるネットワーク インターセプタの後に実行されます。
OkHttpClient client = new OkHttpClient ();
client . networkInterceptors (). add ( new LogbookInterceptor ( logbook ));
client . networkInterceptors (). add ( new GzipInterceptor ());
logbook-okhttp
モジュールには、 OkHttpClient
のバージョン 3.x で使用するInterceptor
が含まれています。
OkHttpClient client = new OkHttpClient . Builder ()
. addNetworkInterceptor ( new LogbookInterceptor ( logbook ))
. build ();
gzip 圧縮された応答を期待している場合は、さらにGzipInterceptor
登録する必要があります。 OkHttp に組み込まれた透過的な gzip サポートは、圧縮されたバイナリ応答をログブックに記録させるネットワーク インターセプタの後に実行されます。
OkHttpClient client = new OkHttpClient . Builder ()
. addNetworkInterceptor ( new LogbookInterceptor ( logbook ))
. addNetworkInterceptor ( new GzipInterceptor ())
. build ();
logbook-ktor-client
モジュールには以下が含まれます。
HttpClient
とともに使用されるLogbookClient
:
private val client = HttpClient ( CIO ) {
install( LogbookClient ) {
logbook = logbook
}
}
logbook-ktor-server
モジュールには以下が含まれます。
Application
で使用されるLogbookServer
:
private val server = embeddedServer( CIO ) {
install( LogbookServer ) {
logbook = logbook
}
}
あるいは、 logbook-ktor-client
とlogbook-ktor-server
モジュールの両方を同梱するlogbook-ktor
を使用することもできます。
logbook-spring
モジュールには、 RestTemplate
で使用するClientHttpRequestInterceptor
が含まれています。
LogbookClientHttpRequestInterceptor interceptor = new LogbookClientHttpRequestInterceptor ( logbook );
RestTemplate restTemplate = new RestTemplate ();
restTemplate . getInterceptors (). add ( interceptor );
ログブックには、Spring Boot ユーザーにとって便利な自動構成が付属しています。次のすべての部分が適切なデフォルトで自動的に設定されます。
logbook-core
への依存関係を宣言する代わりに、Spring Boot Starter への依存関係を宣言します。
< dependency >
< groupId >org.zalando</ groupId >
< artifactId >logbook-spring-boot-starter</ artifactId >
< version >${logbook.version}</ version >
</ dependency >
必要に応じて、すべての Bean をオーバーライドしてカスタマイズできます。たとえば、次のようになります。
@ Bean
public BodyFilter bodyFilter () {
return merge (
defaultValue (),
replaceJsonStringProperty ( singleton ( "secret" ), "XXX" ));
}
可能な統合ポイントのリストを確認するには、 LogbookAutoConfiguration
または次の表を参照してください。
タイプ | 名前 | デフォルト |
---|---|---|
FilterRegistrationBean | secureLogbookFilter | LogbookFilter に基づく |
FilterRegistrationBean | logbookFilter | LogbookFilter に基づく |
Logbook | 条件、フィルター、フォーマッタ、ライターに基づく | |
Predicate<HttpRequest> | requestCondition | フィルターはありません。後でlogbook.exclude およびlogbook.exclude と結合されます。 |
HeaderFilter | logbook.obfuscate.headers に基づく | |
PathFilter | logbook.obfuscate.paths に基づく | |
QueryFilter | logbook.obfuscate.parameters に基づく | |
BodyFilter | BodyFilters.defaultValue() 、フィルタリングを参照 | |
RequestFilter | RequestFilters.defaultValue() 、フィルタリングを参照 | |
ResponseFilter | ResponseFilters.defaultValue() 、フィルタリングを参照 | |
Strategy | DefaultStrategy | |
AttributeExtractor | NoOpAttributeExtractor | |
Sink | DefaultSink | |
HttpLogFormatter | JsonHttpLogFormatter | |
HttpLogWriter | DefaultHttpLogWriter |
複数のフィルターが 1 つに結合されます。
logbook-spring
から自動構成された Bean logbook-spring
の一部のクラスは自動構成に含まれています。
次のようなコードを使用してLogbookClientHttpRequestInterceptor
自動接続できます。
private final RestTemplate restTemplate ;
MyClient ( RestTemplateBuilder builder , LogbookClientHttpRequestInterceptor interceptor ){
this . restTemplate = builder
. additionalInterceptors ( interceptor )
. build ();
}
次の表に、利用可能な構成を示します (アルファベット順に並べ替えています)。
構成 | 説明 | デフォルト |
---|---|---|
logbook.attribute-extractors | AttributeExtractor のリスト。 type (現在はJwtFirstMatchingClaimExtractor またはJwtAllMatchingClaimsExtractor )、 claim-names 、 claim-key などの構成が含まれます。 | [] |
logbook.filter.enabled | LogbookFilter フィルターを有効にする | true |
logbook.filter.form-request-mode | フォームリクエストの処理方法を決定します | body |
logbook.filters.body.default-enabled | java.util.ServiceLoader によって収集されるデフォルトの本文フィルターを有効または無効にします。 | true |
logbook.format.style | 書式設定スタイル ( http 、 json 、 curl またはsplunk ) | json |
logbook.httpclient.decompress-response | gzip でエンコードされた本文を含む HttpClient の追加の解凍プロセスを有効または無効にします (ログ記録のみを目的としています)。これは、余分な解凍が必要となり、パフォーマンスに影響を与える可能性があることを意味します。 | false (無効) |
logbook.minimum-status | ログ記録を有効にするための最小ステータス ( status-at-least およびbody-only-if-status-at-least ) | 400 |
logbook.obfuscate.headers | 難読化が必要なヘッダー名のリスト | [Authorization] |
logbook.obfuscate.json-body-fields | 難読化する JSON 本文フィールドのリスト | [] |
logbook.obfuscate.parameters | 難読化が必要なパラメータ名のリスト | [access_token] |
logbook.obfuscate.paths | 難読化が必要なパスのリスト。フィルタリングの構文を確認してください。 | [] |
logbook.obfuscate.replacement | 難読化された値の代わりに使用される値 | XXX |
logbook.predicate.include | 特定のパスとメソッドのみを含めます (定義されている場合) | [] |
logbook.predicate.exclude | 特定のパスとメソッドを除外します ( logbook.predicate.include をオーバーライドします) | [] |
logbook.secure-filter.enabled | SecureLogbookFilter 有効にする | true |
logbook.strategy | 戦略 ( default 、 status-at-least 、 body-only-if-status-at-least 、 without-body ) | default |
logbook.write.chunk-size | ログ行を最大chunk-size の小さなチャンクに分割します。 | 0 (無効) |
logbook.write.max-body-size | 本文をmax-body-size 文字まで切り詰めて... を追加します。logbook.write.max-body-size 値に関係なく、リクエストがロギングの対象であれば、ログブックは引き続き本文全体をバッファリングします。 | -1 (無効) |
logbook :
predicate :
include :
- path : /api/**
methods :
- GET
- POST
- path : /actuator/**
exclude :
- path : /actuator/health
- path : /api/admin/**
methods :
- POST
filter.enabled : true
secure-filter.enabled : true
format.style : http
strategy : body-only-if-status-at-least
minimum-status : 400
obfuscate :
headers :
- Authorization
- X-Secret
parameters :
- access_token
- password
write :
chunk-size : 1000
attribute-extractors :
- type : JwtFirstMatchingClaimExtractor
claim-names : [ "sub", "subject" ]
claim-key : Principal
- type : JwtAllMatchingClaimsExtractor
claim-names : [ "sub", "iat" ]
基本的な Logback 構成の場合
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
LogstashLogbackSink
を使用してログブックを構成する
HttpLogFormatter formatter = new JsonHttpLogFormatter();
LogstashLogbackSink sink = new LogstashLogbackSink(formatter);
のような出力の場合
{
"@timestamp" : "2019-03-08T09:37:46.239+01:00",
"@version" : "1",
"message" : "GET http://localhost/test?limit=1",
"logger_name" : "org.zalando.logbook.Logbook",
"thread_name" : "main",
"level" : "TRACE",
"level_value" : 5000,
"http" : {
// logbook request/response contents
}
}
LogstashLogbackSink
特定のレベルで初期化することで、デフォルトのログ レベルを柔軟にカスタマイズできます。例えば:
LogstashLogbackSink sink = new LogstashLogbackSink(formatter, Level.INFO);
getWriter
やgetParameter*()
使用するダウンストリーム コードに干渉します。詳細については、「サーブレット」を参照してください。ERROR
ディスパッチをサポートしていません。エラー応答を生成するためにこれを使用しないことを強くお勧めします。 質問、懸念事項、バグレポートなどがある場合は、このリポジトリの Issue Tracker に問題を提出してください。
貢献するには、プル リクエストを作成し、追加または変更の簡単な説明 (1 ~ 2 文) を追加するだけです。詳しくは投稿ガイドラインをご確認ください。
ネルソン時代の 3 本マストの 6 等フリゲートのレプリカ、グランド ターク - JoJan による航海日誌と海図は、クリエイティブ コモンズ (表示 - 継承 3.0 非移植) の下でライセンスされています。