1.はじめに
Spring Bootバージョン:2.3.4.RELEASE
オンラインで問題が発生したときにDEBUGログが必要かどうかはわかりませんが、現在INFOが使用されています。
DEBUGを有効にする場合は、バージョンを再パッケージ化してリリースする必要がありますが、シナリオによっては、再起動後に問題が再発しない場合があり、これは非常に苦痛です。
今日は、Spring Bootでのログ構成の動的調整について説明します。これにより、ログレベルを自由に移動できます。
春のブートログ
SpringBoot内で実際に使用されているのはCommonsLoggingであり、Spring Bootに基づく構成ロードメカニズムは、Java Util Logging、Log4j2、およびLogbackといういくつかのロギング方法を提供します。
ログバックはデフォルトのログフレームワークです。特別な必要がない場合は、ログバックを置き換えることはお勧めしません。(パフォーマンスについては話さないでください)
ログ形式
実際のアプリケーションで重要なフォーマットなどを過小評価しないでください。
あなたの会社に統合ログの基本コンポーネントがあるかどうかはわかりません。もちろん、統合ログ構成ファイルがないか、おそらく存在するでしょう。
ログ形式が統一されていない場合、各プロジェクトに独自のスタイルがある場合、ログの分割を支援するように運用および保守パートナーにどのように依頼できますか?警察に電話しますか?それは本当に定期的な死への手紙であり、完全に電気を生成するために愛に依存しています。(たとえば、使用するLoghubが均一でない場合、操作と保守によって強制終了されます)
ログ形式の構成を見てみましょう。ここではパターンのみです。
-|%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{tid}|%thread|%logger{36}.%M:%L-%msg%n
まず、各ポジションについて説明します。
- %d {yyyy-MM-dd HH:mm:ss.SSS}:時間
- %-5レベル:ログレベル
- %X {tid}:カスタム分散トラッキングID
- %thread:スレッド
- %logger {36}。%M:%L:クラスのフルネーム(36は最長の文字を表します)。情報行番号
- %msg%n:ラップする情報を出力します
なぜその前に-|があるのか理解できるかどうかわかりませんか?実際、例外スタック情報などの通常のセグメンテーション時にニューラインログを区別するのに便利です。
いくつかの知識ポイント
Spring Bootで使用される他のいくつかの小さなポイントについて話しましょう、トピックに取り掛かりましょう
- ここで、LogbackにはFATALレベルがなく、ERRORとして分類されます
- application.propertiesでdebug = trueを構成してデバッグモードを有効にすることができます。また、trace = trueを構成してトレースモードを有効にすることもできます。
- application.propertiesのlogging.level。=を使用して、org.hibernateレベルがERRORに設定されるなどのさまざまなログレベルを構成できます。logging.level.org.hibernate= error
- ロググループの概念。このような構成が煩わしい場合は、全体的な構成に対してグループを設定できます。例:logging.group.tomcat = org.apache.catalina、org.apache.coyote構成レベルはTRACEですlogging.level.tomcat = TRACE
- Logback構成ファイルを使用する場合、公式の推奨事項はlogback-spring.xmlのような名前を使用することです。logback.xmlを使用する場合、Springのログの初期化が問題になるはずです。
- ログ構成を制御しているが、logback.xmlをログバック構成の名前として使用したくない場合は、application.properties構成ファイルのlogging.configプロパティを介してカスタム名を指定できます。logging.config= classpath:xxx-log.xml
2つ目は、ログレベルを動的に変更することです。
実行状態のSpringBootアプリケーションが動的ログレベルをどのように変更するかについて説明しましょう
スプリングブートアクチュエータ
アクチュエータは、Spring Bootの名前、監視、監査、測定情報などを知っている必要があります。私たちが使用する正常なシャットダウン、ヘルスチェック、およびログ情報はすべて、これらのものによって実現されます。
Actuatorを使用した後、LoggerRESTインターフェイスを使用してログを操作できます。次の3つがあります。
- GET http://127.0.0.1:6080/actuator/loggersは、現在のアプリケーションのすべてのログレベル情報(必要なものまたは何)を返します。
- GET http://127.0.0.1:6080/actuator/loggers/ {name}は、{name}のログレベルを返します
- POST http://127.0.0.1:6080/actuator/loggers/ {name}構成パラメーター{"configuredLevel": "INFO"、 "effectiveLevel": "INFO"}ログレベルの変更
アクチュエータメカニズムを使用して、レベルを動的に変更します
1)必要な構成のSpring Boot Actuatorに依存します(親を継承する場合は、バージョンは必要ありません)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
2)、構成ファイル
#注意,这里我只开启了loggers,health两个Actuator
management.endpoints.web.exposure.include=loggers,health
management.endpoint.loggers.enabled=true
3)、コントローラーを作成します
@RestController
@RequestMapping("/log")
public class TestLogController {
private Logger log = LoggerFactory.getLogger(TestLogController.class);
@GetMapping
public String log() {
log.trace("This is a TRACE level message");
log.debug("This is a DEBUG level message");
log.info("This is an INFO level message");
log.warn("This is a WARN level message");
log.error("This is an ERROR level message");
return "See the log for details";
}
}
4)、アプリケーションを起動します
この時点で、アプリケーションを起動した後、IDEAを使用すると、次のマッピングが表示されます。ロガーに関する3つのRESTインターフェイスがあります。
5)、テスト
この時点で、最初にGET http://127.0.0.1:6080/logを実行すると、コンソールに次の情報が出力されます。
2020-10-15 23:14:51.204 INFO 52628 --- [nio-6080-exec-7] c.q.chapter1.failure.TestLogController : This is an INFO level message
2020-10-15 23:14:51.220 WARN 52628 --- [nio-6080-exec-7] c.q.chapter1.failure.TestLogController : This is a WARN level message
2020-10-15 23:14:51.221 ERROR 52628 --- [nio-6080-exec-7] c.q.chapter1.failure.TestLogController : This is an ERROR level message
このとき、GET http://127.0.0.1:6080/actuator/loggers/ROOTを実行し、{"configuredLevel": "INFO"、 "effectiveLevel": "INFO"}を返します。これは、この時点でのアプリケーションのログレベルがINFOであることを意味します。 ROOTはルートノードを表します。
6)、レベルを変更します
現時点では、INFO情報は確認しません。アプリケーションログレベル全体をWARNに変更する場合は、POSThttp://127.0.0.1:6080 / actuator / loggers / ROOTを実行します。パラメータは{"configuredLevel": "TRACE"、 "EffectiveLevel": "TRACE"}
この時点で、GET http://127.0.0.1:6080/logを再度実行すると、コンソールに次の情報が出力されます。
2020-10-15 23:24:11.481 TRACE 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController : This is a TRACE level message
2020-10-15 23:24:11.481 DEBUG 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController : This is a DEBUG level message
2020-10-15 23:24:11.481 INFO 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController : This is an INFO level message
2020-10-15 23:24:11.481 WARN 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController : This is a WARN level message
2020-10-15 23:24:11.481 ERROR 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController : This is an ERROR level message
他の方法
- 構成ファイルのスキャン:Logback自動スキャンの機能変更レベルです。logback-spring.xmlを有効にすると、logback-spring.xmlの内部ログレベルを動的に変更できます。興味がある場合は、自分で試すことができます。
- arthas動的変更
- Apolloなどのリモート構成センターと組み合わせて動的なレベル変更を実現
三つ、実現原理
ここでは主にSpringBoot Actuator Logを使用しているので、その原理についても説明します。
エンドポイントの読み込み
まず、図に示すように、依存するspring-boot-actuator(すべてのActuatorはこの番号です)からLoggersEndpointを見つけます。
Spring Bootのロードメカニズムに精通している友人は、各アクチュエータエンドポイントの背後に、エンドポイントをロードするためのxxxEndpointAutoConfigurationが必要であることを知っています。
これらのロードメカニズムはすべてspring-boot-actuator-autoconfigureに格納されており、LoggersEndpointAutoConfigurationを見つけてLoggersEndpointの構成クラスをロードできます。
そのコアを見てください:
@Bean
@ConditionalOnBean(LoggingSystem.class)
@Conditional(OnEnabledLoggingSystemCondition.class)
@ConditionalOnMissingBean
public LoggersEndpoint loggersEndpoint(LoggingSystem loggingSystem,
ObjectProvider<LoggerGroups> springBootLoggerGroups) {
return new LoggersEndpoint(loggingSystem, springBootLoggerGroups.getIfAvailable(LoggerGroups::new));
}
あなたは2つの重要なパラメータを見ることができます:
- LoggingSystem:抽象的なトップレベルクラス
- springBootLoggerGroups:現在のロググループデータを保存します
要約する:
1. spring-boot-starter-actuatorパッケージに依存した後、spring-boot-actuator-autoconfigureに依存します
2.spring-boot-actuator-autoconfigureでMETA-INF / spring.factoriesへのスキャンを開始すると、LoggersEndpointAutoConfigurationが次の場所にロードされます。
3. LoggersEndpoinはLoggersEndpointAutoConfigurationで宣言され、LoggingSystemとspringBootLoggerGroupsがパラメーターとして割り当てられます。
4.プロジェクトの開始後、LoggersEndpointインターフェイスを介してログデータにアクセスします
LoggingSystem
LoggingSystemの継承
以上のことから、LoggingSystemがログ操作管理の中核であることがわかりますので、まずは彼のダイアグラムを見てみましょう。
継承関係を通じて、LogbackLoggingSystemがマスターであることが一目でわかります。マスターはわかっていますが、LoggingSystemはどのようにロードされますか?
LoggingSystemのロード
主な参加者は次のとおりです。
- LoggingApplicationListener
- ApplicationStartingEvent
- LogbackLoggingSystem
- LoggingSystem
言うまでもない、最初の写真
1.アプリケーションはSpringApplication.run(Chapter1Application.class、args);を使用します。
2.起動イベントApplicationStartingEvent、ApplicationEnvironmentPreparedEventなどを送信します。
3. LoggingApplicationListenerは、イベント配布用のイベントを受信します
4.LoggingApplicationListenerはイベントApplicationStartingEventを受信します
5. LoggingApplicationListenerは、内部のonApplicationStartingEvent(ApplicationStartingEvent event)メソッドを呼び出し、LoggingSystem.get(classloader)を使用してLoggingSystemを初期化します。
6.次に、LogbackLoggingSystem.beforeInitialize()を呼び出します(ここではログバックを使用しているため)
7、LoggingApplicationListenerはイベントApplicationEnvironmentPreparedEventを受信します
8. LoggingApplicationListenerは、内部のonApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEventイベント)メソッドを呼び出します
9. onApplicationEnvironmentPreparedEventは、initialize(ConfigurableEnvironment environment、ClassLoader classLoader)メソッドを呼び出します。このメソッドは、環境変数の構成に従ってロギングシステムを初期化します。
LoggersEndpoint
最後に、LoggersEndpointを見てみましょう。解釈の便宜上、ここではすべてをコピーしません。どこを選択しますか?
まず、ログ操作用の3つのインターフェイスを見てください。
- GET / actuator / loggersは、パブリックMap <String、Object> loggers()メソッドに対応します
- GET /アクチュエータ/ロガー/ {名前}publicLoggerLevelsloggerLevels(@Selector String name)方法
- POST /アクチュエータ/ロガー/ {名前}publicvoidconfigureLogLevel(@Selector String name、@ Nullable LogLevel configurationLevel)方法
これはパブリックMap <String、Object> loggers()メソッドの例です。他は同様です。
@ReadOperation
public LoggerLevels loggerLevels(@Selector String name) {
Assert.notNull(name, "Name must not be null");
LoggerGroup group = this.loggerGroups.get(name);
if (group != null) {
return new GroupLoggerLevels(group.getConfiguredLevel(), group.getMembers());
}
LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(name);
return (configuration != null) ? new SingleLoggerLevels(configuration) : null;
}
コードは実際には非常に単純なので、あまり解釈はしません。
四、話
実際、ログはシステムアプリケーションで非常に重要であり、トラブルシューティングの重要な証拠でもあります。経験によると、私たちのシステムのログはいくつかのことをするはずです:
- 統一されたログ形式
- 統合されたログコンポーネントを提供するのが最善です。たとえば、publiclogback-spring.xmlコンポーネントを使用します。APMログの追加など、ログの特定の特性を変更する必要がある場合は、1つのポイントを変更するだけで、システムのすべてのログステータスが変更されます。