2017-05-30 4 views
0

個人的なJavaプロジェクトで作業するとき、コンソールにテキストをうまくロギングする方法があります。私は一般に、このために静的な静的なクラスをいくつか作成し、接頭辞を処理してメッセージにタイムスタンプを適用するので、System.out.println( "Text")の使用を省略できます。 。デフォルトのJavaライブラリを使用してコンソール出力をタイムスタンプする適切な方法はありますか?

これは、私はしばらく前に書いたクラスがあると私は本当に方法のように、それはテキストフォーマットので、別のプロジェクトでそれを再利用する傾向がある:予想通り

import java.text.SimpleDateFormat; 
import java.util.Date; 

public class Log { 

    public static final int LEVEL_INFO = 0; 
    public static final int LEVEL_WARNING = 1; 
    public static final int LEVEL_ERROR = 2; 

    private static SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); 
    /** 
    * Used instead of System.out.println for consistent formatting. 
    * 
    * @param messageToPrefix Message that you want to send to print. 
    * @param errorLevel Type of message you want to send. 
    */ 
    public static void print(String messageToPrefix, int errorLevel) { 
     StringBuilder message = new StringBuilder(); 
     message.append("[").append(df.format(new Date())).append("] "); 
     switch(errorLevel) { 
      case LEVEL_INFO: 
       message.append("[Info] "); 
       break; 
      case LEVEL_WARNING: 
       message.append("[Warning] "); 
       break; 
      case LEVEL_ERROR: 
       message.append("[Error] "); 
       break; 
     } 
     message.append(messageToPrefix); 
     System.out.println(message.toString()); 
    } 
} 

これは、すべての作品ですが、そこにあります私はもう少し前に気付いた小さな問題:タイムスタンプを作成するこの方法は非常にリソース集約的です!これを呼び出すには、タイムスタンプが作成されてコンソールに書き込まれるまで、ログに記録するコードが停止する必要があります。これはちょうど私にとっては非効率的なように思えます(ここでは数ミリ秒ということもあります)。私は私がにSystem.currentTimeMillisを使用したもの(この伐採方法の実行時間を比較したとき)、この結論に達しました素敵なタイムスタンプにそれをフォーマットしないが、このように使用する場合は、MSにおけるランタイムを示しています

public class Log { 

    private static final long startTime = System.currentTimeMillis(); 

    public static final int LOG_LEVEL_INFO = 0; 
    public static final int LOG_LEVEL_WARNING = 1; 
    public static final int LOG_LEVEL_ERROR = 2; 
    public static final int LOG_LEVEL_UNKNOWN = 3; 

    /** 
    * Used instead of System.out.println for consistent formatting. 
    * 
    * @param msg Message that you want to send to log. 
    * @param importance How important is the message? 
    */ 
    public static void print(String msg, int importance) { 
     StringBuilder finalMsg = new StringBuilder(); 
     finalMsg.append("[").append(System.currentTimeMillis() - startTime).append(" ms] "); 
     switch (importance) { 
      case 0: 
       finalMsg.append("[INFO] "); 
       break; 
      case 1: 
       finalMsg.append("[WARNING] "); 
       break; 
      case 2: 
       finalMsg.append("[ERROR] "); 
       break; 
      default: 
       finalMsg.append("[UNKNOWN] "); 
       break; 
     } 
     finalMsg.append(msg); 
     System.out.println(finalMsg); 
    } 
} 

この方法は、約50メッセージを超えるような小規模でさえも、より速い方法であることが判明しました。ランニングタイムは50秒です。

これは私にいくつかの質問について考えさせました: このようなタイムスタンプを作成するためのよりよい方法がありますか? ロギングコードが完了するのを待たない方法はありますか? このスレッドを開始するとよいでしょうか? まったく間違ったトラックにいますか?

私は、これを小さくしてシンプルにするために余分なライブラリを使用しません。

アドバイスをいただければ幸いです!

+2

ロギングライブラリを使用します。組み込みの['java.util.logging'](https://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html#package.description)また、 JULと呼ばれる。 – Andreas

+0

別の注記:[静的SimpleDateFormatで注意してください](https://stackoverflow.com/questions/4021151/java-dateformat-is-not-threadsafe-what-does-this-leads-to)。これを修正すると、処理時間がさらに長くなる可能性があります。 – Marvin

+0

@Andreas私は参照してください。正直なところ私はその存在を知らなかった。私はそれを試してみる、ありがとう。 –

答えて

0

編集:これは、(これはいくつかのアドバイスをした後で)これはログとタイムスタンプメッセージを安全に送信する方法だと思います。それは最速の方法ではないかもしれませんが、使用するのが安全で、私が望む結果を私に提供します。

import java.text.SimpleDateFormat; 
import java.util.Date; 

    public class Log { 

     public static final int LEVEL_INFO = 0; 
     public static final int LEVEL_WARNING = 1; 
     public static final int LEVEL_ERROR = 2; 

     private static final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss")); 

     /** 
     * Used instead of System.out.println for consistent formatting. 
     * 
     * @param messageToPrefix Message that you want to send to print. 
     * @param errorLevel Type of message you want to send. 
     */ 
     public static void print(String messageToPrefix, int errorLevel) { 
      StringBuilder message = new StringBuilder(); 
      message.append("[").append(formatter.get().format(new Date())).append("] "); 
      switch(errorLevel) { 
       case LEVEL_INFO: 
        message.append("[Info] "); 
        break; 
       case LEVEL_WARNING: 
        message.append("[Warning] "); 
        break; 
       case LEVEL_ERROR: 
        message.append("[Error] "); 
        break; 
      } 
      message.append(messageToPrefix); 
      System.out.println(message.toString()); 
     } 
    } 

私は彼らに与えられたすべてのアドバイスのコメントに人々に感謝したいと思います。

+0

スレッドセーフは、複数のスレッドが状態にアクセスする並行環境でアプリケーションを実行する場合にのみ重要です。これが真でない場合、ロックするとプログラムが遅くなります。この理由から(StringBufferなど)、スレッドセーフなクラス(StringBufferなど)が再実装されました。そして、いくつかのスレッドセーフなクラス、例えば。 BigIntegerには、特定のパフォーマンスシナリオで使用する可変コンパニオンクラス(BitSet)が付属しています。 – scottb

+0

あなたのクラスは、変更可能なSimpleDateFormatを除いて、とにかくスレッドセーフであると思われます。オブジェクトが不変(したがって常にスレッドセーフである)のJava Date-Timeライブラリの対応するクラスを使用すると、プログラムはロックを必要とせずにスレッドセーフな状態を維持できます。 – scottb

+0

scottbと同意します。可能であれば、Java Date-Timeライブラリに行き、古くなったクラップを削除してください。そして、バックポートがあるので、Java 8がなくても可能です。 +++スレッドが安全でない部分を扱うときは、 'ThreadLocal'の使用を検討してください。 +++フォーマットされた文字列とともに最後のミリ秒を単一要素のキャッシュとして保存することを検討してください。これは、 '' java.time'が大きく最適化されているとは思うが、現代の図書館でも役に立ちます。 – maaartinus

関連する問題