34 JDBCの診断機能
Oracle Database 12cリリース1 (12.1)の診断機能を使用すると、Oracle JDBCドライバを使用するアプリケーションの問題や、ドライバ自体の問題を診断できます。また、Oracle JDBCドライバを使用してOracle DatabaseインスタンスにアクセスするJavaアプリケーションを開発、保守するために必要な労力を低減できます。
Oracle JDBCドライバには、ユーザーがJDBCアプリケーションの問題を識別および修正することを可能にする次の診断機能が用意されています。
ノート:
JDBCドライバの診断機能は、標準のjava.util.logging
フレームワークおよびjavax.management
MBeanフレームワークに基づいています。これらの標準フレームワークについての情報はこの文書では扱いません。
34.1 Oracle JDBCドライバのロギング機能について
この項では、次の概念について説明します。
34.1.1 Oracle JDBCドライバのロギング機能の概要
JDBCドライバのコードが実行されるときに発生するイベントの情報を記録します。イベントには、SQL例外などユーザーの目に触れるイベントも、内部JDBCメソッドの出入りなどの詳細JDBC内部イベントも含めることができます。ユーザーがこの機能を有効にすると、特定のイベントまたはすべてのイベントを記録することができます。
Oracle Database 11gより前は、JDBCドライバは、J2SE 2.0と3.0をサポートしていました。J2SEのこれらのバージョンには、java.util.logging
が含まれませんでした。このため、Oracle Database 11gより前のJDBCドライバ・リリースによって提供されるロギング機能は、java.util.logging
フレームワークと異なります。
Oracle Database 11g以降、JDBCドライバではJ2SE 2.0と3.0はもうサポートされません。このため、JDBCドライバのロギング機能は、標準java.util.logging
パッケージをフル活用します。強化されたロギング・システムではログ・レベルが有効利用され、ユーザーはログ出力を関心のものに制限できます。特定のクラスの情報がより一貫して記録されるため、ログ・ファイルがわかりやすくなりました。
この機能では新しいAPIや構成ファイルは導入されません。既存の標準java.util.logging
構成ファイルに新しいパラメータが追加されたのみです。これらのパラメータはjava.util.logging
の使用に不可欠なもので、既存のパラメータと同様に使用されます。
ノート:
生成されたログの内容の正確性は保証されません。ログの内容は大部分、実装の詳細に依存します。実装の細部はリリースのたびに変更されるため、ログの正確な内容もリリースごとに変更される傾向があります。
34.1.2 JDBCロギングの有効化と使用
Javaアプリケーションのデバッグを開始する前に、JDBCロギングを有効にして、構成する必要があります。この項では、JDBCロギングを有効にして使用するために実行する必要があるステップを説明します。内容は次のとおりです。
34.1.2.1 CLASSPATHの構成について
JDBCドライバのそれぞれのバージョンに対応するいくつかのJARファイルが付属しています。最適化されたJARファイルにはロギング・コードが含まれていないため、使用時にログ出力が生成されません。ログ出力を取得するには、デバッグJARファイル(ojdbc6_g.jar
やojdbc7_g.jar
のようにファイル名に_gが付いています)を使用する必要があります。デバッグJARファイルはCLASSPATH
に含まれている必要があります。
ノート:
デバッグJARファイル、たとえばojdbc6_g.jar
やojdbc7_g.jar
がCLASSPATH
内の唯一のOracle JDBC JARファイルであることを確認してください。
34.1.2.2 ロギングの有効化
ロギングを有効化する方法には次のようなものがあります。
-
Javaシステム・プロパティの設定
oracle.jdbc.Trace
システム・プロパティを設定することによってロギングを有効にできます。java -Doracle.jdbc.Trace=true ...
システム・プロパティの設定によりグローバル・ロギングを有効にできます。ロギングがアプリケーション全体に対して有効になります。アプリケーション全体をデバッグする場合、またはアプリケーションのソース・コードを変更しないか変更できない場合は、グローバル・ロギングを使用できます。
-
プログラムによる有効化
ロギングをプログラム的に有効または無効にするには、次のようにします。
最初に、Diagnosability MBeanの
ObjectName
を取得します。ObjectName
は次のようになりますcom.oracle.jdbc:type=diagnosability,name=<loader>
loader
は、Oracle JDBCドライバをロードしたクラス・ローダー・インスタンスに基づいた一意の名前です。ノート:
ドライバは、1つの仮想マシンに複数回ロードできます。したがって、それぞれ一意の名前を持つ複数のMBeanが存在することになります。
次のとおりにコードを作成します。
ClassLoader l = oracle.jdbc.OracleDriver.getClassLoader(); String loader = l.getName() + "@" + l.hashCode(); // compute the ObjectName
javax.management.ObjectName name = new javax.management.ObjectName("com.oracle.jdbc:type=diagnosability, name="+loader); // get the MBean server javax.management.MBeanServer mbs = java.lang.management.ManagementFactory.getPlatformMBeanServer(); // find out if logging is enabled or not System.out.println("LoggingEnabled = " + mbs.getAttribute(name, "LoggingEnabled")); // enable logging mbs.setAttribute(name, new javax.management.Attribute("LoggingEnabled", true)); // disable logging mbs.setAttribute(name, new javax.management.Attribute("LoggingEnabled", false));
ノート:
-
同じクラス・ローダーでJDBCドライバが複数回数をロードすると、一意の名前を作成するために、MBeanが追加されるたびに
l.hashCode()
メソッドの値が増加します。どのMBeanがどのJDBCドライバ・インスタンスに関連付けられているかを識別することが難しくなる可能性があります。 -
ロードされているJDBCドライバのインスタンスが1つしかない場合は、名前を*に設定します。
-
プログラムでロギングを有効および無効にすると、ログ出力の生成に必要なアプリケーションの部分を変更しやすくなります。
ノート:
上のいずれかの方法を使用してロギングを有効にしても、重大なエラーの最小限のログが生成されるだけです。通常、それではあまり役に立ちません。より有用で詳細なログを生成するには、java.util.logging
を構成する必要があります。
34.1.2.3 ロギングの構成
有用で詳細なログを生成するには、java.util.logging
を構成する必要があります。これには、構成ファイルを使用する方法と、プログラム的に行う方法があります。
JDBCをインストールすると、サンプル構成ファイル、OracleLog.properties
がdemo
ディレクトリに配置されます。そこにはjava.util.logging
の構成方法に関する基本情報や、最初に使用できるいくつかの初期設定が含まれています。このサンプル・ファイルをそのまま使用することも、ファイルを編集して使用することも、ファイルの名前を変更して使用することも、任意の名前を持つ完全に新しいファイルを作成することも可能です。
構成ファイルを使用するには、Javaランタイムにそれを認識させる必要があります。それには、システム・プロパティを設定します。次に例を示します。
java -Djava.util.logging.config.file=/jdbc/demo/OracleLog.properties.
ファイルはjava.util.logging
システムによって読み取られます。このファイルはどこに配置してもかまいません。
java.util.logging.config.file
とoracle.jdbc.Trace
は同時に使用できます。
java -Djava.util.logging.config.file=/jdbc/demo/OracleLog.properties -Doracle.jdbc.Trace=true
デフォルトのOracleLog.properties
ファイルを使用できます。希望する出力が得られる場合も、得られない場合もあります。独自の構成ファイルを作成して使用することもできます。次のステップに従ってください。
ノート:
ステップ2で指定した設定を使用すると、大量のログ出力が生成されます。また、ログ出力はコンソールに表示されます。
34.1.2.4 ログ出力のファイルへのリダイレクト
また、java.util.logging
を構成して、ログ出力をファイルにリダイレクトできます。そうする場合は、構成ファイルを次のように変更します。
.level=SEVERE oracle.jdbc.level=INFO oracle.jdbc.handlers=java.util.logging.FileHandler java.util.logging.FileHandler.level=INFO java.util.logging.FileHandler.pattern=jdbc.log java.util.logging.FileHandler.count=1 java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
これにより、正確に同じログ出力が生成され、現在のディレクトリにjdbc.log
という名前のファイルで保存されます。
レベル設定を変更することで、詳細度を制御することができます。定義されているレベルは、最も詳細度の低いものから最も高いものまで、次のようになります。
-
OFF
ロギングをオフにします。
-
SEVERE
SQLExceptionと内部エラーを記録します。
-
WARNING
SQLWarningと、好ましくないが致命的ではない内部の状況を記録します。
-
INFO
まれではあるが重要なイベントおよびエラーを記録します。生成されるログ・メッセージは比較的小量です。
-
CONFIG
実行されるSQL文字列を記録します。
-
FINE
すべてのパブリック・メソッドへの出入りが記録されるため、JDBC操作を詳細にトレースできます。生成されるログ・メッセージはかなり大量です。
-
FINER
内部メソッドのコールを記録します。
-
FINEST
大量の内部メソッドのコールを記録します。
-
ALL
詳細をすべて記録します。ロギング詳細度が最も高いレベルです。
ノート:
詳細度がFINE
を超えるレベルでは、非常に大量のログが生成されます。
上で示された例で詳細の出力量を削減するには、java.util.logging.FileHandler.level
設定をALL
からINFO
に変更します。
java.util.logging.FileHandler.level=INFO
ノート:
INFO
では、実行されるSQL文字列を記録します。
oracle.jdbc
ログ出力のレベルを変更することは可能ですが、必要ありません。FileHandler
レベルを設定することで、ログ・ファイルにダンプされるログ・メッセージを制御できます。
34.1.2.5 ログ出力の使用
レベルを設定すると、JDBCからのすべてのロギング出力が減少します。しかし、コードのある部分からの出力は大量に必要ですが、他の部分からはほとんど必要ない場合があります。そうするには、ログ出力に関する深い理解が必要です。
ログ出力は、名前で定義されたツリー構造をなしています。ルート・ログ出力の名前は「」(空の文字列)です。構成ファイルの最初の行には、.level=SEVERE
と記述されています。これは、ルート・ログ出力のレベル設定です。次の行はoracle.jdbc.level=INFO
です。これは、oracle.jdbc
という名前のログ出力のレベルを設定しています。oracle.jdbc
ログ出力は、ログ出力ツリーのメンバーです。その親はoracle
という名前です。oracle
ログ出力の親がルート・ログ出力(空の文字列)です。
ロギング・メッセージは、特定のログ出力(たとえば、oracle.jdbc
)に送信されます。メッセージがそのレベルのレベル・チェックに合格すると、メッセージは、そのレベルのハンドラ(存在する場合)と親ログ出力に渡されます。このため、ずっと見ていくと、oracle.log
に送信されるログ・メッセージはそのログ出力のレベル、INFO
に対して比較されます。レベルが同じか低い(詳細度が低い)場合、FileHandlerと親ログ出力(oracle)に送信されます。この場合も、レベルに対して確認されます。この例のような場合は、レベルが設定されていないため、親レベル(SEVERE
)が使用されます。メッセージ・レベルが同じか低い場合は、ハンドラに渡され(存在しません)、親に送信されます。この場合は、ルート・ログ出力の親です。このようなツリー構造は、出力の量を減らす役には立ちませんでした。役に立つのは、JDBCドライバがいくつかのサブ・ログ出力を使用するということです。ログ・メッセージをいずれかのサブ・ログ出力に制限すると、出力が大幅に少なくなります。Oracle JDBCドライバによって使用されるログ出力は、次のとおりです。
-
oracle.jdbc
-
oracle.jdbc.pool
-
oracle.jdbc.rowset
-
oracle.jdbc.xa
-
oracle.sql
ノート:
ドライバが使用するログ出力は、リリースによって異なることがあります。
34.1.2.6 ロギングの例
oracle.sql
コンポーネントで発生していることを追跡し、残りのドライバに関する基本情報の一部を取得する場合を考えます。これは、ロギングのより複雑な使用方法です。config
ファイルのエントリを次に示します。
# # set levels # .level=SEVERE oracle.level=INFO oracle.jdbc.driver.level=INFO oracle.jdbc.pool.level=OFF oracle.jdbc.util.level=OFF oracle.sql.level=INFO # # configure handlers # oracle.handlers=java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level=INFO java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
構成ファイルのそれぞれの行で行われている処理を検討します。
.level=SEVERE
ルート・ログ出力のロギング・レベルをSEVERE
に設定します。深刻な障害の場合を除き、他の、Oracleのものでないコンポーネントからのロギングを確認する必要はありません。このため、すべてのログ出力のデフォルト・レベルをSEVERE
に設定します。明示的に設定された場合を除いて、各ログ出力はレベルを親から継承します。ルート・ログ出力のレベルをSEVERE
に設定すると、あらためて設定したログ出力を除いて、他のすべてのログ出力が確実にそのレベルを継承するようにできます。
oracle.level=INFO
oracle.sql
とoracle.jdbc.driver
ログ出力の両方からログを出力します。共通の祖先はoracle
です。このため、oracle
ログ出力のレベルをINFO
に設定します。より低いレベルでは詳細度をより明示的に制御します。
oracle.jdbc.driver.level=INFO
ここでは、oracle.jdbc.driver
からのSQL実行の表示のみが必要です。このため、レベルをINFO
に設定します。これはかなり小量のレベルですが、このテストの処理内容を追跡するためには役立ちます。
oracle.jdbc.pool.level=OFF
このテストではDataSource
を使用しており、そのロギングすべてを表示する必要はありません。したがって、OFF
にします。
oracle.jdbc.util.level=OFF
oracle.jdbc.util
パッケージからのロギングを表示する必要はありません。XAまたはRowsetを使用していた場合、それもオフにします。
oracle.sql.level=INFO
oracle.sql
で発生していることを表示します。このため、レベルをINFO
に設定します。これにより、大量の詳細が出力されるのを回避しながら、パブリック・メソッドのコールについて多くの情報が得られます。
oracle.handlers=java.util.logging.ConsoleHandler
stderr
に全内容をダンプします。テストを実行する場合、stderr
をファイルにリダイレクトします。
java.util.logging.ConsoleHandler.level=INFO
System.err
であるコンソールに全内容をダンプします。この場合、ハンドラでなくログ出力でフィルタリングしています。
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
簡単でほぼ判読可能な形式を使用します。
この構成ファイルでテストを実行すると、oracle.sql
パッケージからは適度に詳細な情報を取得し、コア・ドライバ・コードからは少量の情報を取得します。他のコードからは何も取得しません。
XMLFormatter
を使用して、Oracleサポートにログを送信することもできます。
カスタムjava.util.logging.Filter
を実装および使用して、ログに書き込まれたデータをより詳細に制御できます。これは標準java.util.logging
機能で、JSEのJavaDocに記述されています。カスタム・フィルタを使用すると、次のことが可能になります。
-
マルチスレッド・アプリケーションのスレッドの取得(1つのみ)
-
長時間実行中のアプリケーションの断続的なエラーの取得
34.1.3 実行時における機能固有のロギングの有効化または無効化
Oracle Database 12cリリース2 (12.2.0.1)以降、JDBCでは実行時に選択した機能に対して機能固有のロギングの有効化または無効化がサポートされています。たとえば、ロード・バランシング機能のみのロギングを有効にして、JDBCの他の機能のロギングを無効にすることができます。また、同じ実行で高速接続フェイルオーバー機能のロギングを有効にして、ロード・バランシング機能のロギングを無効にすることもできます。
すべての機能のロギングはデフォルトで有効になっています。
JDBCのロギングの切替えノブはOracleDiagnosabilityMBean
に含まれています。このBeanを使用するには、JConsoleを起動してアプリケーションに接続します。
サポートされている機能のリストを表示するには、次のメソッドを使用します。
getTraceController().getSupportedFeatures()
現在有効になっている機能のリストを表示するには、次のメソッドを使用します。
getTraceController().getEnabledFeatures()
特定の機能またはすべての機能のロギングを有効にするには、次のようにtrace
メソッドを使用します。
trace(boolean enable, String feature_name)
trace(boolean enable, ALL)
特定の機能またはすべての機能のロギングを無効にするには、次のようにtrace
メソッドを使用します。
trace(boolean disable, String feature_name)
trace(boolean disable, ALL)
ロギングを一時停止および再開するには、それぞれ、次のメソッドを使用します。
suspend()
resume()
34.1.4 機能固有のロギング用のロギング構成ファイルの使用
Oracle Database 12cリリース2 (12.2.0.1)以降、ロギング構成ファイルにプロパティを追加することにより、特定の機能のロギングを有効または無効にすることができます。ロギングはデフォルトですべての機能について有効になっています。そうでない場合、次の構文を使用してすべての機能のロギングを有効にすることができます。
clio.feature.all = on
機能固有のロギングを有効にするには、次のプロパティを使用できます。
clio.feature.pool_statistics = on
clio.feature.check_in = on
clio.feature.check_out = on
clio.feature.labeling = on
clio.feature.conn_construction = on
clio.feature.conn_destruction = on
clio.feature.high_availability = on
clio.feature.load_balancing = on
clio.feature.transaction_affinity = on
clio.feature.web_affinity = on
clio.feature.data_affinity = on
clio.feature.conn_harvesting = on
clio.feature.ttl_conn_timeout = on
clio.feature.abandoned_conn_timeout = on
clio.feature.admin = on
clio.feature.sharding = on
34.1.5 パフォーマンス、スケーラビリティおよびセキュリティに関する問題点
ロギング機能を使用すると、アプリケーションの追跡やデバッグ、および詳細ログ出力の生成が可能になりますが、パフォーマンス、スケーラビリティおよびセキュリティに関する問題が多少あります。
注意:
トレース・ファイルには、ユーザー名、パスワードやユーザー・データなどの機密情報が含まれていることがあります。Oracleでは、このような機密情報を保護するために、本番データや資格証明が含まれるJDBCデバッグJARファイルを使用しないことをお薦めします。さらに、トレース・ファイルの作成のための適切なセキュリティ・プラクティスに従うことをお薦めします。
セキュリティ上の問題
フル・ロギングを有効にすると、機密情報がトレース・ファイルに公開されるというリスクが発生します。これはロギング機能の内在的問題です。ただし、特定のJDBC JARファイルにのみ、JDBCロギング機能が含まれます。次のJARファイルにはフル・ロギングが含まれるため、本番環境での使用はお薦めしません。
-
ojdbc8_g.jar
-
ojdbc8dms_g.jar
ojdbc8dms.jar
JARファイルには、制限付きのロギング機能が含まれています。
ノート:
データベースのユーザー名およびパスワードは、ojdbc8_g.jar
およびojdbc8dms_g.jar
JARファイルで作成されたログ・ファイルに表示されません。ただし、SQL文、定義された値またはバインド値の一部である機密ユーザー・データは、これらのJARファイルのいずれかを使用して作成されたログに表示されます。
トレース・ファイルのセキュアな処理について
トレース・ファイルをセキュアに処理するには、次のようにする必要があります。
-
トレース・ファイルの機密情報の量を最小限に抑えるために、実行のトレースは必要な分のみにします。
-
ユーザーが所有するディレクトリでトレース・ファイルを作成します。
/tmp
ディレクトリなどの共通のパブリック・ディレクトリにファイルを作成しないでください。 -
トレース・ファイルを作成するディレクトリに
UMASK
を設定します。これにより、トレース・ファイルへのユーザー・アクセスが制限されます。 -
java.util.logging.FileHandler
でappend
オプションを有効にしないでください。これにより、トレース・ファイルに対して所有者と権限を適切に制御できます。 -
ojdbc8.jar
ファイルの使用時に、LoggingPermission
をJDBCコード・ベースに付与しないでください。ojdbc8dms.jar
ファイルはログ出力が制限されており、LoggingPermission
が必要です。デバッグJARファイルojdbc8_g.jar
およびojdbc8dms_g.jar
には拡張トレースが含まれており、LoggingPermission
が必要です。
パフォーマンスとスケーラビリティの問題
ロギングは、パフォーマンスにかなり影響します。本番システムでロギングが有効になっていないことを確認する必要があります。また、本番環境でデバッグJARファイルを使用しないでください。ロギングが無効の場合、パフォーマンスへの影響はありません。
ロギングには、多くの共有リソースへの保護アクセスが伴うため、結果として、スケーラビリティが大幅に低下します。これはjava.util.logging
フレームワークの問題です。
34.2 診断能力管理
JDBC診断能力管理機能には、MBean、oracle.jdbc.driver.OracleDiagnosabilityMBean
が導入されています。このMBeanを使用して、JDBCロギングの有効化および無効化が可能です。
関連項目:
OracleDiagnosabilityMBean
APIの詳細は、JDBC Javadocを参照してください。
将来のリリースでは、このMBeanはJDBC内部関数に関する他の統計情報を提供するように拡張されます。
セキュリティ上の問題
この機能により、JDBCロギングを有効にできます。JDBCロギングを有効にするには、特別な権限は必要ありません。ただし、ロギングが有効になると、ログ出力を生成するために標準のJava権限LoggingPermission
が必要になります。この権限がない場合、ログを生成するすべてのJDBC処理でセキュリティ例外がスローされます。これは標準のJavaメカニズムです。