Klogging

純Kotlinで構築されたスタンドアロンロギングライブラリ。Kotlinコルーチンとの深い統合により、構造化ログイベントをデフォルトでサポート。非同期イベント配信とコンテキスト情報の自動取得機能を提供。

ロギングライブラリKotlinコルーチン構造化ログ非同期Kotlinネイティブ

ライブラリ

Klogging

概要

Kloggingは、純Kotlinで構築されたスタンドアロンロギングライブラリとして、「Kotlinイディオムによる簡単で強力なロギング」を提供し、Kotlinコルーチンとの深い統合により現代的なKotlin開発ニーズに対応しています。構造化ログイベントをデフォルトでサポートし、非同期イベント配信とコンテキスト情報の自動取得機能により、マイクロサービスと非同期処理が重要な環境での高パフォーマンスログ管理を実現。従来のJavaロギングフレームワークを超越したKotlinファーストなロギングソリューションです。

詳細

Kloggingは2025年のコルーチンベースKotlinアプリケーションで注目度が高まっている次世代ロギングライブラリです。コルーチンスコープでの情報保存と自動コンテキスト管理、マイクロ秒レベルの高精度タイムスタンプ、JDKプラットフォームロギングの実装など、現代的な分散システム要件に対応した機能を搭載。Spring Bootとの優れた統合性により、サーバーサイドKotlin開発での構造化ログとトレーサビリティを大幅に向上させ、従来のSLF4J+Logbackアプローチを補完・発展させる重要な位置付けにあります。

主な特徴

  • コルーチンネイティブ: Kotlinコルーチンとの深い統合と自動コンテキスト管理
  • 構造化ログデフォルト: メッセージテンプレートによる構造化イベント自動生成
  • 非同期イベント配信: 高パフォーマンスな非同期ログ処理機能
  • 高精度タイムスタンプ: マイクロ秒からナノ秒レベルの精密時刻記録
  • Kotlinファースト: 純Kotlin実装による最適化されたAPI設計
  • Spring Boot統合: 企業レベルでの導入を支援する統合機能

メリット・デメリット

メリット

  • Kotlinコルーチンとの統合によりコンテキスト管理が自動化
  • 構造化ログがデフォルトで現代的なログ解析・監視環境に適応
  • 非同期処理により高負荷環境でのパフォーマンス向上を実現
  • 純Kotlin実装でKotlinイディオムに完全準拠した自然なAPI
  • マイクロサービス環境でのトレーサビリティと分散ログ管理に優位性
  • Spring Bootとの統合により企業レベル開発での採用容易性

デメリット

  • Kotlinエコシステムに特化しており他言語との互換性は限定的
  • 比較的新しいライブラリで成熟度とコミュニティサイズがSLF4Jより小規模
  • 従来JavaロギングとのAPI互換性がなく移行時の学習コストが存在
  • 高度な機能が多く小規模プロジェクトではオーバーエンジニアリングの可能性
  • デバッグやトラブルシューティング情報が従来ライブラリより少ない
  • 企業環境での実績がまだ限定的で保守的な組織での採用ハードルが高い

参考ページ

書き方の例

インストールと基本セットアップ

// build.gradle.kts
dependencies {
    implementation("io.klogging:klogging-jvm:0.10.1")
    // Spring Boot統合の場合
    implementation("io.klogging:slf4j-klogging:0.10.1")
}
<!-- Maven pom.xml -->
<dependency>
    <groupId>io.klogging</groupId>
    <artifactId>klogging-jvm</artifactId>
    <version>0.10.1</version>
</dependency>
import io.klogging.Klogging
import io.klogging.NoCoLogging
import io.klogging.config.loggingConfiguration
import kotlinx.coroutines.*

// 基本的なKlogging設定
fun main() = runBlocking {
    // コンソール出力の設定
    loggingConfiguration {
        ANSI_CONSOLE()
    }
    
    // シンプルなログ出力テスト
    val logger = NoCoLogging.logger()
    logger.info { "Klogging initialized successfully" }
    
    // コルーチン環境でのログ
    launch {
        val coLogger = Klogging.logger()
        coLogger.info { "Coroutine-based logging ready" }
    }
}

// 詳細設定例
fun setupAdvancedKlogging() {
    loggingConfiguration {
        // 複数出力先設定
        sink("console", ANSI_CONSOLE())
        sink("file", FILE("logs/app.log"))
        sink("json", FILE("logs/app.json", JSON_FORMAT))
        
        // ログレベル設定
        minLevel(Level.INFO)
        
        // 構造化ログ設定
        logger("com.example.service") {
            minLevel(Level.DEBUG)
            stopOnMatch = true
        }
        
        // 非同期配信設定
        asyncDispatcher {
            bufferSize = 1000
            dropOnOverflow = false
        }
    }
}

コルーチンとの統合(基本的な使用方法)

import io.klogging.Klogging
import io.klogging.NoCoLogging
import io.klogging.events.logContext
import kotlinx.coroutines.*

// コルーチン統合ロギングクラス
class UserService : Klogging {
    
    suspend fun processUser(userId: String, userData: UserData) = coroutineScope {
        // コルーチンコンテキストにログ情報を追加
        launch(logContext("userId" to userId, "operation" to "processUser")) {
            logger.info { "Starting user processing" }
            
            try {
                // ユーザーデータ検証
                validateUserData(userData)
                logger.debug { "User data validation completed" }
                
                // データベース保存
                saveUserToDatabase(userData)
                logger.info { "User data saved successfully" }
                
                // 外部API通知
                notifyExternalSystems(userId)
                logger.info { "External systems notified" }
                
            } catch (e: Exception) {
                logger.error(e) { "User processing failed" }
                throw e
            }
        }
    }
    
    private suspend fun validateUserData(userData: UserData) {
        logger.debug { "Validating user data: ${userData.email}" }
        
        if (userData.email.isBlank()) {
            logger.warn { "Invalid email address provided" }
            throw IllegalArgumentException("Email is required")
        }
        
        if (userData.age < 0 || userData.age > 150) {
            logger.warn { "Invalid age: ${userData.age}" }
            throw IllegalArgumentException("Invalid age range")
        }
    }
    
    private suspend fun saveUserToDatabase(userData: UserData) {
        logger.debug { "Saving to database" }
        delay(100) // データベース操作シミュレーション
        logger.info { "Database save completed" }
    }
    
    private suspend fun notifyExternalSystems(userId: String) {
        logger.debug { "Notifying external systems" }
        delay(50) // API呼び出しシミュレーション
        logger.info { "External notification completed" }
    }
}

// 非コルーチン環境での使用
class ConfigurationManager : NoCoLogging {
    
    fun loadConfiguration(configPath: String): Configuration {
        logger.info { "Loading configuration from: $configPath" }
        
        return try {
            val config = parseConfigFile(configPath)
            logger.info { "Configuration loaded successfully. Entries: ${config.entries.size}" }
            config
        } catch (e: Exception) {
            logger.error(e) { "Failed to load configuration" }
            throw ConfigurationException("Configuration loading failed", e)
        }
    }
    
    private fun parseConfigFile(path: String): Configuration {
        logger.debug { "Parsing configuration file" }
        // ファイル解析処理
        return Configuration()
    }
}

// データクラス
data class UserData(
    val email: String,
    val name: String,
    val age: Int
)

data class Configuration(
    val entries: Map<String, String> = emptyMap()
)

class ConfigurationException(message: String, cause: Throwable) : Exception(message, cause)

// 使用例
suspend fun main() {
    loggingConfiguration {
        ANSI_CONSOLE()
    }
    
    val userService = UserService()
    val configManager = ConfigurationManager()
    
    // コルーチンベースの処理
    val userData = UserData("[email protected]", "田中太郎", 30)
    userService.processUser("user123", userData)
    
    // 非コルーチン処理
    val config = configManager.loadConfiguration("/path/to/config.yaml")
}

構造化ログとコンテキスト管理

import io.klogging.Klogging
import io.klogging.events.logContext
import io.klogging.events.LogEvent
import kotlinx.coroutines.*
import java.util.*

// 構造化ログを活用したAPIサービス
class ApiService : Klogging {
    
    suspend fun handleRequest(requestId: String, endpoint: String, payload: Any) = coroutineScope {
        // リクエストコンテキストの設定
        launch(logContext(
            "requestId" to requestId,
            "endpoint" to endpoint,
            "timestamp" to System.currentTimeMillis(),
            "service" to "ApiService"
        )) {
            logger.info { "API request received" }
            
            val startTime = System.nanoTime()
            
            try {
                // 認証・認可チェック
                authenticateRequest(requestId)
                
                // ビジネスロジック実行
                val result = processRequest(endpoint, payload)
                
                val duration = (System.nanoTime() - startTime) / 1_000_000.0
                
                // 成功ログ(構造化)
                logger.info {
                    "API request completed successfully. " +
                    "Duration: {duration}ms, Result: {resultType}"
                } withContext mapOf(
                    "duration" to duration,
                    "resultType" to result::class.simpleName,
                    "resultSize" to result.toString().length
                )
                
            } catch (e: AuthenticationException) {
                val duration = (System.nanoTime() - startTime) / 1_000_000.0
                logger.warn(e) {
                    "Authentication failed. Duration: {duration}ms"
                } withContext mapOf(
                    "duration" to duration,
                    "errorType" to "authentication",
                    "clientIp" to getCurrentClientIp()
                )
                throw e
                
            } catch (e: Exception) {
                val duration = (System.nanoTime() - startTime) / 1_000_000.0
                logger.error(e) {
                    "API request failed. Duration: {duration}ms, Error: {errorMessage}"
                } withContext mapOf(
                    "duration" to duration,
                    "errorMessage" to e.message,
                    "errorType" to e::class.simpleName
                )
                throw e
            }
        }
    }
    
    private suspend fun authenticateRequest(requestId: String) {
        logger.debug { "Authenticating request" }
        
        // 認証処理シミュレーション
        delay(10)
        
        if (requestId.startsWith("invalid")) {
            throw AuthenticationException("Invalid request ID")
        }
        
        logger.debug { "Authentication successful" }
    }
    
    private suspend fun processRequest(endpoint: String, payload: Any): Any {
        logger.debug { "Processing business logic for endpoint: $endpoint" }
        
        return when (endpoint) {
            "/users" -> processUserRequest(payload)
            "/orders" -> processOrderRequest(payload)
            else -> {
                logger.warn { "Unknown endpoint: $endpoint" }
                throw IllegalArgumentException("Unsupported endpoint")
            }
        }
    }
    
    private suspend fun processUserRequest(payload: Any): Map<String, Any> {
        logger.debug { "Processing user request" }
        delay(50) // 処理時間シミュレーション
        
        return mapOf(
            "status" to "success",
            "userId" to UUID.randomUUID().toString(),
            "data" to payload
        )
    }
    
    private suspend fun processOrderRequest(payload: Any): Map<String, Any> {
        logger.debug { "Processing order request" }
        delay(100) // 処理時間シミュレーション
        
        return mapOf(
            "status" to "success",
            "orderId" to UUID.randomUUID().toString(),
            "data" to payload
        )
    }
    
    private fun getCurrentClientIp(): String {
        // クライアントIP取得(実装は環境に依存)
        return "192.168.1.100"
    }
}

// カスタム例外
class AuthenticationException(message: String) : Exception(message)

// 拡張関数でコンテキスト情報を追加
infix fun String.withContext(context: Map<String, Any>): String {
    return this // 実際のKloggingではコンテキストが自動的に処理される
}

// パフォーマンス監視ロガー
class PerformanceLogger : Klogging {
    
    suspend fun <T> measureOperation(
        operationName: String,
        additionalContext: Map<String, Any> = emptyMap(),
        operation: suspend () -> T
    ): T = coroutineScope {
        launch(logContext(
            "operation" to operationName,
            "startTime" to System.currentTimeMillis()
        ) + additionalContext) {
            
            val startTime = System.nanoTime()
            val startMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
            
            logger.debug { "Starting operation: $operationName" }
            
            try {
                val result = operation()
                val duration = (System.nanoTime() - startTime) / 1_000_000.0
                val endMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
                val memoryDelta = endMemory - startMemory
                
                logger.info {
                    "Operation completed: {operation}. Duration: {duration}ms, Memory: {memoryDelta}KB"
                } withContext mapOf(
                    "operation" to operationName,
                    "duration" to duration,
                    "memoryDelta" to memoryDelta / 1024,
                    "success" to true
                )
                
                return@launch result
                
            } catch (e: Exception) {
                val duration = (System.nanoTime() - startTime) / 1_000_000.0
                
                logger.error(e) {
                    "Operation failed: {operation}. Duration: {duration}ms, Error: {error}"
                } withContext mapOf(
                    "operation" to operationName,
                    "duration" to duration,
                    "error" to e.message,
                    "success" to false
                )
                
                throw e
            }
        }
    }
}

// 使用例
suspend fun main() {
    loggingConfiguration {
        sink("console", ANSI_CONSOLE())
        sink("file", FILE("logs/structured.log", JSON_FORMAT))
    }
    
    val apiService = ApiService()
    val perfLogger = PerformanceLogger()
    
    // 構造化ログを伴うAPI処理
    perfLogger.measureOperation(
        "api_request_processing",
        mapOf("endpoint" to "/users", "method" to "POST")
    ) {
        apiService.handleRequest(
            "req123",
            "/users",
            mapOf("name" to "田中太郎", "email" to "[email protected]")
        )
    }
}

Spring Boot統合と実用例

import io.klogging.Klogging
import io.klogging.NoCoLogging
import io.klogging.config.loggingConfiguration
import io.klogging.events.logContext
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.web.bind.annotation.*
import org.springframework.stereotype.Service
import org.springframework.stereotype.Repository
import kotlinx.coroutines.*
import javax.annotation.PostConstruct

@SpringBootApplication
class KloggingDemoApplication : NoCoLogging {
    
    @PostConstruct
    fun setupLogging() {
        loggingConfiguration {
            // 開発環境設定
            ANSI_CONSOLE()
            sink("file", FILE("logs/spring-app.log"))
            sink("json", FILE("logs/spring-app.json", JSON_FORMAT))
            
            // パッケージ別ログレベル
            logger("com.example.controller") { minLevel(Level.DEBUG) }
            logger("com.example.service") { minLevel(Level.INFO) }
            logger("com.example.repository") { minLevel(Level.WARN) }
            
            // SQLログの詳細設定
            logger("org.springframework.jdbc") { minLevel(Level.DEBUG) }
        }
        
        logger.info { "Klogging configuration completed for Spring Boot" }
    }
}

fun main(args: Array<String>) {
    runApplication<KloggingDemoApplication>(*args)
}

// RESTコントローラー
@RestController
@RequestMapping("/api/users")
class UserController(
    private val userService: UserService
) : Klogging {
    
    @PostMapping
    suspend fun createUser(@RequestBody userRequest: CreateUserRequest): UserResponse = coroutineScope {
        val requestId = java.util.UUID.randomUUID().toString()
        
        launch(logContext(
            "requestId" to requestId,
            "endpoint" to "/api/users",
            "method" to "POST",
            "controller" to "UserController"
        )) {
            logger.info { "Creating new user: ${userRequest.email}" }
            
            try {
                val user = userService.createUser(userRequest)
                
                logger.info {
                    "User created successfully. UserId: {userId}, Email: {email}"
                } withContext mapOf(
                    "userId" to user.id,
                    "email" to user.email,
                    "requestId" to requestId
                )
                
                UserResponse(user.id, user.email, user.name, "created")
                
            } catch (e: UserAlreadyExistsException) {
                logger.warn(e) {
                    "User creation failed - already exists: {email}"
                } withContext mapOf(
                    "email" to userRequest.email,
                    "requestId" to requestId
                )
                throw e
                
            } catch (e: Exception) {
                logger.error(e) {
                    "User creation failed: {error}"
                } withContext mapOf(
                    "error" to e.message,
                    "email" to userRequest.email,
                    "requestId" to requestId
                )
                throw e
            }
        }
    }
    
    @GetMapping("/{userId}")
    suspend fun getUser(@PathVariable userId: String): UserResponse = coroutineScope {
        launch(logContext(
            "userId" to userId,
            "endpoint" to "/api/users/{userId}",
            "method" to "GET"
        )) {
            logger.debug { "Retrieving user: $userId" }
            
            val user = userService.findUser(userId)
                ?: throw UserNotFoundException("User not found: $userId")
            
            logger.debug { "User retrieved successfully" }
            
            UserResponse(user.id, user.email, user.name, "retrieved")
        }
    }
}

// ビジネスサービス
@Service
class UserService(
    private val userRepository: UserRepository,
    private val emailService: EmailService
) : Klogging {
    
    suspend fun createUser(request: CreateUserRequest): User = coroutineScope {
        launch(logContext("service" to "UserService", "operation" to "createUser")) {
            logger.info { "Creating user: ${request.email}" }
            
            // 重複チェック
            val existingUser = userRepository.findByEmail(request.email)
            if (existingUser != null) {
                logger.warn { "User already exists: ${request.email}" }
                throw UserAlreadyExistsException("User already exists")
            }
            
            // ユーザー作成
            val user = User(
                id = java.util.UUID.randomUUID().toString(),
                email = request.email,
                name = request.name
            )
            
            val savedUser = userRepository.save(user)
            logger.info { "User saved to database: ${savedUser.id}" }
            
            // ウェルカムメール送信(非同期)
            launch {
                emailService.sendWelcomeEmail(savedUser)
            }
            
            logger.info { "User creation completed: ${savedUser.id}" }
            savedUser
        }
    }
    
    suspend fun findUser(userId: String): User? = coroutineScope {
        launch(logContext("service" to "UserService", "operation" to "findUser")) {
            logger.debug { "Finding user: $userId" }
            
            val user = userRepository.findById(userId)
            if (user != null) {
                logger.debug { "User found: ${user.email}" }
            } else {
                logger.debug { "User not found: $userId" }
            }
            
            user
        }
    }
}

// リポジトリ
@Repository
class UserRepository : Klogging {
    
    // 簡易的なインメモリストレージ
    private val users = mutableMapOf<String, User>()
    private val emailIndex = mutableMapOf<String, String>()
    
    suspend fun save(user: User): User = withContext(Dispatchers.IO) {
        launch(logContext("repository" to "UserRepository", "operation" to "save")) {
            logger.debug { "Saving user to database: ${user.id}" }
            
            users[user.id] = user
            emailIndex[user.email] = user.id
            
            // データベース保存をシミュレーション
            delay(10)
            
            logger.debug { "User saved successfully: ${user.id}" }
        }
        user
    }
    
    suspend fun findById(userId: String): User? = withContext(Dispatchers.IO) {
        launch(logContext("repository" to "UserRepository", "operation" to "findById")) {
            logger.debug { "Finding user by ID: $userId" }
            
            // データベース検索をシミュレーション
            delay(5)
            
            val user = users[userId]
            logger.debug { "User search result: ${if (user != null) "found" else "not found"}" }
            
            user
        }
    }
    
    suspend fun findByEmail(email: String): User? = withContext(Dispatchers.IO) {
        launch(logContext("repository" to "UserRepository", "operation" to "findByEmail")) {
            logger.debug { "Finding user by email: $email" }
            
            delay(5)
            
            val userId = emailIndex[email]
            val user = userId?.let { users[it] }
            
            logger.debug { "Email search result: ${if (user != null) "found" else "not found"}" }
            
            user
        }
    }
}

// メールサービス
@Service
class EmailService : Klogging {
    
    suspend fun sendWelcomeEmail(user: User) = coroutineScope {
        launch(logContext(
            "service" to "EmailService",
            "operation" to "sendWelcomeEmail",
            "userId" to user.id
        )) {
            logger.info { "Sending welcome email to: ${user.email}" }
            
            try {
                // メール送信処理をシミュレーション
                delay(100)
                
                logger.info { "Welcome email sent successfully to: ${user.email}" }
                
            } catch (e: Exception) {
                logger.error(e) {
                    "Failed to send welcome email to: {email}"
                } withContext mapOf(
                    "email" to user.email,
                    "userId" to user.id,
                    "error" to e.message
                )
            }
        }
    }
}

// データクラス
data class CreateUserRequest(
    val email: String,
    val name: String
)

data class UserResponse(
    val id: String,
    val email: String,
    val name: String,
    val status: String
)

data class User(
    val id: String,
    val email: String,
    val name: String
)

// カスタム例外
class UserAlreadyExistsException(message: String) : Exception(message)
class UserNotFoundException(message: String) : Exception(message)

高度な設定とカスタマイズ

import io.klogging.Klogging
import io.klogging.config.*
import io.klogging.events.*
import io.klogging.rendering.*
import io.klogging.sending.*
import kotlinx.coroutines.*
import java.time.LocalDateTime

// 高度なKlogging設定
object AdvancedKloggingConfig {
    
    fun setupProduction() {
        loggingConfiguration {
            // カスタムレンダリング設定
            rendering {
                // JSON形式でのカスタムレンダリング
                custom("customJson") { event ->
                    buildString {
                        append("{")
                        append("\"timestamp\":\"${event.timestamp}\",")
                        append("\"level\":\"${event.level}\",")
                        append("\"logger\":\"${event.logger}\",")
                        append("\"message\":\"${event.message}\",")
                        append("\"thread\":\"${event.items["thread"]}\",")
                        append("\"context\":{")
                        event.items.filter { it.key != "thread" }
                            .entries.joinToString(",") { "\"${it.key}\":\"${it.value}\"" }
                        append("}}")
                    }
                }
                
                // カスタムコンソール出力
                custom("colorConsole") { event ->
                    val color = when (event.level) {
                        Level.ERROR -> "\u001B[31m"  // 赤
                        Level.WARN -> "\u001B[33m"   // 黄
                        Level.INFO -> "\u001B[32m"   // 緑
                        Level.DEBUG -> "\u001B[36m"  // シアン
                        else -> "\u001B[0m"          // リセット
                    }
                    val reset = "\u001B[0m"
                    "$color[${event.timestamp}] [${event.level}] ${event.logger}: ${event.message}$reset"
                }
            }
            
            // カスタム送信先設定
            sending {
                // ファイル出力設定
                custom("rotatingFile") { events ->
                    events.forEach { event ->
                        val logFile = getLogFileForDate(LocalDateTime.now())
                        writeToFile(logFile, renderEvent(event, "customJson"))
                    }
                }
                
                // 外部システム連携
                custom("elasticSearch") { events ->
                    // ElasticSearchへの送信実装
                    sendToElasticSearch(events)
                }
                
                custom("metrics") { events ->
                    // メトリクス収集
                    collectMetrics(events)
                }
            }
            
            // 複合シンク設定
            sink("production") {
                renderer = "customJson"
                dispatcher = listOf("rotatingFile", "elasticSearch", "metrics")
            }
            
            sink("development") {
                renderer = "colorConsole"
                dispatcher = listOf("CONSOLE")
            }
            
            // ロガー別設定
            logger("com.example.api") {
                minLevel(Level.INFO)
                sink("production")
                stopOnMatch = true
            }
            
            logger("com.example.service") {
                minLevel(Level.DEBUG)
                sink("development")
                stopOnMatch = false
            }
            
            // パフォーマンス監視設定
            logger("performance") {
                minLevel(Level.DEBUG)
                sink("production")
                additionalContext = mapOf(
                    "application" to "myapp",
                    "version" to "1.0.0"
                )
            }
            
            // フィルター設定
            filter { event ->
                // 機密情報のマスキング
                event.copy(
                    message = maskSensitiveData(event.message),
                    items = event.items.mapValues { maskSensitiveData(it.value.toString()) }
                )
            }
        }
    }
    
    private fun getLogFileForDate(date: LocalDateTime): String {
        return "logs/app-${date.toLocalDate()}.log"
    }
    
    private fun writeToFile(filename: String, content: String) {
        // ファイル書き込み実装
        java.io.File(filename).appendText(content + "\n")
    }
    
    private fun renderEvent(event: LogEvent, renderer: String): String {
        // イベントレンダリング実装
        return event.toString()
    }
    
    private suspend fun sendToElasticSearch(events: List<LogEvent>) {
        // ElasticSearch送信実装
        withContext(Dispatchers.IO) {
            // HTTP クライアントでElasticSearchにPOST
            events.forEach { event ->
                // 実装詳細
            }
        }
    }
    
    private fun collectMetrics(events: List<LogEvent>) {
        // メトリクス収集実装
        events.forEach { event ->
            when (event.level) {
                Level.ERROR -> incrementErrorCounter()
                Level.WARN -> incrementWarningCounter()
                else -> incrementInfoCounter()
            }
        }
    }
    
    private fun maskSensitiveData(text: String): String {
        return text
            .replace(Regex("password[=:]\\s*\\S+", RegexOption.IGNORE_CASE), "password=***")
            .replace(Regex("token[=:]\\s*\\S+", RegexOption.IGNORE_CASE), "token=***")
            .replace(Regex("\\b\\d{4}-\\d{4}-\\d{4}-\\d{4}\\b"), "****-****-****-****")
    }
    
    private fun incrementErrorCounter() { /* メトリクス実装 */ }
    private fun incrementWarningCounter() { /* メトリクス実装 */ }
    private fun incrementInfoCounter() { /* メトリクス実装 */ }
}

// カスタムロガー実装
class AuditLogger : Klogging {
    
    suspend fun logSecurityEvent(
        eventType: String,
        userId: String?,
        details: Map<String, Any>
    ) = coroutineScope {
        launch(logContext(
            "eventType" to "security",
            "auditCategory" to eventType,
            "userId" to (userId ?: "anonymous"),
            "timestamp" to System.currentTimeMillis()
        )) {
            logger.info {
                "Security event: {eventType}. Details: {details}"
            } withContext mapOf(
                "eventType" to eventType,
                "details" to details,
                "severity" to determineSeverity(eventType)
            )
        }
    }
    
    suspend fun logBusinessEvent(
        operation: String,
        entityId: String,
        changes: Map<String, Any>
    ) = coroutineScope {
        launch(logContext(
            "eventType" to "business",
            "operation" to operation,
            "entityId" to entityId
        )) {
            logger.info {
                "Business operation: {operation} on entity {entityId}"
            } withContext mapOf(
                "operation" to operation,
                "entityId" to entityId,
                "changes" to changes,
                "changeCount" to changes.size
            )
        }
    }
    
    private fun determineSeverity(eventType: String): String {
        return when (eventType) {
            "login_failure", "unauthorized_access" -> "high"
            "login_success", "logout" -> "low"
            "password_change", "permission_change" -> "medium"
            else -> "low"
        }
    }
}

// 使用例
suspend fun main() {
    AdvancedKloggingConfig.setupProduction()
    
    val auditLogger = AuditLogger()
    
    // セキュリティイベント
    auditLogger.logSecurityEvent(
        "login_failure",
        "user123",
        mapOf(
            "ip" to "192.168.1.100",
            "userAgent" to "Mozilla/5.0...",
            "reason" to "invalid_password"
        )
    )
    
    // ビジネスイベント
    auditLogger.logBusinessEvent(
        "user_update",
        "user123",
        mapOf(
            "oldEmail" to "[email protected]",
            "newEmail" to "[email protected]",
            "updatedBy" to "admin"
        )
    )
}