Tinylog
軽量でシンプルなJavaロギングフレームワーク。最小限の設定で高いパフォーマンスを実現し、小さなフットプリントが特徴。複雑な設定を避けたい開発者やリソース制約のある環境に最適化されている。
GitHub概要
tinylog-org/tinylog
tinylog is a lightweight logging framework for Java, Kotlin, Scala, and Android
スター748
ウォッチ11
フォーク81
作成日:2012年9月13日
言語:Java
ライセンス:Apache License 2.0
トピックス
androidjavajclkotlinkotlin-libraryloggerlogging-libraryscalaslf4jtinylog
スター履歴
データ取得日時: 2025/7/17 23:31
ライブラリ
tinylog
概要
tinylogは「軽量で高速なJava向けロギングフレームワーク」として開発された、最小限の依存関係と優れたパフォーマンスを重視したロギングソリューションです。わずか2つのJARファイル(APIと実装)で構成され、合計サイズは約195KBという超軽量設計を実現。Java、Kotlin、Scala、Android環境で利用可能で、数十万件/秒のログ出力能力を持つ高速処理が特徴。シンプルな設定とスタティックロガーの採用により、複雑な設定やインスタンス生成を必要としない直感的な開発体験を提供します。
詳細
tinylog 2025年版は軽量性とパフォーマンスを追求したJavaロギングフレームワークの最新形態として、企業環境から個人開発まで幅広い用途で採用されています。外部依存関係を一切持たない自己完結型アーキテクチャにより、アプリケーションの起動時間短縮とメモリ使用量最小化を実現。無効化されたログレベルのメソッド呼び出しは完全にno-opとなり、JVMによってランタイム時に除去されるため、本番環境でのパフォーマンスへの影響がほぼゼロ。多様なライター(Console、File、Rolling File、Database、Syslog等)をサポートし、非同期書き込みとバッファリング機能により大量ログ処理にも対応します。
主な特徴
- 超軽量設計: わずか195KBの2つのJARファイル、外部依存なし
- 高速パフォーマンス: 数十万件/秒のログ出力、最適化されたno-op処理
- シンプルAPI: スタティックロガーによるインスタンス不要の簡単な使用法
- 多様なライター: Console、File、Database、Syslog等豊富な出力先
- 非同期処理: 書き込みスレッドとバッファリングによる高速化
- マルチプラットフォーム: Java、Kotlin、Scala、Android、GraalVM対応
メリット・デメリット
メリット
- 最小限の依存関係による軽量性とアプリケーション起動の高速化
- 業界トップクラスのログ出力パフォーマンスと最適化されたメモリ使用量
- 複雑な設定不要のシンプルなプロパティファイル設定
- スタティックロガーによるインスタンス管理不要の開発効率
- 非同期書き込み対応による高負荷環境での安定性
- AndroidやGraalVMネイティブイメージとの優れた互換性
デメリット
- 機能が最小限に絞られており、高度なログ分析機能は限定的
- エコシステムが小さく、サードパーティプラグインが少ない
- 複雑なログフィルタリングやトランスフォーメーション機能の不足
- 大規模エンタープライズ向けの統合管理機能が限定的
- 他の主要ロギングフレームワークと比較してコミュニティが小さい
- レガシーコードからの移行時に既存設定の再構築が必要
参考ページ
書き方の例
インストール・セットアップ
<!-- Maven依存関係 -->
<dependencies>
<!-- tinylog API -->
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-api</artifactId>
<version>2.7.0</version>
</dependency>
<!-- tinylog実装 -->
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-impl</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
// Gradle依存関係
dependencies {
implementation 'org.tinylog:tinylog-api:2.7.0'
implementation 'org.tinylog:tinylog-impl:2.7.0'
}
// Javaでのインポートとバージョン確認
import org.tinylog.Logger;
public class LoggingSetup {
public static void main(String[] args) {
// バージョン情報の確認
Logger.info("tinylog setup completed");
Logger.info("Using tinylog version: {}",
org.tinylog.provider.ProviderRegistry.getLoggingProvider().getClass().getPackage().getImplementationVersion());
}
}
基本的なログ出力
import org.tinylog.Logger;
public class BasicLoggingExample {
public static void main(String[] args) {
// 基本的なログ出力(全レベル)
Logger.trace("トレースレベルのメッセージ - デバッグ詳細情報");
Logger.debug("デバッグレベルのメッセージ - 開発時の詳細情報");
Logger.info("インフォレベルのメッセージ - 一般的な情報");
Logger.warn("警告レベルのメッセージ - 注意が必要な状況");
Logger.error("エラーレベルのメッセージ - エラーが発生");
// パラメータ付きログ出力({}プレースホルダー使用)
String userName = "田中太郎";
int userAge = 30;
Logger.info("ユーザー情報: 名前={}, 年齢={}", userName, userAge);
// 複数パラメータでのログ出力
String product = "ノートPC";
double price = 89800.0;
int quantity = 2;
Logger.info("注文詳細: 商品={}, 価格={}, 数量={}, 合計={}",
product, price, quantity, price * quantity);
// 条件付きログ出力(パフォーマンス最適化)
if (Logger.isDebugEnabled()) {
String expensiveOperation = performExpensiveCalculation();
Logger.debug("計算結果: {}", expensiveOperation);
}
// 例外情報を含むログ出力
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
Logger.error(e, "計算エラーが発生しました: {}", e.getMessage());
Logger.error("スタックトレース付きエラー", e);
}
// 配列やコレクションのログ出力
String[] languages = {"Java", "Kotlin", "Scala"};
Logger.info("サポート言語: {}", (Object) languages);
// 遅延評価によるパフォーマンス最適化
Logger.debug(() -> "重い処理結果: " + performExpensiveCalculation());
}
private static String performExpensiveCalculation() {
// 重い処理のシミュレーション
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "計算完了";
}
}
ログレベル設定
# tinylog.properties - ログレベル設定
# グローバルレベル設定(全ログ出力に適用)
level = info
# パッケージ別レベル設定
[email protected] = debug
[email protected] = warn
[email protected] = error
# 特定クラスのレベル設定
[email protected] = trace
[email protected] = info
# ルートレベル(未設定パッケージのデフォルト)
level@root = warn
# 複数ライターでの異なるレベル設定
writer1 = console
writer1.level = debug
writer1.format = {date: HH:mm:ss.SSS} [{level}] {class-name}: {message}
writer2 = file
writer2.level = warn
writer2.file = logs/warnings.log
writer2.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
// Java設定によるレベル変更
import org.tinylog.configuration.Configuration;
public class LogLevelConfig {
public static void configureLogLevels() {
// プログラムでのレベル設定
Configuration.set("level", "debug");
Configuration.set("[email protected]", "trace");
// 設定の確認
Logger.info("ログレベル設定完了");
Logger.debug("デバッグレベルが有効です");
Logger.trace("トレースレベルが有効です");
// 動的レベル変更
Configuration.set("level", "warn");
Logger.info("このメッセージは表示されません(warnレベル以下のため)");
Logger.warn("このメッセージは表示されます");
}
}
ログフォーマット設定
# tinylog.properties - フォーマット設定
# 基本的なコンソール出力フォーマット
writer = console
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class-name}.{method}() - {message}
# 詳細なフォーマット(スレッド情報含む)
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{thread}] [{level}] {class}:{line} - {message}
# JSON形式でのログ出力
writer.format = {"timestamp":"{date: yyyy-MM-dd'T'HH:mm:ss.SSS}", "level":"{level}", "class":"{class}", "message":"{message}"}
# カスタム色付きフォーマット(コンソール用)
writer.format = {date: HH:mm:ss.SSS} @|bold,{level-color} [{level}]|@ {class-name}: {message}
# ファイル出力用の詳細フォーマット
writer2 = file
writer2.file = logs/application.log
writer2.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{pid}] [{thread}] [{level}] {class}:{line} - {message}{newline}{exception}
# 異なる出力先での異なるフォーマット
# コンソール: シンプル
writer1 = console
writer1.format = [{level}] {class-name}: {message}
# ファイル: 詳細
writer2 = file
writer2.file = logs/detailed.log
writer2.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}.{method}():{line} - {message}{newline}{exception}
# エラーファイル: エラーのみ
writer3 = file
writer3.file = logs/errors.log
writer3.level = error
writer3.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [ERROR] {class}:{line}{newline}Message: {message}{newline}Exception: {exception}
ファイル出力設定
# tinylog.properties - ファイル出力設定
# 基本的なファイル出力
writer = file
writer.file = logs/application.log
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
# ローリングファイル出力(サイズベース)
writer = rolling file
writer.file = logs/app_{count}.log
writer.policies = size: 10MB
writer.backups = 5
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
# ローリングファイル出力(時間ベース)
writer = rolling file
writer.file = logs/app_{date: yyyy-MM-dd}.log
writer.policies = daily: 00:00
writer.backups = 30
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
# 複合条件でのローリング(サイズと時間)
writer = rolling file
writer.file = logs/app_{date: yyyy-MM-dd}_{count}.log
writer.policies = daily: 06:00, size: 50MB
writer.backups = 10
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
# 圧縮付きローリングファイル
writer = rolling file
writer.file = logs/app_{date: yyyy-MM-dd}_{count}.log.gz
writer.policies = daily: 00:00, size: 100MB
writer.backups = 7
writer.compress = gzip
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
# 複数ファイル出力(レベル別)
# 全レベル
writer1 = file
writer1.file = logs/all.log
writer1.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
# エラー専用
writer2 = file
writer2.file = logs/error.log
writer2.level = error
writer2.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [ERROR] {class}:{line} - {message}{newline}{exception}
# 開発用デバッグファイル
writer3 = file
writer3.file = logs/debug.log
writer3.level = debug
writer3.format = {date: HH:mm:ss.SSS} [DEBUG] {class}.{method}():{line} - {message}
# 共有ファイル出力(複数インスタンス)
writer = shared file
writer.file = logs/shared.log
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{pid}] [{level}] {class}: {message}
パフォーマンス最適化
# tinylog.properties - パフォーマンス最適化設定
# 非同期書き込み有効化(高速化)
writingthread = true
# バッファリング有効化(さらなる高速化)
writer = file
writer.file = logs/optimized.log
writer.buffered = true
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
# 非同期 + バッファリング + ローリング
writer = rolling file
writer.file = logs/high-performance_{count}.log
writer.policies = size: 100MB
writer.backups = 5
writer.buffered = true
writingthread = true
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {class}: {message}
# 大量ログ処理用設定
# フィルタリングでログ量を制限
level = warn
[email protected] = error
# バッチ書き込み用設定
writer = file
writer.file = logs/batch.log
writer.buffered = true
writer.autoflush = false # 手動フラッシュ制御
writingthread = true
writer.format = {date: yyyy-MM-dd HH:mm:ss.SSS} [{level}] {message}
# メモリ最適化設定
# 簡素なフォーマットでメモリ使用量削減
writer.format = {date: HH:mm:ss} [{level}] {message}
// Java実装でのパフォーマンス最適化
import org.tinylog.Logger;
import org.tinylog.configuration.Configuration;
public class PerformanceOptimization {
// 高頻度ログ出力のパフォーマンステスト
public static void performanceTest() {
long startTime = System.nanoTime();
// 10万件のログ出力テスト
for (int i = 0; i < 100000; i++) {
Logger.info("ログメッセージ #{}", i);
}
long endTime = System.nanoTime();
double durationMs = (endTime - startTime) / 1_000_000.0;
Logger.info("10万件ログ出力時間: {:.2f}ms", durationMs);
Logger.info("1秒あたりのログ出力数: {:.0f}件/秒", 100000 / (durationMs / 1000));
}
// 条件付きログによる最適化
public static void conditionalLoggingOptimization() {
// パフォーマンス重視の条件付きログ
if (Logger.isTraceEnabled()) {
String expensiveData = generateExpensiveData();
Logger.trace("詳細データ: {}", expensiveData);
}
// ラムダ式による遅延評価(推奨)
Logger.debug(() -> "重い処理結果: " + generateExpensiveData());
// メソッド参照による最適化
Logger.info("ユーザーデータ: {}", () -> getCurrentUser().toString());
}
// メモリ効率的なログ出力
public static void memoryEfficientLogging() {
// 大量データの場合は必要な部分のみログ出力
String[] largeArray = new String[10000];
Logger.debug("配列サイズ: {}", largeArray.length); // 配列全体ではなくサイズのみ
// StringBuilderを避けた効率的な文字列連結
String user = "田中太郎";
int id = 123;
Logger.info("ユーザー処理: user={}, id={}", user, id); // +演算子より効率的
}
// バッチ処理での手動フラッシュ制御
public static void batchProcessingOptimization() {
try {
// autoflush=falseの場合の手動制御
for (int i = 0; i < 1000; i++) {
Logger.info("バッチ処理 #{}", i);
// 100件ごとに手動フラッシュ
if (i % 100 == 0) {
// フラッシュは自動的に処理される(手動制御は限定的)
Logger.info("チェックポイント: {}件処理完了", i);
}
}
} finally {
// 処理完了時の最終フラッシュ
Logger.info("バッチ処理完了");
}
}
private static String generateExpensiveData() {
// 重い処理のシミュレーション
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("data_").append(i).append(",");
}
return sb.toString();
}
private static User getCurrentUser() {
return new User("田中太郎", 30);
}
private static class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return String.format("User{name='%s', age=%d}", name, age);
}
}
}