Scala-Logging
SLF4Jをラップした便利で高性能なScalaロギングライブラリ。Lightbend Labsによって保守され、Scalaの特性を活かしたイディオムatic API設計。SLF4Jと他のロギングライブラリの上に構築され、最も広く使用されているScalaロギングソリューション。
ライブラリ
Scala Logging
概要
Scala LoggingはSLF4Jをラップした、Scala言語に特化した高性能ロギングライブラリです。Scalaのマクロシステムを活用してコンパイル時に条件付きログ出力を最適化し、実行時オーバーヘッドを最小限に抑制します。LazyLogging、StrictLogging、AnyLoggingなど複数のトレイトを提供し、様々な使用パターンに対応。Scalaの文字列補間との完全な統合により、読みやすく表現力豊かなログコードを記述できる、現代的なScalaアプリケーション開発に最適化されたロギングソリューションです。
詳細
Scala Loggingは2013年にLightbendによって開始され、Scala言語の特性を最大限活用したロギングライブラリとして進化してきました。最新版3.9.xではScala 2.11、2.12、2.13、Scala 3をサポートし、SLF4J 1.7+をバックエンドとして使用します。マクロベースの実装により、ログレベルが無効な場合の文字列補間処理を完全に回避し、本番環境でのパフォーマンス劣化を防ぎます。LoggerTakingImplicientやCanLogによる高度な型安全性、MDCサポート、マルチスレッド環境での安全性など、エンタープライズレベルの要求に応える機能を提供します。
主な特徴
- マクロベース最適化: ログレベル無効時の処理を完全にコンパイル時除去
- 複数トレイト提供: LazyLogging、StrictLogging、AnyLoggingで柔軟な実装
- Scala文字列補間統合: s"文字列"記法とSLF4Jプレースホルダーの自動変換
- 型安全な文脈ログ: LoggerTakingImplicitによるコンテキスト情報自動付与
- SLF4J完全互換: 既存のSLF4Jエコシステムとの透明な統合
- マルチスレッド対応: 並行処理環境での安全で効率的なログ出力
メリット・デメリット
メリット
- マクロによるコンパイル時最適化で実行時オーバーヘッドが極めて小さい
- Scalaの文字列補間記法により直感的で読みやすいログコードを記述可能
- SLF4J互換性により豊富なログバックエンド(Logback、Log4j2等)を選択可能
- LazyLogging等のトレイトにより最小限のボイラープレートコードで実装
- LoggerTakingImplicitによる型安全な文脈情報の自動付与機能
- Lightbend社による長期サポートと活発なコミュニティ
デメリット
- Scala専用ライブラリのため、Java等他言語プロジェクトでは利用不可
- マクロ依存のため、リフレクションベースの一部フレームワークで制約が発生
- SLF4Jバックエンドの選択と設定が別途必要(Logback等)
- 高度な機能(LoggerTakingImplicit等)は学習コストが高い
- デバッグ時にマクロ展開されたコードの調査が困難な場合がある
- ネイティブイメージビルド(GraalVM)で一部制約が生じる可能性
参考ページ
書き方の例
基本セットアップ
// build.sbtでの依存関係追加
libraryDependencies ++= Seq(
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.4",
"ch.qos.logback" % "logback-classic" % "1.2.10"
)
// 基本的なインポート
import com.typesafe.scala-logging.Logger
import org.slf4j.LoggerFactory
// Loggerインスタンスの作成方法
val logger = Logger("MyApplication")
val logger = Logger(LoggerFactory.getLogger("MyApplication"))
val logger = Logger(getClass.getName)
val logger = Logger(classOf[MyClass])
val logger = Logger[MyClass]
// 基本的なログ出力
logger.debug("デバッグメッセージ")
logger.info("情報メッセージ")
logger.warn("警告メッセージ")
logger.error("エラーメッセージ")
基本的なログ出力
import com.typesafe.scala-logging.Logger
class UserService {
private val logger = Logger(getClass)
def createUser(name: String, email: String): User = {
logger.info(s"ユーザー作成開始: 名前=$name, メール=$email")
// Scalaの文字列補間を使用(推奨)
val userId = generateUserId()
logger.debug(s"生成されたユーザーID: $userId")
val user = User(userId, name, email, createdAt = java.time.LocalDateTime.now())
// 条件付きログ出力(マクロによる最適化)
logger.debug(s"作成されたユーザーオブジェクト: ${user.toString}")
try {
val savedUser = saveToDatabase(user)
logger.info(s"ユーザー作成成功: ID=${savedUser.id}")
savedUser
} catch {
case ex: DatabaseException =>
logger.error(s"データベースエラー: ${ex.getMessage}", ex)
throw ex
case ex: Exception =>
logger.error(s"予期しないエラー: ${ex.getMessage}", ex)
throw new UserCreationException("ユーザー作成に失敗しました", ex)
}
}
def getUserById(id: String): Option[User] = {
logger.debug(s"ユーザー検索: ID=$id")
val result = findUserInDatabase(id)
result match {
case Some(user) =>
logger.debug(s"ユーザー発見: ${user.name}")
Some(user)
case None =>
logger.warn(s"ユーザーが見つかりません: ID=$id")
None
}
}
def updateUser(user: User): User = {
logger.info(s"ユーザー更新開始: ${user.id}")
// パフォーマンス最適化:ログレベルが有効な場合のみ処理
logger.whenDebugEnabled {
logger.debug("詳細なユーザー情報ダンプ:")
logger.debug(s" ID: ${user.id}")
logger.debug(s" 名前: ${user.name}")
logger.debug(s" メール: ${user.email}")
logger.debug(s" 作成日時: ${user.createdAt}")
}
val updatedUser = updateInDatabase(user)
logger.info(s"ユーザー更新完了: ${updatedUser.id}")
updatedUser
}
private def generateUserId(): String = java.util.UUID.randomUUID().toString
private def saveToDatabase(user: User): User = user // モック実装
private def findUserInDatabase(id: String): Option[User] = None // モック実装
private def updateInDatabase(user: User): User = user // モック実装
}
// データクラスの定義
case class User(id: String, name: String, email: String, createdAt: java.time.LocalDateTime)
// カスタム例外クラス
class UserCreationException(message: String, cause: Throwable) extends Exception(message, cause)
class DatabaseException(message: String) extends Exception(message)
// 複数のログレベルを使用したサービス例
class PaymentService {
private val logger = Logger[PaymentService]
def processPayment(userId: String, amount: BigDecimal): PaymentResult = {
logger.info(s"決済処理開始: ユーザー=$userId, 金額=$amount")
// 入力値の検証
if (amount <= 0) {
logger.warn(s"不正な決済金額: $amount (ユーザー: $userId)")
return PaymentResult.failure("不正な金額です")
}
if (amount > 1000000) {
logger.warn(s"高額決済の検出: $amount (ユーザー: $userId)")
// 管理者通知等の処理
}
logger.debug(s"決済前バリデーション完了: ユーザー=$userId")
try {
// 外部決済API呼び出し
logger.debug("外部決済API呼び出し中...")
val transactionId = callPaymentAPI(userId, amount)
logger.info(s"決済成功: ユーザー=$userId, 取引ID=$transactionId, 金額=$amount")
PaymentResult.success(transactionId)
} catch {
case ex: PaymentAPIException =>
logger.error(s"決済API エラー: ${ex.getMessage} (ユーザー: $userId, 金額: $amount)", ex)
PaymentResult.failure(s"決済処理エラー: ${ex.getMessage}")
case ex: java.net.SocketTimeoutException =>
logger.error(s"決済API タイムアウト: ユーザー=$userId, 金額=$amount", ex)
PaymentResult.failure("決済サービスが利用できません。しばらくお待ちください。")
case ex: Exception =>
logger.error(s"予期しない決済エラー: ${ex.getClass.getSimpleName} - ${ex.getMessage}", ex)
PaymentResult.failure("システムエラーが発生しました")
}
}
private def callPaymentAPI(userId: String, amount: BigDecimal): String = {
// 外部API呼び出しのシミュレーション
Thread.sleep(100) // API遅延のシミュレーション
s"txn_${java.util.UUID.randomUUID().toString.take(8)}"
}
}
// 決済結果クラス
sealed trait PaymentResult
object PaymentResult {
case class Success(transactionId: String) extends PaymentResult
case class Failure(reason: String) extends PaymentResult
def success(transactionId: String): PaymentResult = Success(transactionId)
def failure(reason: String): PaymentResult = Failure(reason)
}
class PaymentAPIException(message: String) extends Exception(message)
高度な設定(トレイト、マクロ、パフォーマンス最適化)
import com.typesafe.scala-logging.{LazyLogging, StrictLogging, AnyLogging, Logger}
// LazyLoggingトレイト - ログ使用頻度が低いクラス向け
class LazyLoggingExample extends LazyLogging {
def processData(data: List[String]): Unit = {
logger.info("データ処理開始")
// ログが必要な場合のみLoggerが初期化される
data.foreach { item =>
logger.debug(s"処理中のアイテム: $item")
}
logger.whenDebugEnabled {
logger.debug("詳細な処理情報:")
logger.debug(s" 総アイテム数: ${data.length}")
logger.debug(s" 処理時刻: ${java.time.LocalDateTime.now()}")
}
logger.info("データ処理完了")
}
}
// StrictLoggingトレイト - ログを頻繁に使用するクラス向け
class StrictLoggingExample extends StrictLogging {
def initializeService(): Unit = {
// Loggerがクラス初期化時に即座に作成される
logger.info("サービス初期化開始")
try {
loadConfiguration()
connectToDatabase()
startBackgroundTasks()
logger.info("サービス初期化完了")
} catch {
case ex: Exception =>
logger.error("サービス初期化失敗", ex)
throw ex
}
}
private def loadConfiguration(): Unit = {
logger.debug("設定ファイル読み込み中...")
// 設定読み込み処理
logger.debug("設定ファイル読み込み完了")
}
private def connectToDatabase(): Unit = {
logger.debug("データベース接続中...")
// DB接続処理
logger.info("データベース接続完了")
}
private def startBackgroundTasks(): Unit = {
logger.debug("バックグラウンドタスク開始中...")
// バックグラウンド処理開始
logger.info("バックグラウンドタスク開始完了")
}
}
// AnyLoggingトレイト - カスタムLogger設定
class AnyLoggingExample extends AnyLogging {
// カスタムLoggerを明示的に定義
override protected val logger: Logger = Logger("CustomApplication.SpecialComponent")
def specialOperation(): Unit = {
logger.info("特別な操作開始")
// 特別なログ形式やフィルタリングが必要な場合
logger.debug("特別なデバッグ情報")
logger.info("特別な操作完了")
}
}
// 複数Loggerの使用例
class MultiLoggerService {
private val mainLogger = Logger("Application.Main")
private val auditLogger = Logger("Application.Audit")
private val securityLogger = Logger("Application.Security")
def authenticateUser(username: String, password: String): Boolean = {
mainLogger.info(s"ユーザー認証開始: $username")
securityLogger.info(s"認証試行: ユーザー名=$username, IP=${getCurrentIP()}")
val isValid = validateCredentials(username, password)
if (isValid) {
mainLogger.info(s"認証成功: $username")
auditLogger.info(s"LOGIN_SUCCESS: user=$username, timestamp=${java.time.Instant.now()}")
securityLogger.info(s"認証成功: $username")
} else {
mainLogger.warn(s"認証失敗: $username")
auditLogger.warn(s"LOGIN_FAILURE: user=$username, timestamp=${java.time.Instant.now()}")
securityLogger.warn(s"認証失敗: $username, IP=${getCurrentIP()}")
}
isValid
}
private def validateCredentials(username: String, password: String): Boolean = {
// 認証ロジックのシミュレーション
username.nonEmpty && password.length >= 8
}
private def getCurrentIP(): String = "127.0.0.1" // IP取得のモック
}
// パフォーマンス測定とログ
class PerformanceLoggingService extends LazyLogging {
def measureOperation[T](operationName: String)(operation: => T): T = {
val startTime = System.nanoTime()
logger.debug(s"$operationName 開始")
try {
val result = operation
val endTime = System.nanoTime()
val durationMs = (endTime - startTime) / 1_000_000.0
logger.info(s"$operationName 完了: ${durationMs}ms")
// 遅い処理の警告
if (durationMs > 1000) {
logger.warn(s"遅い処理検出: $operationName (${durationMs}ms)")
}
result
} catch {
case ex: Exception =>
val endTime = System.nanoTime()
val durationMs = (endTime - startTime) / 1_000_000.0
logger.error(s"$operationName 失敗: ${durationMs}ms", ex)
throw ex
}
}
}
// 使用例
class BusinessService extends LazyLogging {
private val perfLogger = new PerformanceLoggingService()
def complexBusinessOperation(data: String): String = {
logger.info("複雑なビジネス処理開始")
val result = perfLogger.measureOperation("データ変換") {
transformData(data)
}
val finalResult = perfLogger.measureOperation("バリデーション") {
validateResult(result)
}
logger.info("複雑なビジネス処理完了")
finalResult
}
private def transformData(data: String): String = {
logger.debug(s"データ変換中: ${data.take(50)}...")
Thread.sleep(500) // 処理時間のシミュレーション
data.toUpperCase
}
private def validateResult(result: String): String = {
logger.debug("結果バリデーション中...")
Thread.sleep(200) // バリデーション時間のシミュレーション
if (result.nonEmpty) result else throw new IllegalArgumentException("Invalid result")
}
}
エラーハンドリングとデバッグログ
import com.typesafe.scala-logging.LazyLogging
import scala.util.{Try, Success, Failure}
import scala.concurrent.{Future, ExecutionContext}
// 包括的なエラーハンドリング
class ErrorHandlingService extends LazyLogging {
def safeOperation[T](operationName: String)(operation: => T): Try[T] = {
logger.debug(s"$operationName 実行開始")
Try {
operation
} match {
case Success(result) =>
logger.debug(s"$operationName 成功")
Success(result)
case Failure(ex: IllegalArgumentException) =>
logger.warn(s"$operationName: 不正な引数 - ${ex.getMessage}")
Failure(ex)
case Failure(ex: java.io.IOException) =>
logger.error(s"$operationName: IO エラー - ${ex.getMessage}", ex)
Failure(ex)
case Failure(ex: java.sql.SQLException) =>
logger.error(s"$operationName: データベースエラー - ${ex.getMessage}", ex)
Failure(ex)
case Failure(ex) =>
logger.error(s"$operationName: 予期しないエラー - ${ex.getClass.getSimpleName}: ${ex.getMessage}", ex)
Failure(ex)
}
}
// 詳細なスタックトレース付きエラーログ
def logDetailedError(operation: String, exception: Throwable): Unit = {
logger.error(s"詳細エラーレポート: $operation")
logger.error(s" 例外クラス: ${exception.getClass.getName}")
logger.error(s" エラーメッセージ: ${exception.getMessage}")
if (exception.getCause != null) {
logger.error(s" 根本原因: ${exception.getCause.getClass.getName} - ${exception.getCause.getMessage}")
}
logger.error(" スタックトレース:")
exception.getStackTrace.take(10).foreach { stackElement =>
logger.error(s" ${stackElement.toString}")
}
// システム情報の追加
logger.error(s" 発生時刻: ${java.time.LocalDateTime.now()}")
logger.error(s" スレッド: ${Thread.currentThread().getName}")
logger.error(s" メモリ使用量: ${Runtime.getRuntime.totalMemory() - Runtime.getRuntime.freeMemory()} bytes")
}
}
// 非同期処理でのエラーハンドリング
class AsyncService extends LazyLogging {
implicit val ec: ExecutionContext = ExecutionContext.global
def asyncOperation(id: String): Future[String] = {
logger.info(s"非同期処理開始: ID=$id")
val future = Future {
logger.debug(s"非同期処理実行中: ID=$id")
// 時間のかかる処理のシミュレーション
Thread.sleep(1000)
if (id.startsWith("error")) {
throw new RuntimeException(s"Simulated error for ID: $id")
}
s"処理結果: $id"
}
future.onComplete {
case Success(result) =>
logger.info(s"非同期処理成功: ID=$id, 結果=$result")
case Failure(exception) =>
logger.error(s"非同期処理失敗: ID=$id", exception)
}
future
}
def batchAsyncOperation(ids: List[String]): Future[List[String]] = {
logger.info(s"バッチ非同期処理開始: ${ids.length} 件")
val futures = ids.map(asyncOperation)
Future.sequence(futures).map { results =>
logger.info(s"バッチ非同期処理完了: 成功 ${results.length} 件")
results
}.recover {
case ex =>
logger.error("バッチ非同期処理で部分的失敗", ex)
List.empty[String]
}
}
}
// デバッグ専用ログサービス
class DebugLoggingService extends LazyLogging {
def traceMethodCall[T](methodName: String, args: Any*)(operation: => T): T = {
logger.debug(s"[$methodName] 呼び出し開始: 引数=${args.mkString(", ")}")
val startTime = System.nanoTime()
try {
val result = operation
val endTime = System.nanoTime()
val durationUs = (endTime - startTime) / 1000.0
logger.debug(s"[$methodName] 正常終了: 実行時間=${durationUs}μs, 戻り値=$result")
result
} catch {
case ex: Exception =>
val endTime = System.nanoTime()
val durationUs = (endTime - startTime) / 1000.0
logger.debug(s"[$methodName] 例外終了: 実行時間=${durationUs}μs, 例外=${ex.getClass.getSimpleName}")
throw ex
}
}
def logObjectState(objName: String, obj: Any): Unit = {
logger.debug(s"オブジェクト状態ダンプ [$objName]:")
logger.debug(s" クラス: ${obj.getClass.getName}")
logger.debug(s" toString: ${obj.toString}")
logger.debug(s" hashCode: ${obj.hashCode()}")
// リフレクションによるフィールド情報(開発時のみ推奨)
if (logger.isDebugEnabled) {
try {
val fields = obj.getClass.getDeclaredFields
fields.foreach { field =>
field.setAccessible(true)
val value = field.get(obj)
logger.debug(s" ${field.getName}: $value")
}
} catch {
case _: IllegalAccessException =>
logger.debug(s" フィールド情報にアクセスできません")
}
}
}
def logCollectionDetails[T](collectionName: String, collection: Iterable[T]): Unit = {
logger.debug(s"コレクション詳細 [$collectionName]:")
logger.debug(s" サイズ: ${collection.size}")
logger.debug(s" 型: ${collection.getClass.getName}")
if (logger.isDebugEnabled && collection.nonEmpty) {
logger.debug(s" 最初の要素: ${collection.head}")
if (collection.size > 1) {
logger.debug(s" 最後の要素: ${collection.last}")
}
if (collection.size <= 10) {
logger.debug(s" 全要素: [${collection.mkString(", ")}]")
} else {
logger.debug(s" 最初の5要素: [${collection.take(5).mkString(", ")}]...")
}
}
}
}
// 使用例
class ProductService extends LazyLogging {
private val errorHandler = new ErrorHandlingService()
private val debugLogger = new DebugLoggingService()
case class Product(id: String, name: String, price: BigDecimal)
def createProduct(name: String, price: BigDecimal): Try[Product] = {
debugLogger.traceMethodCall("createProduct", name, price) {
errorHandler.safeOperation("製品作成") {
if (name.trim.isEmpty) {
throw new IllegalArgumentException("製品名は必須です")
}
if (price <= 0) {
throw new IllegalArgumentException("価格は正の値である必要があります")
}
val product = Product(
id = java.util.UUID.randomUUID().toString,
name = name.trim,
price = price
)
debugLogger.logObjectState("新製品", product)
// データベース保存のシミュレーション
if (name.contains("error")) {
throw new java.sql.SQLException("データベース保存エラー")
}
logger.info(s"製品作成成功: ${product.id}")
product
}
}
}
def searchProducts(query: String): List[Product] = {
debugLogger.traceMethodCall("searchProducts", query) {
val results = performSearch(query)
debugLogger.logCollectionDetails("検索結果", results)
results
}
}
private def performSearch(query: String): List[Product] = {
// 検索処理のシミュレーション
List(
Product("1", "Sample Product 1", BigDecimal("100.00")),
Product("2", "Sample Product 2", BigDecimal("200.00"))
).filter(_.name.toLowerCase.contains(query.toLowerCase))
}
}
実用例(エンタープライズアプリケーション統合)
import com.typesafe.scala-logging.{LazyLogging, Logger, LoggerTakingImplicit, CanLog}
import org.slf4j.MDC
import scala.concurrent.{Future, ExecutionContext}
import scala.util.{Try, Success, Failure}
// MDC(Mapped Diagnostic Context)を使用した文脈情報の自動付与
class ContextualLoggingService extends LazyLogging {
def withContext[T](userId: String, requestId: String)(operation: => T): T = {
MDC.put("userId", userId)
MDC.put("requestId", requestId)
MDC.put("timestamp", java.time.Instant.now().toString)
try {
logger.info("処理開始")
val result = operation
logger.info("処理完了")
result
} catch {
case ex: Exception =>
logger.error("処理中にエラーが発生", ex)
throw ex
} finally {
MDC.clear()
}
}
}
// カスタム文脈情報の型安全な自動付与
case class RequestContext(userId: String, requestId: String, clientIP: String)
implicit object CanLogRequestContext extends CanLog[RequestContext] {
override def logMessage(originalMsg: String, context: RequestContext): String = {
s"[User:${context.userId}][Request:${context.requestId}][IP:${context.clientIP}] $originalMsg"
}
override def afterLog(context: RequestContext): Unit = {
MDC.put("userId", context.userId)
MDC.put("requestId", context.requestId)
MDC.put("clientIP", context.clientIP)
}
}
class EnterpriseService {
private val contextLogger = Logger.takingImplicit[RequestContext]("EnterpriseService")
def processRequest(data: String)(implicit context: RequestContext): Future[String] = {
implicit val ec: ExecutionContext = ExecutionContext.global
contextLogger.info(s"リクエスト処理開始: データ長=${data.length}")
Future {
// ビジネスロジックの処理
contextLogger.debug("データ変換中...")
val transformedData = data.toUpperCase
contextLogger.debug("バリデーション中...")
if (transformedData.contains("ERROR")) {
throw new IllegalArgumentException("不正なデータが含まれています")
}
contextLogger.info("リクエスト処理完了")
transformedData
}.recover {
case ex =>
contextLogger.error(s"リクエスト処理失敗: ${ex.getMessage}", ex)
throw ex
}
}
}
// 分散システム向けの構造化ログ
class DistributedSystemLogger extends LazyLogging {
case class LogEvent(
service: String,
operation: String,
correlationId: String,
startTime: Long,
endTime: Option[Long] = None,
status: String = "IN_PROGRESS",
metadata: Map[String, Any] = Map.empty
)
def logStructuredEvent(event: LogEvent): Unit = {
val duration = event.endTime.map(_ - event.startTime)
val logMessage = s"SERVICE=${event.service} " +
s"OPERATION=${event.operation} " +
s"CORRELATION_ID=${event.correlationId} " +
s"STATUS=${event.status} " +
duration.map(d => s"DURATION=${d}ms ").getOrElse("") +
s"METADATA=${event.metadata.map { case (k, v) => s"$k=$v" }.mkString(",")}"
event.status match {
case "SUCCESS" => logger.info(logMessage)
case "ERROR" => logger.error(logMessage)
case "WARNING" => logger.warn(logMessage)
case _ => logger.debug(logMessage)
}
}
def traceDistributedOperation[T](
service: String,
operation: String,
correlationId: String,
metadata: Map[String, Any] = Map.empty
)(block: => T): T = {
val startTime = System.currentTimeMillis()
logStructuredEvent(LogEvent(
service = service,
operation = operation,
correlationId = correlationId,
startTime = startTime,
metadata = metadata
))
try {
val result = block
val endTime = System.currentTimeMillis()
logStructuredEvent(LogEvent(
service = service,
operation = operation,
correlationId = correlationId,
startTime = startTime,
endTime = Some(endTime),
status = "SUCCESS",
metadata = metadata
))
result
} catch {
case ex: Exception =>
val endTime = System.currentTimeMillis()
logStructuredEvent(LogEvent(
service = service,
operation = operation,
correlationId = correlationId,
startTime = startTime,
endTime = Some(endTime),
status = "ERROR",
metadata = metadata + ("error" -> ex.getMessage)
))
throw ex
}
}
}
// マイクロサービス間通信のログ
class MicroserviceLogger extends LazyLogging {
def logOutgoingRequest(targetService: String, endpoint: String, payload: Any): String = {
val requestId = java.util.UUID.randomUUID().toString
logger.info(s"OUTGOING_REQUEST: service=$targetService endpoint=$endpoint requestId=$requestId")
logger.debug(s"OUTGOING_PAYLOAD: requestId=$requestId payload=${payload.toString}")
requestId
}
def logIncomingResponse(requestId: String, statusCode: Int, responseTime: Long): Unit = {
if (statusCode >= 200 && statusCode < 300) {
logger.info(s"INCOMING_RESPONSE: requestId=$requestId status=$statusCode responseTime=${responseTime}ms")
} else if (statusCode >= 400 && statusCode < 500) {
logger.warn(s"CLIENT_ERROR_RESPONSE: requestId=$requestId status=$statusCode responseTime=${responseTime}ms")
} else if (statusCode >= 500) {
logger.error(s"SERVER_ERROR_RESPONSE: requestId=$requestId status=$statusCode responseTime=${responseTime}ms")
}
}
def logCircuitBreakerEvent(service: String, event: String, details: Map[String, Any] = Map.empty): Unit = {
val message = s"CIRCUIT_BREAKER: service=$service event=$event ${details.map { case (k, v) => s"$k=$v" }.mkString(" ")}"
event match {
case "OPEN" | "HALF_OPEN" => logger.warn(message)
case "CLOSED" => logger.info(message)
case "SUCCESS" => logger.debug(message)
case "FAILURE" => logger.error(message)
case _ => logger.info(message)
}
}
}
// 本番環境向けの監視・アラートログ
class MonitoringLogger extends LazyLogging {
def logMetric(metricName: String, value: Double, unit: String = "", tags: Map[String, String] = Map.empty): Unit = {
val tagsString = if (tags.nonEmpty) s" tags=[${tags.map { case (k, v) => s"$k:$v" }.mkString(",")}]" else ""
logger.info(s"METRIC: name=$metricName value=$value unit=$unit$tagsString")
}
def logAlert(level: String, component: String, message: String, metadata: Map[String, Any] = Map.empty): Unit = {
val metadataString = if (metadata.nonEmpty) s" metadata=[${metadata.map { case (k, v) => s"$k:$v" }.mkString(",")}]" else ""
val logMessage = s"ALERT: level=$level component=$component message=$message$metadataString"
level.toUpperCase match {
case "CRITICAL" => logger.error(logMessage)
case "HIGH" => logger.error(logMessage)
case "MEDIUM" => logger.warn(logMessage)
case "LOW" => logger.info(logMessage)
case _ => logger.info(logMessage)
}
}
def logHealthCheck(component: String, status: String, responseTime: Long, details: String = ""): Unit = {
val message = s"HEALTH_CHECK: component=$component status=$status responseTime=${responseTime}ms details=$details"
status.toUpperCase match {
case "HEALTHY" => logger.info(message)
case "DEGRADED" => logger.warn(message)
case "UNHEALTHY" => logger.error(message)
case _ => logger.info(message)
}
}
}
// 統合使用例
class ComprehensiveApplicationService extends LazyLogging {
private val contextLogger = new ContextualLoggingService()
private val distributedLogger = new DistributedSystemLogger()
private val microserviceLogger = new MicroserviceLogger()
private val monitoringLogger = new MonitoringLogger()
def handleBusinessRequest(userId: String, requestData: String): Future[String] = {
implicit val ec: ExecutionContext = ExecutionContext.global
val requestId = java.util.UUID.randomUUID().toString
val correlationId = java.util.UUID.randomUUID().toString
Future {
contextLogger.withContext(userId, requestId) {
distributedLogger.traceDistributedOperation(
service = "BusinessService",
operation = "handleBusinessRequest",
correlationId = correlationId,
metadata = Map("userId" -> userId, "dataLength" -> requestData.length)
) {
try {
// ビジネスロジック実行
val result = processBusinessLogic(requestData)
// メトリクス記録
monitoringLogger.logMetric(
metricName = "business_request_processed",
value = 1,
tags = Map("userId" -> userId, "status" -> "success")
)
result
} catch {
case ex: Exception =>
// アラート送信
monitoringLogger.logAlert(
level = "HIGH",
component = "BusinessService",
message = s"Business request processing failed: ${ex.getMessage}",
metadata = Map("userId" -> userId, "requestId" -> requestId)
)
throw ex
}
}
}
}
}
private def processBusinessLogic(data: String): String = {
// ビジネスロジックのシミュレーション
if (data.contains("slow")) {
Thread.sleep(2000) // 遅い処理のシミュレーション
}
if (data.contains("error")) {
throw new RuntimeException("Simulated business logic error")
}
s"Processed: ${data.toUpperCase}"
}
}