401

人生で初めて、オープンソース化される Java API を作成する立場にいることに気づきました。他の多くのプロジェクトに含まれることを願っています。

ロギングについては、私 (そして実際に私が一緒に働いている人々) は常に JUL ( java.util.logging) を使用しており、問題が発生したことはありません。ただし、API 開発のために何をすべきかをより詳細に理解する必要があります。私はこれについていくつかの調査を行いましたが、私が得た情報では、さらに混乱するだけです. したがって、この投稿。

私はJUL出身なので、それに偏っています。残りの私の知識はそれほど大きくありません。

私が行った調査から、人々が JUL を好まない理由を次のように思いつきました。

  1. 「私は、Sun が JUL をリリースするずっと前に Java で開発を始めました。新しいことを学ぶよりも、logging-framework-X を使い続ける方が簡単でした」 . うーん。冗談ではありません、これは実際に人々が言うことです。この議論により、私たちは皆 COBOL を行っている可能性があります。(しかし、私はこれが怠惰な男であることを確かに関連付けることができます)

  2. 「JUL のロギング レベルの名前が気に入らない」 . わかりました、真剣に、これは新しい依存関係を導入する理由として十分ではありません.

  3. 「JUL からの出力の標準フォーマットが気に入らない」 . うーん。これは単なる構成です。コードに関して何もする必要さえありません。(確かに、昔は独自の Formatter クラスを作成して正しく処理する必要があったかもしれません)。

  4. 「logging-framework-X も使用する他のライブラリを使用しているので、そちらを使用する方が簡単だと思いました」 . これは循環的な議論ですね。「全員」がJULではなくlogging-framework-Xを使用するのはなぜですか?

  5. 「他の誰もが logging-framework-X を使用しています」 . 私にとってこれは、上記の特殊なケースです。多数派が常に正しいとは限りません。

では、本当の大きな疑問は、なぜ JULではないのかということです。. 私が逃したのは何ですか?ロギング ファサード (SLF4J、JCL) の存在理由は、複数のロギング実装が歴史的に存在してきたことであり、その理由は実際には JUL の前の時代にまでさかのぼります。JUL が完璧だったら、ロギング ファサードは存在しないでしょう。さらに紛らわしいのは、JUL 自体がある程度ファサードであり、ハンドラー、フォーマッター、さらには LogManager を交換できるようにすることです。

同じことを行う複数の方法 (ロギング) を受け入れるのではなく、そもそもなぜそれらが必要だったのか疑問に思うべきではありませんか? (そして、それらの理由がまだ存在するかどうかを確認してください)

わかりました、これまでの私の調査では、JULの実際の問題である可能性があることがわかりました。

  1. パフォーマンス。SLF4J のパフォーマンスは他よりも優れていると言う人もいます。これは時期尚早の最適化のケースのように私には思えます。1 秒あたり数百メガバイトをログに記録する必要がある場合、とにかく正しい道を進んでいるかどうかはわかりません。JUL も進化しており、Java 1.4 で行ったテストは正しくない可能性があります。ここでそれについて読むことができ、この修正は Java 7 に組み込まれました。多くの人は、ロギング メソッドでの文字列連結のオーバーヘッドについても話します。ただし、テンプレート ベースのロギングはこのコストを回避し、JUL にも存在します。個人的には、テンプレートベースのロギングを実際に書くことはありません。あまりにも怠惰です。たとえば、JUL でこれを行う場合:

     log.finest("Lookup request from username=" + username 
        + ", valueX=" + valueX
        + ", valueY=" + valueY));
    

    私のIDEは私に警告し、それを次のように変更する許可を求めます:

     log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", 
        new Object[]{username, valueX, valueY});
    

    ..もちろん承ります。許可が与えられました! ご協力ありがとうございました。

    そのため、私は実際にそのようなステートメントを自分で作成するのではなく、IDE によって作成されます。

    パフォーマンスの問題に関する結論として、競合他社と比較して JUL のパフォーマンスが良くないことを示唆するものは何も見つかりませんでした。

  2. classpath からの構成。デフォルトの JUL は、クラスパスから構成ファイルをロードできません。そうするのは数行のコードです。これが煩わしい理由はわかりますが、解決策は短くて簡単です。

  3. 出力ハンドラの可用性。JUL には、すぐに使用できる 5 つの出力ハンドラー (コンソール、ファイル ストリーム、ソケット、およびメモリ) が付属しています。これらは拡張することも、新しいものを作成することもできます。これは、たとえば、UNIX/Linux Syslog および Windows イベント ログへの書き込みである可能性があります。私は個人的にこの要件を持ったことはなく、使用されているのを見たこともありませんが、それが便利な機能である理由は確かに理解できます. Logback には、たとえば Syslog 用のアペンダーが付属しています。それでも私はそれを主張します

    1. 出力先のニーズの 99.5% は、JUL のすぐに使えるものでカバーされます。
    2. 特別なニーズは、他の何かの上ではなく、JUL の上にあるカスタム ハンドラーによって満たされる可能性があります。JUL の Syslog 出力ハンドラーを作成するのに、別のロギング フレームワークの場合よりも時間がかかることを示唆するものは何もありません。

何か見落としがあるのではないかと、とても心配です。JUL 以外のロギング ファサードとロギング実装の使用は非常に広まっているため、理解していないのは私だけだという結論に達する必要があります。恐れながら、それは初めてではないでしょう。:-)

では、API をどうすればよいでしょうか? 成功させたいです。もちろん、「流れに乗って」SLF4J(最近最も人気があるようです)を実装することもできますが、私自身のために、すべての混乱を正当化する今日のJULの何が問題なのかを正確に理解する必要がありますか?ライブラリに JUL を選択することで、自分自身を妨害することになりますか?

テストのパフォーマンス

(2012 年 7 月 7 日に nolan600 によって追加されたセクション)

SLF4J のパラメータ化が JUL の 10 倍以上高速であることについて、以下の Ceki からの参照があります。だから私はいくつかの簡単なテストを始めました。一見すると、その主張は確かに正しい。暫定的な結果は次のとおりです (ただし、読み進めてください!)。

  • 実行時間 SLF4J、バックエンド Logback: 1515
  • 実行時間 SLF4J、バックエンド JUL: 12938
  • 実行時間 JUL: 16911

上記の数値はミリ秒であるため、少ないほど良いです。したがって、10 倍のパフォーマンスの違いは、最初は実際にはかなり近いものです。私の最初の反応:それはたくさんあります!

ここがテストの核心です。ご覧のとおり、整数と文字列はループで構成され、ログ ステートメントで使用されます。

    for (int i = 0; i < noOfExecutions; i++) {
        for (char x=32; x<88; x++) {
            String someString = Character.toString(x);
            // here we log 
        }
    }

(ログ ステートメントにプリミティブ データ型 (この場合は int) とより複雑なデータ型 (この場合は String) の両方を持たせたいと思いました。それが重要かどうかはわかりませんが、それはあります。)

SLF4J のログ ステートメント:

logger.info("Logging {} and {} ", i, someString);

JUL のログ ステートメント:

logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});

JVM は、実際の測定が行われる前に 1 回実行された同じテストで「ウォームアップ」されました。Windows 7 では Java 1.7.03 を使用しました。最新バージョンの SLF4J (v1.6.6) と Logback (v1.0.6) を使用しました。stdout と stderr が null デバイスにリダイレクトされました。

ただし、注意してください。JUL はgetSourceClassName()デフォルトで出力にソース クラス名を出力しますが、Logback は出力しないため、JUL がほとんどの時間を費やしていることがわかりました。そこで、リンゴとオレンジを比較しています。テストを再度実行し、ロギングの実装を同様の方法で構成して、実際に同じものが出力されるようにする必要があります。ただし、SLF4J+Logback は依然として上位にあると思われますが、上記の初期の数値にはほど遠いものです。乞うご期待。

ところで: このテストは、私が実際に SLF4J または Logback を使用したのは初めてでした。楽しい経験。あなたが始めたばかりのとき、JULは確かにあまり歓迎されません。

パフォーマンスのテスト (パート 2)

(2012 年 7 月 8 日に nolan600 によって追加されたセクション)

結局のところ、JUL でパターンをどのように構成するか、つまり、ソース名が含まれているかどうかはパフォーマンスにとって重要ではありません。私は非常に単純なパターンで試しました:

java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"

それは上記のタイミングをまったく変更しませんでした。getSourceClassName()私のプロファイラーは、これが私のパターンの一部ではなかったとしても、ロガーが への呼び出しに多くの時間を費やしていることを明らかにしました。柄は問いません。

したがって、パフォーマンスの問題について、少なくともテスト済みのテンプレート ベースのログ ステートメントでは、JUL (遅い) と SLF4J+Logback (速い) の実際のパフォーマンスの差は約 10 倍あると結論付けています。ちきさんのおっしゃる通りです。

getLogger()また、SLF4J の呼び出しは JUL の同上よりもはるかに高価であるという別のこともわかります。(プロファイラーが正確な場合は 95 ミリ秒対 0.3 ミリ秒)。意味あり。SLF4J は、基礎となるロギング実装のバインドにしばらく時間がかかります。これは私を怖がらせません。これらの呼び出しは、アプリケーションの存続期間中はほとんど発生しません。堅牢性は、実際のログ呼び出しに含まれている必要があります。

最終的な結論

(2012 年 7 月 8 日に nolan600 によって追加されたセクション)

ご回答ありがとうございます。私が当初考えていたこととは反対に、API に SLF4J を使用することにしました。これは、多くのこととあなたの入力に基づいています。

  1. デプロイ時にログの実装を柔軟に選択できます。

  2. アプリケーション サーバー内で実行する場合の JUL の構成の柔軟性の欠如に関する問題。

  3. SLF4J は、上で詳述したように、特に Logback と組み合わせると、確かにはるかに高速です。これが単なる大まかなテストであったとしても、JUL よりも SLF4J+Logback の最適化に多くの労力が費やされたと信じる理由があります。

  4. ドキュメンテーション。SLF4J のドキュメントは、より包括的で正確です。

  5. パターンの柔軟性。テストを行ったとき、JUL が Logback のデフォルト パターンを模倣するように設定しました。このパターンには、スレッドの名前が含まれます。JUL はそのままではこれを行うことができないことがわかりました。わかりました、今まで見逃したことはありませんが、ログ フレームワークに欠けているべきものではないと思います。限目!

  6. 現在、ほとんどの (または多くの) Java プロジェクトは Maven を使用しているため、依存関係を追加することはそれほど大きなことではありません。これは SLF4J にも当てはまるようです。また、SLF4J jar とその仲間はサイズが小さいです。

奇妙なことに、SLF4J で少し作業した後、実際に JUL に腹を立てました。JULもこうじゃなきゃいけないのが今でも悔やまれます。JUL は完璧にはほど遠いですが、ある程度は機能します。十分ではありません。例として同じことが言えPropertiesますが、抽象化については考えていません。そのため、人々は独自の構成ライブラリと何を持っているかをプラグインできます。その理由は、バーのすぐ上に来るのに対し、今日の JUL にはその逆が当てはまるためだと思いPropertiesます...そして過去には存在しなかったため、ゼロになりました。

4

5 に答える 5

240

免責事項: 私は log4j、SLF4J、および logback プロジェクトの創設者です。

SLF4J を好む客観的な理由があります。1 つは、SLF4J を使用すると、エンド ユーザーが基礎となるロギング フレームワークを自由に選択できるようになります。さらに、知識の豊富なユーザーは、log4j を超える機能を提供する logbackを好む傾向があり、jul は大きく遅れをとっています。一部のユーザーにとっては機能的に jul で十分かもしれませんが、他の多くのユーザーにとってはそうではありません。簡単に言えば、ロギングが重要な場合は、基礎となる実装として logback を使用して SLF4J を使用することをお勧めします。ロギングが重要でない場合は、jul で問題ありません。

ただし、oss 開発者は、自分の好みだけでなく、ユーザーの好みも考慮する必要があります。したがって、SLF4J が jul よりも優れていると確信しているからではなく、現在 (2012 年 7 月) ほとんどの Java 開発者がロギング API として SLF4J を好むため、SLF4J採用する必要があります。最終的に世論を気にしないことにした場合は、次の事実を考慮してください。

  1. jul は JDK にバンドルされているため、jul を好む人は便宜上そうしています。私の知る限り、7月を支持する客観的な議論は他にありません
  2. あなた自身の jul の好みはまさにそれです。

したがって、世論よりも「確固たる事実」を保持することは、一見勇気があるように見えますが、この場合は論理的な誤りです。

それでも納得できない場合は、JB Nizetが追加の有力な議論を行います。

ただし、エンド ユーザーは、自分のコード、または log4j または logback を使用する別のライブラリに対して、このカスタマイズを既に行っている可能性があります。jul は拡張可能ですが、4 つの異なるロギング フレームワークを使用する 4 つのライブラリを使用するため、logback、jul、log4j、および神のみが他のどのロギング フレームワークを拡張する必要があるかを知っています。SLF4J を使用することで、あなたが選択したものではなく、彼が望むロギング フレームワークを構成できるようになります。一般的なプロジェクトでは、自分のライブラリだけでなく、無数のライブラリが使用されることに注意してください

なんらかの理由で SLF4J API が嫌いで、それを使用すると仕事の楽しさがなくなる場合は、ぜひ jul を使用してください。 結局、jul を SLF4J にリダイレクトする手段があります。

ところで、jul のパラメータ化は SLF4J のものよりも少なくとも 10 倍遅く、最終的に顕著な違いが生じます。

于 2012-07-06T10:32:52.240 に答える
37
  1. java.util.loggingJava 1.4 で導入されました。その前にロギングの用途がありました。そのため、他にも多くのロギング API が存在します。これらの API は Java 1.4 より前に頻繁に使用されていたため、1.4 がリリースされたときにゼロに落ちただけでなく、大きな市場シェアを獲得しました。

  2. JUL は最初からそれほど素晴らしいものではありませんでした。あなたが言及したことの多くは、1.4 ではかなり悪化し、1.5 では改善されただけです (6 でも同様だと思いますが、よくわかりません)。

  3. JUL は、同じ JVM 内で構成が異なる複数のアプリケーションにはあまり適していません (相互作用しない複数の Web アプリケーションを考えてみてください)。Tomcat は、それを機能させるためにいくつかのフープをジャンプする必要があります (正しく理解していれば、効果的に JUL を再実装します)。

  4. ライブラリが使用するロギング フレームワークに常に影響を与えることはできません。したがって、SLF4J (実際には他のライブラリの上の非常に薄い API レイヤーにすぎません) を使用すると、ロギングの世界全体のある程度一貫した全体像を維持するのに役立ちます (したがって、同じシステムでライブラリのロギングを行いながら、基礎となるロギング フレームワークを決定できます)。

  5. ライブラリは簡単には変更できません。以前のバージョンのライブラリが logging-library-X を使用していた場合、logging-library-Y (JUL など) に簡単に切り替えることはできません (後者が明らかに優れている場合でも)。そのライブラリのユーザーは、新しいロギング フレームワークを学習し、(少なくとも) ロギングを再構成する必要があります。特に、ほとんどの人に明らかな利益をもたらさない場合はなおさらです。

JUL は、少なくとも最近の他のロギング フレームワークの有効な代替手段であると思います。

于 2012-07-06T09:17:24.877 に答える
32

私見ですが、slf4j のようなロギング ファサードを使用する主な利点は、エンド ユーザーに選択を押し付けるのではなく、ライブラリのエンド ユーザーが必要とする具体的なロギング実装を選択できるようにすることです。

おそらく、彼は Log4j または LogBack (特別なフォーマッター、アペンダーなど) に時間とお金を投資しており、jul を構成するよりも Log4j または LogBack を使い続けることを好みます。問題ありません。slf4j ではそれが可能です。7月にLog4jを使用するのは賢明な選択ですか? 多分そうでないかもしれません。しかし、あなたは気にしません。エンド ユーザーが好みのものを選択できるようにします。

于 2012-07-06T09:19:45.833 に答える
9

私は、あなたが思うように、すぐに始めるのが最も簡単だったので、JULを使い始めました。しかし、何年にもわたって、私はもう少し時間をかけて選択したいと思うようになりました。

私の主な問題は、多くのアプリケーションで使用されている「ライブラリ」コードが大量にあり、それらすべてがJULを使用していることです。Webサービスタイプのアプリでこれらのツールを使用すると、ログが消えたり、予測できない場所や奇妙な場所に移動したりします。

私たちの解決策は、ライブラリコードにファサードを追加することでした。つまり、ライブラリログの呼び出しは変更されませんでしたが、使用可能なログメカニズムに動的にリダイレクトされました。POJOツールに含まれている場合はJULに転送されますが、Webアプリとしてデプロイされている場合はLogBackにリダイレクトされます。

残念ながら、ライブラリコードはパラメータ化されたロギングを使用していませんが、必要に応じて後付けすることができます。

slf4jを使用してファサードを構築しました。

于 2012-07-06T13:42:03.260 に答える