【Java】 SSLログ や SOAPログ などのコンソールログをファイル出力に変更するには...

■ はじめに

 * 以下のコンソールログ(標準出力)を、ファイル出力するための方法を記述する。
 (もっといい方法がありそうだが)

 1) SSLログ
    => System.setProperty("javax.net.debug", "all");
詳細は以下の関連記事を参照のこと
http://blogs.yahoo.co.jp/dk521123/35261371.html
 2) WebサービスなどのSOAPログ
  2-1) サーバ側
    => System.setProperty("com.sun.xml.ws.transport.http.HttpAdapter.dump", "true");
  2-2) クライアント側
    => System.setProperty("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true");
詳細は以下の関連記事を参照のこと
http://blogs.yahoo.co.jp/dk521123/36522384.html

■ 方法

http://stackoverflow.com/questions/4595950/capture-javax-net-debug-to-file
に記載。ただ、この方法だと実用的に問題があったので、そのことも含めてサンプルを記載しておく。

■ 注意

 * (後述でも述べているが)System.out.println()などの結果も出力されてしまう
  => あくまで、本番ではなく、デバッグとして使用した方がいい
 * 現状、日本語が文字化けする

■ サンプル

 * 例として、以下の関連記事で行ったクライアント側のSOAPログ出力をベースに修正してみる
   (サーバ側の実装は、以下の関連記事と同じなので今回は省略している)
http://blogs.yahoo.co.jp/dk521123/36522384.html
 * Log出力として、今回は、以下の関連記事で書いた標準ログ java.util.logging を使う
 (別にLog4jとかでもいい)
http://blogs.yahoo.co.jp/dk521123/33205569.html

Demo.java

まずは、呼び出し側。以下の関連記事の「クライアントサイドの実装」がベース。
http://blogs.yahoo.co.jp/dk521123/36522384.html
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Logger;

public class Demo {
  final static Logger logger = Logger.getLogger("Demo");
  
  public static void main(String[] args) throws SecurityException, IOException {
    // ★追加★
    CustomLogHelper logHelper = new CustomLogHelper();
    logHelper.initilize(logger);
 
    // SOAP Log
    System.setProperty("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true");

    try {
      URL url = new URL("http://localhost:8080/SampleWebService/services/SampleWebService.ws?wsdl");
      HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
      httpURLConnection.setConnectTimeout(2 * 1000);
      httpURLConnection.setReadTimeout(2 * 1000);
      SampleWebServiceService service = new SampleWebServiceService(url);
      SampleWebService proxy = service.getSampleWebServicePort();

      long start = System.currentTimeMillis();
      String result = proxy.sayYourAge("Ken", 11L);
      long end = System.currentTimeMillis();
      System.out.println((end - start) + "ms");

      System.out.println("Result : " + result);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    
    // ★追加(後処理)★
    logHelper.close();

    System.out.println("Done");
  }
}

LogOutputStream.java

import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Logger;

public class LogOutputStream extends OutputStream {
  private StringBuilder stringBuilder = new StringBuilder();
  private Logger logger;
  
  public LogOutputStream(Logger logger) {
    this.logger = logger;
  }
  
  @Override
  public void write(int byteValue) throws IOException {
    if (byteValue == '\n') {
      this.logger.info(this.stringBuilder.toString());
      this.stringBuilder.setLength(0);
    } else {
      this.stringBuilder.append((char) byteValue);
    }
  }
}

CustomLogHelper.java

import java.io.Closeable;
import java.io.IOException;
import java.io.PrintStream;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CustomLogHelper implements Closeable {
  private PrintStream printStream;

  public CustomLogHelper() {
    this.printStream = null;
  }

  public void initilize(Logger logger) throws SecurityException, IOException {
    // Loggerの初期化
    FileHandler fileHandler = new FileHandler("SoapLog%u.%g.log", 10000, 10, true);
    fileHandler.setFormatter(new CustomLogFormatter());
    logger.addHandler(fileHandler);
    logger.setLevel(Level.ALL);

    // コンソールログをファイル出力するための初期化
    this.printStream = new PrintStream(new LogOutputStream(logger));
    System.setOut(this.printStream);
  }

  @Override
  public void close() {
    if (this.printStream != null) {
      this.printStream.close();
    }
  }
}

CustomLogFormatter.java

http://blogs.yahoo.co.jp/dk521123/33205569.html
と同じ。任意。
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;

public class CustomLogFormatter extends Formatter {
  private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

  @Override
  public String format(LogRecord logRecord) {
    final StringBuilder returnValue = new StringBuilder();

    returnValue.append(this.dateFormat.format(new Date(logRecord.getMillis())));
    returnValue.append(" ");

    Level level = logRecord.getLevel();
    if (level == Level.FINEST) {
      returnValue.append("FINEST");
    } else if (level == Level.FINER) {
      returnValue.append("FINER ");
    } else if (level == Level.FINE) {
      returnValue.append("FINE ");
    } else if (level == Level.CONFIG) {
      returnValue.append("CONFIG");
    } else if (level == Level.INFO) {
      returnValue.append("INFO ");
    } else if (level == Level.WARNING) {
      returnValue.append("WARN ");
    } else if (level == Level.SEVERE) {
      returnValue.append("SEVERE");
    } else {
      returnValue.append(Integer.toString(logRecord.getLevel().intValue()));
      returnValue.append(" ");
    }
    returnValue.append(" ");
    returnValue.append(logRecord.getLoggerName());
    returnValue.append(" - ");
    returnValue.append(logRecord.getMessage());
    returnValue.append("\n");

    return returnValue.toString();
  }
}

出力結果「SoapLog0.0.log」

SOAPログが出力できた。ただ、System.out.println()の結果も出力されてしまう...
2017-02-05 18:33:54.120 INFO  Demo - ---[HTTP request - http://localhost:8080/SampleWebService/services/SampleWebService.ws]---
2017-02-05 18:33:54.128 INFO  Demo - Accept: text/xml, multipart/related
2017-02-05 18:33:54.129 INFO  Demo - Content-Type: text/xml; charset=utf-8
2017-02-05 18:33:54.129 INFO  Demo - SOAPAction: "http://webservice.sample.com/SampleWebService/sayYourAgeRequest"
2017-02-05 18:33:54.130 INFO  Demo - User-Agent: JAX-WS RI 2.2.9-b130926.1035 svn-revision#8c29a9a53251ff741fca1664a8221dc876b2eac8
2017-02-05 18:33:54.131 INFO  Demo - <?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> xmlns:ns2="Ken11--------------------">http://webservice.sample.com/">Ken11--------------------
2017-02-05 18:33:54.132 INFO  Demo - 
2017-02-05 18:33:54.136 INFO  Demo - ---[HTTP response - http://localhost:8080/SampleWebService/services/SampleWebService.ws - 200]---
2017-02-05 18:33:54.137 INFO  Demo - null: HTTP/1.1 200
2017-02-05 18:33:54.138 INFO  Demo - Content-Type: text/xml;charset=utf-8
2017-02-05 18:33:54.139 INFO  Demo - Date: Sun, 05 Feb 2017 09:33:53 GMT
2017-02-05 18:33:54.139 INFO  Demo - Transfer-Encoding: chunked
2017-02-05 18:33:54.140 INFO  Demo - <?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> xmlns:ns2="Ken's">http://webservice.sample.com/">Ken's age is 11.</return></ns2:sayYourAgeResponse></S:Body></S:Envelope>--------------------
2017-02-05 18:33:54.140 INFO  Demo - 
2017-02-05 18:33:54.144 INFO  Demo - 45ms
2017-02-05 18:33:54.145 INFO  Demo - Result : Ken's age is 11.



関連記事

Javaアプリにおける SSL通信時のデバッグ方法

http://blogs.yahoo.co.jp/dk521123/35261371.html

【JAX-WS】 Webサービス / Metro [7] ~ SOAPログを出力する ~

http://blogs.yahoo.co.jp/dk521123/36522384.html

標準 java.util.logging を使ったログ機能 ~ログフォーマットしてテキスト形式でログファイル出力するには~

http://blogs.yahoo.co.jp/dk521123/33205569.html