24

String.format(...)メソッドに似たものが必要ですが、遅延評価が必要です。

この lazyFormat メソッドは、 toString() メソッドがフォーマット パターンを評価するオブジェクトを返す必要があります。

誰かがすでにこれを行っているのではないかと思います。これはどの図書館でも利用できますか?

これを置き換えたい(ロガーはlog4jインスタンスです):

if(logger.isDebugEnabled() ) {
   logger.debug(String.format("some texts %s with patterns %s", object1, object2));
}

これとともに:

logger.debug(lazyFormat("some texts %s with patterns %s", object1, object2));

デバッグロギングが有効になっている場合にのみ、文字列をフォーマットするために lazyFormat が必要です。

4

10 に答える 10

17

最新の log4j 2.X バージョンhttp://logging.apache.org/log4j/2.x/log4j-users-guide.pdfでパラメーター置換を使用して実行できます。

4.1.1.2 パラメータ置換

多くの場合、ロギングの目的は、システムで何が起こっているかに関する情報を提供することです。これには、操作されているオブジェクトに関する情報を含める必要があります。Log4j 1.x では、次のようにして実現できます。

if (logger.isDebugEnabled()) {     
  logger.debug("Logging in user " + user.getName() + " with id " + user.getId()); 
} 

これを繰り返し行うと、コードが目前の実際のタスクよりもロギングに関するものであるかのように感じる効果があります。さらに、ログ レベルが 2 回チェックされることになります。isDebugEnabled の呼び出しで 1 回、debug メソッドで 1 回。より良い代替手段は次のとおりです。

logger.debug("Logging in user {} with id {}", user.getName(), user.getId()); 

上記のコードでは、ロギング レベルは 1 回だけチェックされ、文字列の構築はデバッグ ロギングが有効になっている場合にのみ行われます。

于 2012-12-29T05:16:13.653 に答える
13

効率的なロギングのために遅延連結を探している場合は、Slf4Jを見てください。 これにより、次のように記述できます。

LOGGER.debug("this is my long string {}", fatObject);

文字列の連結は、デバッグ レベルが設定されている場合にのみ行われます。

于 2009-06-03T06:40:07.357 に答える
5

重要な注意:すべてのロギング コードをSLF4J (特に log4j 1.x) を使用するように移動することを強くお勧めします。これは、特定のロギングの実装に関するあらゆる種類の特異な問題 (つまりバグ) に悩まされるのを防ぎます。よく知られているバックエンドの実装の問題に対する「修正」があるだけでなく、長年にわたって出現してきた新しい高速な実装でも機能します。


あなたの質問への直接の回答として、 SLF4Jを使用すると次のようになります。

LOGGER.debug("some texts {} with patterns {}", object1, object2);

あなたが提供したものの最も重要な部分は、2 つの Object インスタンスを渡しているという事実です。object1.toString()メソッドとメソッドはobject2.toString()すぐには評価されません。さらに重要なことは、toString()メソッドが返すデータが実際に使用される場合にのみメソッドが評価されることです。つまり、遅延評価の本当の意味です。

大量のクラスでオーバーライドする必要のない、使用できるより一般的なパターンを考えてみましたtoString()(オーバーライドを行うためのアクセス権がないクラスもあります)。私は簡単なドロップインプレース ソリューションを思いつきました。繰り返しますが、 SLF4Jを使用して、レベルのロギングが有効になっている場合にのみ文字列を作成します。これが私のコードです:

    class SimpleSfl4jLazyStringEvaluation {
      private static final Logger LOGGER = LoggerFactory.getLogger(SimpleSfl4jLazyStringEvaluation.class);

      ...

      public void someCodeSomewhereInTheClass() {
//all the code between here
        LOGGER.debug(
            "{}"
          , new Object() {
              @Override
              public String toString() {
                return "someExpensiveInternalState=" + getSomeExpensiveInternalState();
              }
            }
//and here can be turned into a one liner
        );
      }

      private String getSomeExpensiveInternalState() {
        //do expensive string generation/concatenation here
      }
    }

そして、ワンライナーに単純化するために、 someCodeSomewhereInTheClass() の LOGGER 行を次のように短縮できます。

LOGGER.debug("{}", new Object(){@Override public String toString(){return "someExpensiveInternalState=" + getSomeExpensiveInternalState();}});

この単純なモデルに従うように、すべてのロギング コードをリファクタリングしました。それは物事をかなり整理しました。そして、これを使用していないロギング コードを見つけた場合は、まだ必要であっても、この新しいパターンを使用するようにロギング コードをリファクタリングします。そうすれば、後で「高価な」操作を追加する必要がある変更が行われた場合、インフラストラクチャのボイラープレートが既に存在し、操作を追加するだけでタスクが簡素化されます。

于 2013-08-19T15:33:01.163 に答える
3

アンドレアスの答えに基づいて、次の場合にのみフォーマットを実行するという問題に対するいくつかのアプローチを考えることができLogger.isDebugEnabledますtrue

オプション1:「フォーマットを行う」フラグを渡す

1つのオプションは、実際にフォーマットを実行するかどうかを指示するメソッド引数を持つことです。ユースケースは次のとおりです。

System.out.println(lazyFormat(true, "Hello, %s.", "Bob"));
System.out.println(lazyFormat(false, "Hello, %s.", "Dave"));

出力は次のようになります。

Hello, Bob.
null

のコードlazyFormatは次のとおりです。

private String lazyFormat(boolean format, final String s, final Object... o) {
  if (format) {
    return String.format(s, o);
  }
  else {
    return null;
  }
}

この場合、フラグがに設定されている場合String.formatにのみ実行され、formatフラグが設定されtrueている場合は。falseを返しますnull。これにより、ログメッセージのフォーマットが停止し、「ダミー」情報が送信されます。

したがって、ロガーのユースケースは次のようになります。

logger.debug(lazyFormat(logger.isDebugEnabled(), "Message: %s", someValue));

この方法は、質問で求められているフォーマットに正確には適合しません。

オプション2:ロガーを確認する

別のアプローチは、ロガーに直接尋ねることisDebugEnabledです。

private static String lazyFormat(final String s, final Object... o) {
  if (logger.isDebugEnabled()) {
    return String.format(s, o);
  }
  else {
    return null;
  }
}

このアプローチではlogger、メソッドに表示されることが期待されlazyFormatます。また、このアプローチの利点は、呼び出しisDebugEnabled時に呼び出し元がメソッドをチェックする必要がないlazyFormatことです。そのため、通常の使用法は次のとおりです。

logger.debug(lazyFormat("Debug message is %s", someMessage));
于 2009-06-03T07:24:00.717 に答える
2

Log4j 1.2.16 で導入されたのは、これを行う 2 つのクラスです。

org.apache.log4j.LogMFjava.text.MessageFormatメッセージのフォーマットを使用org.apache.log4j.LogSFし、「SLF4Jパターン構文」を使用し、より高速であると言われています。

以下に例を示します。

LogSF.debug(log, "Processing request {}", req);

 LogMF.debug(logger, "The {0} jumped over the moon {1} times", "cow", 5); 
于 2014-02-23T14:08:56.413 に答える
1

または、次のように書くこともできます

debug(logger, "some texts %s with patterns %s", object1, object2);

public static void debug(Logger logger, String format, Object... args) {
    if(logger.isDebugEnabled()) 
       logger.debug(String.format("some texts %s with patterns %s", args));
}
于 2009-06-03T20:59:48.727 に答える
0

必要な場合にのみ呼び出すためにラッパーを定義できString.format()ます。

詳細なコード例については、この質問を参照してください。

アンドレアスの回答で示唆されているように、同じ質問には可変個引数関数の例もあります。

于 2009-06-03T06:47:34.830 に答える