§ロギング API
アプリケーションでロギングを使用すると、モニタリング、デバッグ、エラートラッキング、およびビジネスインテリジェンスに役立ちます。Play はロギングファサードとして SLF4J
を、デフォルトのロギングエンジンとして Logback を使用します。
§ロギングアーキテクチャ
ロギング API は、効果的なロギング戦略を実装するのに役立つ一連のコンポーネントを使用します。
§ロガー
アプリケーションは、ログメッセージリクエストを送信するロガーを定義できます。各ロガーには、ログメッセージに表示され、構成に使用される名前があります。
ロガーは、そのネーミングに基づいて階層的な継承構造に従います。あるロガーの名前の後にドットが続いたものが、子孫ロガーの名前のプレフィックスである場合、そのロガーは別のロガーの祖先であると言えます。たとえば、「com.foo」という名前のロガーは、「com.foo.bar.Baz」という名前のロガーの祖先です。すべてのロガーはルートロガーから継承します。ロガーの継承により、共通の祖先を構成することで、一連のロガーを構成できます。
各クラスに対して個別の名前付きロガーを作成することをお勧めします。この規約に従って、Play ライブラリは「play」の下に名前空間化されたロガーを使用し、多くのサードパーティライブラリはクラス名に基づいてロガーを持ちます。
§ログレベル
ログレベルは、ログメッセージの重大度を分類するために使用されます。ログリクエストステートメントを記述するときに、重大度を指定すると、生成されたログメッセージに表示されます。
これは、重大度の高い順に並べられた利用可能なログレベルのセットです。
OFF
- ロギングをオフにするために使用され、メッセージ分類としては使用されません。ERROR
- ランタイムエラー、または予期しない状態。WARN
- 非推奨の API の使用、API の不適切な使用、「ほぼ」エラー、望ましくない、または予期しないが、必ずしも「間違い」ではないその他のランタイム状況。INFO
- アプリケーションの起動やシャットダウンなどの興味深いランタイムイベント。DEBUG
- システムを介したフローに関する詳細情報。TRACE
- 最も詳細な情報。
メッセージを分類することに加えて、ログレベルは、ロガーとアペンダーの重大度しきい値を構成するために使用されます。たとえば、レベル INFO
に設定されたロガーは、INFO
以上のレベル (INFO
、WARN
、ERROR
) のリクエストをすべてログに記録しますが、低い重大度 (DEBUG
、TRACE
) のリクエストは無視します。OFF
を使用すると、すべてのログリクエストが無視されます。
§アペンダー
ロギング API を使用すると、ログリクエストを「アペンダー」と呼ばれる 1 つまたは複数の出力先に印刷できます。アペンダーは構成で指定され、コンソール、ファイル、データベース、およびその他の出力のオプションが存在します。
アペンダーをロガーと組み合わせることで、ログメッセージをルーティングおよびフィルタリングできます。たとえば、分析に役立つデータをログに記録するロガーに 1 つのアペンダーを使用し、運用チームが監視するエラー用に別のアペンダーを使用できます。
注: アーキテクチャの詳細については、Logback のドキュメント を参照してください。
§ロガーの使用
最初に、Logger
クラスをインポートします
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
§ロガーの作成
name
引数を持つ LoggerFactory
を使用して、新しいロガーを作成できます
final Logger accessLogger = LoggerFactory.getLogger("access");
アプリケーションイベントをロギングするための一般的な戦略は、クラス名を使用して、クラスごとに個別のロガーを使用することです。ロギング API は、クラス引数を受け取るファクトリメソッドでこれをサポートしています
final Logger log = LoggerFactory.getLogger(this.getClass());
次に、Logger
を使用してログステートメントを書き込むことができます
// Log some debug info
logger.debug("Attempting risky calculation.");
try {
final int result = riskyCalculation();
// Log result if successful
logger.debug("Result={}", result);
} catch (Throwable t) {
// Log error with message and Throwable.
logger.error("Exception with riskyCalculation", t);
}
Play のデフォルトのロギング構成を使用すると、これらのステートメントは次のようなコンソール出力を生成します
[debug] c.e.s.MyClass - Attempting risky calculation.
[error] c.e.s.MyClass - Exception with riskyCalculation
java.lang.ArithmeticException: / by zero
at controllers.Application.riskyCalculation(Application.java:20) ~[classes/:na]
at controllers.Application.index(Application.java:11) ~[classes/:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:69) [classes/:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:69) [classes/:na]
at play.core.Router$HandlerInvoker$$anon$8$$anon$2.invocation(Router.scala:203) [play_2.10-2.3-M1.jar:2.3-M1]
メッセージには、ログレベル、ロガー名 (この場合はクラス名で、省略形で表示されます)、メッセージ、およびログリクエストで Throwable
が使用された場合はスタックトレースが含まれることに注意してください。
application
という名前のロガーにアクセスできる play.Logger
静的メソッドもありますが、Play 2.7.0 以降ではその使用は非推奨です。上記で定義した戦略のいずれかを使用して、独自のロガーインスタンスを宣言する必要があります。
§マーカーの使用
SLF4J API には、ロギングメッセージを充実させ、メッセージを特に関心のあるものとしてマークする役割を果たすマーカーの概念があります。マーカーは、トリガーとフィルタリングに特に役立ちます。たとえば、OnMarkerEvaluator はマーカーが検出されたときにメールを送信したり、特定のフローを独自のアペンダーにマークアウトしたりできます。
マーカーは、ロガーの追加のコンテキスト情報を伝達できるため、非常に役立ちます。たとえば、Logstash Logback Encoder を使用すると、リクエスト情報をロギングステートメントに自動的にエンコードできます
import static net.logstash.logback.marker.Markers.append;
private Marker requestMarker(Http.Request request) {
return append("host", request.host()).and(append("path", request.path()));
}
public Result index(Http.Request request) {
logger.info(requestMarker(request), "Rendering index()");
return ok("foo");
}
マーカーは、ログレベルを明示的に変更せずに、特定のリクエストをログに記録する場合の「トレーサーバレット」スタイルのロギングにも非常に役立つことに注意してください。たとえば、特定の条件が満たされた場合にのみマーカーを追加できます
public class JavaTracerController extends Controller {
private final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(this.getClass());
private static final Marker tracerMarker = org.slf4j.MarkerFactory.getMarker("TRACER");
private Marker tracer(Http.Request request) {
Marker marker = MarkerFactory.getDetachedMarker("dynamic"); // base do-nothing marker...
request.queryString("trace").ifPresent(s -> marker.add(tracerMarker));
return marker;
}
public Result index(Http.Request request) {
logger.trace(tracer(request), "Only logged if queryString contains trace=true");
return ok("hello world");
}
}
次に、logback.xml
で次の TurboFilter を使用してロギングをトリガーします
<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
<Name>TRACER_FILTER</Name>
<Marker>TRACER</Marker>
<OnMatch>ACCEPT</OnMatch>
</turboFilter>
この時点で、入力に応じてデバッグステートメントを動的に設定できます。
ロギングでマーカーを使用する方法の詳細については、Logback マニュアルの TurboFilters セクションと マーカーベースのトリガー セクションを参照してください。
§ロギングパターン
ロガーを効果的に使用すると、同じツールで多くの目標を達成するのに役立ちます
import java.util.concurrent.CompletionStage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.mvc.Action;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
import play.mvc.With;
public class Application extends Controller {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
@With(AccessLoggingAction.class)
public Result index() {
try {
final int result = riskyCalculation();
return ok("Result=" + result);
} catch (Throwable t) {
logger.error("Exception with riskyCalculation", t);
return internalServerError("Error in calculation: " + t.getMessage());
}
}
private static int riskyCalculation() {
return 10 / (new java.util.Random()).nextInt(2);
}
}
class AccessLoggingAction extends Action.Simple {
private static final Logger accessLogger = LoggerFactory.getLogger(AccessLoggingAction.class);
public CompletionStage<Result> call(Http.Request request) {
accessLogger.info(
"method={} uri={} remote-address={}",
request.method(),
request.uri(),
request.remoteAddress());
return delegate.call(request);
}
}
この例では、アクション構成を使用して、リクエストデータを「access」という名前のロガーにログ記録する AccessLoggingAction
を定義します。Application
コントローラーはこのアクションを使用し、アプリケーションイベントのために独自のロガー (クラス名にちなんで名付けられています) も使用します。構成では、これらのロガーをアクセスログやアプリケーションログなどの異なるアペンダーにルーティングできます。
特定のアクションに対してのみリクエストデータをログに記録する場合は、上記の設計が適しています。すべてのリクエストをログに記録するには、フィルターを使用するか、play.http.DefaultHttpRequestHandler
を拡張することをお勧めします。
§構成
構成の詳細については、ロギングの構成 を参照してください。
次へ: 高度なトピック
このドキュメントにエラーを見つけましたか?このページのソースコードは こちら にあります。ドキュメントガイドライン を読んだ後、プルリクエストを自由に投稿してください。質問やアドバイスがありますか? コミュニティフォーラム にアクセスして、コミュニティとの会話を始めましょう。