Microsoft JDBC Driver for SQL Server のトレース取得方法まとめ

Last Update:
このエントリーをはてなブックマークに追加

こんにちは、Japan Developer Support Core チームの近澤です。

今回は、Java アプリケーションで Microsoft JDBC Driver for SQL Server を使用する際のトレース取得方法についてご案内します。接続のトラブルシューティングを行う際には、JDBC ドライバーのトレースが非常に有用な情報となります。また、SSL/TLS 関連のエラーが発生した場合には、より深いレベルでのデバッグが必要となる場合もあります。

JDBC Driver のトレース取得方法

SQL Server JDBC Driver は Java 標準機能の Logger に対応しています。プログラムの実装を変更することなく Logger を使ってトレースを取得することができます。

詳細については、以下の公式ドキュメントもご参照ください。

手順 1: 構成ファイルの準備

まず、logging.properties という構成ファイルを準備します。以下は設定例です。

logging.properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
##############################
# Java Logging Configuration #
##############################
# Note: This file is used only when -Djava.util.logging.config.file=logging.properties is set.

# Global default level
.level=FINEST

# Output to file
handlers=java.util.logging.FileHandler

# File Handler Configuration
java.util.logging.FileHandler.pattern=logs/java_%u_%g.log
java.util.logging.FileHandler.limit=5000000
java.util.logging.FileHandler.count=20
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level=FINEST
java.util.logging.FileHandler.encoding=UTF-8

# JDBC Driver Logging
com.microsoft.sqlserver.jdbc.level=FINEST

手順 2: トレース採取の有効化

アプリケーション実行時のコマンド ラインで、以下のようにトレース採取を有効化します。

1
java -Djava.util.logging.config.file=C:\work\logging.properties app01

このコマンドの各部分の説明:

  • -Djava.util.logging.config.file=C:\work\logging.properties : Logger の構成ファイルを指定
  • app01 : 実行する Java アプリケーション

ログレベルについて

JDBC Driver のログは、Java Util Logging (JUL) に従いますが、ほとんどが下記のレベルに分類されます。

  • FINEST - 最も詳細なデバッグ情報(すべてのトレース)
  • FINER - より詳細なデバッグ情報
  • FINE - デバッグ情報(概要レベル)

ログレベルの詳細については、ドライバー操作のトレース(ログ) - ログ記録のレベルをご参照ください。

トラブルシューティングに必要なレベル

下記のような接続エラーメッセージを記録したい場合は、少なくとも FINE レベルに設定する必要があります。

FINE: *** SQLException:ConnectionID:1 ClientConnectionId: d5adaa76-d1e6-4ecf-9e18-c9f751efdb7b com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption.

FINE: *** SQLException: com.microsoft.sqlserver.jdbc.SQLServerException: Failed to authenticate the user username@yourdomain.com in Active Directory (Authentication=ActiveDirectoryIntegrated).

FINE: *** SQLException: com.microsoft.sqlserver.jdbc.SQLServerException: Login failed for user 'username'. Reason: Azure Active Directory only authentication is enabled. Please contact your system administrator.

SSL/TLS デバッグの有効化

JDBC ドライバーから呼び出される Java の下位レイヤーで SSL/TLS のエラーが発生する場合、ドライバーのトレースだけでは調査に十分ではないケースがあります。このような場合には、javax.net.debug オプションを使用します。

詳細については、Java Secure Socket Extension (JSSE) Reference Guide をご参照ください。

方法 1: コマンドライン オプションでの指定

1
java -Djava.util.logging.config.file=logging.properties -Djavax.net.debug=all app01

デフォルトでは標準出力に出力されます。ファイルに出力したい場合は、リダイレクトを使用します。

1
java -Djava.util.logging.config.file=logging.properties -Djavax.net.debug=all app01 > SSLlog.log 2>&1

このコマンドの各部分の説明:

  • -Djava.util.logging.config.file=logging.properties : JDBC ドライバーのトレースを有効化(前の章の設定)
  • -Djavax.net.debug=all : SSL/TLS の詳細なデバッグ情報を有効化
  • app01 : 実行する Java アプリケーション
  • > SSLlog.log : 標準出力を SSLlog.log ファイルにリダイレクト
  • 2>&1 : 標準エラー出力も標準出力と同じファイルにリダイレクト(これにより、すべての出力が SSLlog.log に記録されます)

方法 2: 環境変数での指定

java.exe を直接実行していない場合(アプリケーションサーバー経由での実行など)は、環境変数 JDK_JAVA_OPTIONS に追加指定できます。

1
set JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% -Djavax.net.debug=all

この設定により、実行時に -D のオプション指定をせずともデバッグログが標準出力に表示されるようになります。

出力例

以下のような詳細なデバッグログが出力されます。

javax.net.ssl|DEBUG|10|main|2023-08-18 17:53:50.966 JST|SSLSocketInputRecord.java:247|READ: TLSv1.2 application_data, length = 249
javax.net.ssl|DEBUG|10|main|2023-08-18 17:53:50.967 JST|SSLCipher.java:1675|Plaintext after DECRYPTION (
0000: 04 01 00 E1 00 49 01 00 81 02 00 00 00 00 00 00 .....I..........
0010: 00 08 00 38 02 49 00 64 00 00 00 00 00 08 00 E7 ...8.I.d........
0020: 64 00 09 04 D0 00 34 04 4E 00 61 00 6D 00 65 00 d.....4.N.a.m.e.
...
)

なお、基本的に、本番環境では -Djavax.net.debug は使用すべきではありません。 すべての SSL/TLS 通信で詳細なログが生成され、I/O オーバーヘッドが発生し、パフォーマンスに影響する可能性があります。 トラブルシューティング時の一時的な使用に限定してください。

プログラムから有効にする方法

前述の「JDBC Driver のトレース取得方法」と「SSL/TLS デバッグの有効化」では、コマンドラインオプションや環境変数を使用してトレースを有効化する方法を説明しました。ここでは、これらの設定をプログラムコード内から動的に有効化する方法をご紹介します。詳細については、ドライバー操作のトレース(ログ) - プログラムによるトレースの有効化もご参照ください。

この方法は、以下のようなケースで有用です:

  • アプリケーションの起動パラメータを変更できない環境
  • 特定の条件下でのみトレースを有効化したい場合

以下に示す LoggerManager クラスは、JDBC ドライバーのトレースと SSL/TLS デバッグの両方をプログラムから設定できるユーティリティクラスのサンプルです。

LoggerManager クラス

このクラスは、Java Util Logging の設定と SSL/TLS デバッグ出力のリダイレクトを管理します。

LoggerManager.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package org.example;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

/**
* Manages logging configuration for the application.
* Provides methods to configure Java Util Logging and SSL/TLS debug output.
*/
public final class LoggerManager {

private static final String LOG_DIR = "logs";
private static final String TIMESTAMP_FORMAT = "yyyyMMdd_HHmmss";
private static final int LOG_SIZE_BYTES = 5_000_000; // 5MB
private static final int LOG_FILE_COUNT = 20;
private static final String ENCODING = "UTF-8";

private static boolean loggingInitialized = false;
private static boolean sslDebugInitialized = false;

private LoggerManager() {
// Utility class - prevent instantiation
}

/**
* Initialize Java Util Logging with specific log level.
* Creates timestamped log files in logs/java_yyyyMMdd_HHmmss_%u_%g.log format.
*
* @param level Log level for JDBC driver logger (e.g., Level.FINEST, Level.FINE)
*/
public static void initializeLogging(Level level) {
if (loggingInitialized) {
return; // Already initialized
}

ensureLogDirectory();
String logFile = createLogFilePath("java", "_%u_%g.log");

try {
FileHandler handler = new FileHandler(logFile, LOG_SIZE_BYTES, LOG_FILE_COUNT, true);
handler.setEncoding(ENCODING);
handler.setFormatter(new SimpleFormatter());
handler.setLevel(level);

Logger jdbcLogger = Logger.getLogger("com.microsoft.sqlserver.jdbc");
jdbcLogger.addHandler(handler);
jdbcLogger.setLevel(level);
jdbcLogger.setUseParentHandlers(false);

loggingInitialized = true;
} catch (IOException e) {
System.err.println("Failed to initialize FileHandler: " + e.getMessage());
}
}

/**
* Initialize SSL/TLS debug output redirection with specified debug level.
* Redirects both System.out and System.err to log file only (no console output).
* Automatically sets javax.net.debug system property.
*
* @param debugLevel SSL debug level. e.g.
* - "all" : All SSL/TLS debug information
* - "ssl" : SSL/TLS related information
* - "ssl:handshake" : SSL handshake only
* - "ssl:record" : SSL record layer
* - "trustmanager" : Certificate trust management
* - "keymanager" : Key management
*/
public static void initializeSslDebugLogging(String debugLevel) {
if (sslDebugInitialized) {
return; // Already initialized
}

// Set javax.net.debug system property
System.setProperty("javax.net.debug", debugLevel);

ensureLogDirectory();
String logFile = createLogFilePath("ssl_debug", ".log");

try {
FileOutputStream fileStream = new FileOutputStream(logFile, true);
PrintStream filePrintStream = new PrintStream(fileStream, true, ENCODING);

System.setOut(filePrintStream);
System.setErr(filePrintStream);

sslDebugInitialized = true;
} catch (IOException e) {
System.err.println("Failed to redirect SSL debug output: " + e.getMessage());
e.printStackTrace();
}
}

private static void ensureLogDirectory() {
File logDir = new File(LOG_DIR);
if (!logDir.exists()) {
logDir.mkdirs();
}
}

private static String createLogFilePath(String prefix, String suffix) {
String timestamp = new SimpleDateFormat(TIMESTAMP_FORMAT).format(new Date());
return LOG_DIR + "/" + prefix + "_" + timestamp + suffix;
}
}

使用例

アプリケーションの Main クラスで、以下のように LoggerManager を使用してトレースを有効化します。

Main.java
1
2
3
4
5
// JDBC ドライバーのトレースを FINEST レベルで有効化
LoggerManager.initializeLogging(Level.FINEST);

// SSL/TLS デバッグ出力をファイルにリダイレクト
LoggerManager.initializeSslDebugLogging("all");

注意点

  • initializeSslDebugLogging() を呼び出すと、標準出力と標準エラー出力がファイルにリダイレクトされ、コンソールには出力されなくなります。
  • アプリケーションの起動時、データベース接続処理の前に呼び出すことをお勧めします。

サードパーティー製品での設定について

Java アプリケーションは WebLogic、WebSphere、Tomcat などのサードパーティー製品を介して実行されているケースが多くあります。その場合には、それぞれの製品上に Logger を有効化するための設定があります。各製品のドキュメントを参照して設定を行ってください。

まとめ

本記事では、Microsoft JDBC Driver for SQL Server のトレース取得方法について説明しました。

JDBC ドライバーのトレース取得

  • logging.properties ファイルを作成し、-Djava.util.logging.config.file オプションで指定
  • 接続エラーの調査には、少なくとも FINE レベルの設定が必要

SSL/TLS デバッグ

  • より深いレベルの調査には -Djavax.net.debug オプションを使用
  • 環境変数 JDK_JAVA_OPTIONS での指定も可能

プログラムからの設定

  • LoggerManager クラスを使用することで、コマンドラインオプションを変更せずにプログラム内からトレースを有効化可能
  • アプリケーションの起動パラメータを変更できない環境や、特定の条件下でのみトレースを有効化したい場合に有用

注意点

  • WebLogic、WebSphere、Tomcat などのアプリケーションサーバーを使用している場合は、各製品固有の Logger 設定方法を確認してください
  • トラブルシューティング時は適切なログレベルを設定し、問題解決後は必要に応じてログレベルを下げることをお勧めします

今回はここまでとなります。JDBC ドライバーのトラブルシューティングの際にぜひご活用ください。


本ブログの内容は弊社の公式見解として保証されるものではなく、開発・運用時の参考情報としてご活用いただくことを目的としています。もし公式な見解が必要な場合は、弊社ドキュメント (https://learn.microsoft.comhttps://support.microsoft.com) をご参照いただくか、もしくは私共サポートまでお問い合わせください。