出力を入力へ

プログラミングに関する基本的な事を中心にまとめます

実行環境に応じてログの動作を切り替える

ローカル環境では標準出力(または標準エラー出力)にデバッグプリント文を出力し、
リモート環境ではなにもして欲しくない。
これをすべて自動で実現させるための方法についてまとめておく。

具体的には、プログラミングコンテストデバッグコードの除去ミスがあったので
同じミスを二度と起こさないようにするための方法。

単純な方法(ただし手作業あり)

一番簡単なのは、デバッグモードを表す変数を準備しておくこと。
ローカルではデバッグモードを有効にしてデバッグプリント文を有効にしておき、
リモートにソースコードを提出する際には変数を切り替えておく。

簡単な実装例は以下の通り

boolean DEBUG = true;
public void debugPrint(Object obj) {
    if(DEBUG) System.out.print(obj);
}

簡単だけど、

  • ソースコード提出時に変数DEBUGをfalseにセットする必要がある
  • printメソッドしか対応していない(printf, printlnなどが利用できない)

といったデメリットが発生する(特に焦ってると変数の書き換えを忘れる)。

自動化する方法

方針としては、以下の通り。
変数の書き換えが面倒なのでローカル/リモートを自動判定させる。
また、デバッグプリントにはPrintStreamを利用する。

環境の自動判定にはSystem.getProperty()を利用する。
取得するプロパティ値には、"user.dir"を利用した。
他にもいろいろあるけど、この値が偶然一致することはないと思ったので。
実装例は以下の通り

private static PrintStream debug;
private static boolean DEBUG = true;
static {
    if (System.getProperty("user.dir").toString().equals(<ローカルディレクトリ名>) && DEBUG) {
        debug = System.out;
    } else {
        debug = new PrintStream(new OutputStream() {
            @Override
            public void write(int b) {}
        });
    }
}

このあたりの実装は過去のデバッグプリントの通り。
Javaにおけるデバッグプリントの実装 - 出力を入力へ

あとは上記の<ローカルディレクトリ名>に固有の値を入れておけば、
固有情報が一致するローカル環境でのみデバッグ文が有効になる。
もちろん、ローカル環境でデバッグプリントを無効化したい場合は
変数DEBUGにfalseをセットすればよい。

自動化する方法(プロパティ値が取得できない場合)

セキュリティ設定によってはgetProperty()でプロパティ情報を取得できない。
具体的には、Codeforcesで上記コードを実行すると
以下のような例外を投げるため上手くいかない

java.security.AccessControlException: access denied ("java.util.PropertyPermission" "user.dir" "read")

取得できないのであれば、取得できない場合をリモートと判定させる。
実装例は以下の通り

    private static PrintStream debug = null;
    private static boolean DEBUG = true;
    static {
        try {
            if(System.getProperty("user.dir").toString().equals(<ローカルディレクトリ名>) && DEBUG) {
                debug = System.out;
            }
        } catch(Exception e) {
        }
        if (debug == null) {
            debug = new PrintStream(new OutputStream() {
                @Override
                public void write(int b) {}
            });
        }
    }


これでDEBUG変数によらず、リモート環境ではデバッグ文が無効化できる。
加えてPrintStreamの各種メソッドが利用できるので便利。