### Logback Configuration Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Configure logging behavior, appenders, and log levels using Logback's XML format. This example sets up console output and defines specific levels for different packages. ```xml %date{ISO8601} [%thread] %-5level %logger{36} - %msg%n ``` -------------------------------- ### Marker + Message Logging Example (Generated) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md This example shows the generated code for logging an error message with a marker, including a level check specific to the marker. ```scala logger.error(securityMarker, "Breach detected") // Generated: // if (logger.isErrorEnabled(securityMarker)) { logger.error(securityMarker, "Breach detected") } ``` -------------------------------- ### Logback Test Configuration Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Example of a logback-test.xml configuration file for setting up console appenders and root logger level during tests. ```xml %-5level %logger - %msg%n ``` -------------------------------- ### Message with Arguments Logging Example (Generated) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md This example demonstrates the generated code for logging an error message with arguments, showing the transformation of string interpolation into SLF4J format and including a level check. ```scala logger.error(s"User $userId failed") // Generated: // if (logger.isErrorEnabled) { logger.error("User {}", userId) } ``` -------------------------------- ### Conditional Block Logging Example (Generated) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md This example demonstrates how a conditional logging block is transformed. The code inside the block is only executed if the specified log level is enabled. ```scala logger.whenErrorEnabled { val report = generateExpensiveReport() logger.error(report) } // Generated: // if (logger.isErrorEnabled) { // val report = generateExpensiveReport() // logger.error(report) // } ``` -------------------------------- ### Macro Performance: Code Size Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Illustrates the minimal code size added by macros, showing the generated bytecode instructions for a simple logging call. ```scala // Input logger.info("message") // Output (3 bytecode instructions) invoke logger.isInfoEnabled() ifeq skip_label invoke logger.info("message") skip_label: ``` -------------------------------- ### Message Only Logging Example (Generated) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md This example shows the generated code for a simple error message log call, which includes a level check. ```scala logger.error("Application crashed") // Generated: // if (logger.isErrorEnabled) { logger.error("Application crashed") } ``` -------------------------------- ### SLF4J Marker Usage Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/types.md Demonstrates how to use SLF4J markers for categorizing log messages, such as 'SECURITY' or 'PERFORMANCE'. ```scala val securityMarker = MarkerFactory.getMarker("SECURITY") val performanceMarker = MarkerFactory.getMarker("PERFORMANCE") logger.warn(securityMarker, "Unauthorized access attempt") ``` -------------------------------- ### Message with Cause Logging Example (Generated) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md This example illustrates the generated code for logging an error message along with an exception, including a level check. ```scala logger.error("Database error", exception) // Generated: // if (logger.isErrorEnabled) { logger.error("Database error", exception) } ``` -------------------------------- ### Logback Configuration with Environment Variables Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Configure Logback to use environment variables for dynamic settings like log level and path. This example sets default values if the variables are not found. ```xml ${LOG_PATH}/application.log %date [%thread] %-5level %logger - %msg%n ``` -------------------------------- ### String Interpolation Example (Works) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/README.md Demonstrates correct usage of string interpolation with logger.info. The message must be a literal string at compile time. ```scala logger.info(s"User $id") // ✓ Works ``` -------------------------------- ### Start Logging with StrictLogging Trait Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/getting-started.md Begin logging in your Scala class by extending the StrictLogging trait. ```scala import com.typesafe.scalalogging.StrictLogging class MyService extends StrictLogging { def start(): Unit = { logger.info("Service starting") } } ``` -------------------------------- ### Usage Example with Correlation ID Logging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/LoggerTakingImplicit.md Demonstrates how to implement correlation ID logging using LoggerTakingImplicit. This example sets up a custom CanLog instance for CorrelationId and shows its usage in handling requests. Ensure SLF4J MDC is configured if using it for external correlation ID management. ```scala import com.typesafe.scalalogging.{CanLog, Logger} import org.slf4j.MDC case class CorrelationId(value: String) implicit object CanLogCorrelationId extends CanLog[CorrelationId] { override def logMessage(originalMsg: String, id: CorrelationId): String = s"[${id.value}] $originalMsg" override def afterLog(id: CorrelationId): Unit = { MDC.remove("correlationId") } } // In your service code def handleRequest(requestId: String): Unit = { implicit val correlationId = CorrelationId(requestId) val logger = Logger.takingImplicit[CorrelationId]("MyService") logger.info("Request started") // Logs: "[req-123] Request started" logger.debug("Processing data") // Logs: "[req-123] Processing data" logger.info("Request completed") // Logs: "[req-123] Request completed" } ``` -------------------------------- ### CanLog Trait Example Implementation Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/types.md An example implementation of the CanLog trait for a CorrelationId type, demonstrating how to integrate custom context into log messages. ```scala case class CorrelationId(value: String) implicit object CanLogCorrelationId extends CanLog[CorrelationId] { override def logMessage(msg: String, id: CorrelationId): String = s"[${id.value}] $msg" } ``` -------------------------------- ### SLF4J MDC Integration Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Utilize SLF4J's Mapped Diagnostic Context (MDC) to add contextual information to log messages. This example shows setting, logging, and clearing MDC values. ```scala import org.slf4j.MDC // Set MDC context MDC.put("userId", "12345") MDC.put("requestId", "req-xyz") // Log with context automatically included (if configured in logback.xml) logger.info("User action") // Clean up MDC.clear() ``` -------------------------------- ### Logback MDC Pattern Configuration Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Example of how to include MDC values in the log output pattern within Logback's configuration. This allows contextual data to appear in logs. ```xml %date [%thread] %-5level %logger - %X{userId} %X{requestId} - %msg%n ``` -------------------------------- ### String Interpolation Example (Fails) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/README.md Illustrates a case where string interpolation does not work because the message is not a literal string at compile time. ```scala val msg = s"User $id"; logger.info(msg) // ✗ No transformation ``` -------------------------------- ### CanLog UserId for Simple Message Prefix Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/CanLog.md An example of implementing CanLog for UserId to prepend user information to log messages. ```scala case class UserId(value: Int) implicit object CanLogUserId extends CanLog[UserId] { override def logMessage(msg: String, userId: UserId): String = s"[user=${userId.value}] $msg" } val logger = Logger.takingImplicit[UserId]("app") implicit val user = UserId(42) logger.info("Profile updated") // Logs: "[user=42] Profile updated" ``` -------------------------------- ### Example Transformation of String Interpolation Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/String-Interpolation.md Illustrates the internal extraction process of literals and expressions from a string interpolation, and how it's transformed into an SLF4J format string with corresponding arguments. ```scala // Input logger.info(s"Processing request $id for user $userId in ${region.name}") // Internal extraction // Literals: ["Processing request ", " for user ", " in ", ""] // Expressions: [id, userId, region.name] // Format: "Processing request {} for user {} in {}" // Output logger.info("Processing request {} for user {} in {}", id, userId, region.name) ``` -------------------------------- ### Detecting String Interpolation Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Example demonstrating how the macro identifies string interpolations by analyzing literal and interpolated parts. ```scala val userId = 42 logger.info(s"User $userId") ``` -------------------------------- ### Logger Naming Convention Examples Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Demonstrates how logger names are automatically derived from class names when using Scala Logging traits, or can be explicitly set. ```scala class MyApplication extends StrictLogging { // logger name = "com.example.MyApplication" logger.info("Starting") } val logger = Logger("custom.name") // logger name = "custom.name" ``` -------------------------------- ### Logging Static Messages Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Example of logging a static message without interpolation, including the generated level check. ```scala logger.error("Static message") // Becomes: if (logger.isErrorEnabled) { logger.error("Static message") } // No arguments passed ``` -------------------------------- ### Service with Strict Logging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Example of a Scala class using StrictLogging for logging. The logger is automatically reconstructed after serialization and deserialization. ```scala class Service extends StrictLogging with Serializable { // logger is serialized by name def work(): Unit = logger.info("Working") } // Serialize val bytes = serialize(new Service()) // Deserialize val service2 = deserialize(bytes) // logger is automatically reconstructed service2.work() // Works normally ``` -------------------------------- ### Example Usage of StrictLogging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Logging-Traits.md Illustrates using the StrictLogging trait. The logger is initialized immediately upon object creation, suitable for singletons, factories, or when logging is always expected. ```scala import com.typesafe.scalalogging.StrictLogging class UserService extends StrictLogging { def createUser(name: String): User = { logger.info(s"Creating user: $name") // ... user creation logic User(name) } def deleteUser(id: Int): Unit = { logger.warn(s"Deleting user: $id") // ... user deletion logic } } val service = new UserService() // logger is initialized immediately during construction service.createUser("Alice") ``` -------------------------------- ### Example Usage of LazyLogging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Logging-Traits.md Demonstrates how to use the LazyLogging trait in a class. The logger is initialized only when its methods are first called, making it suitable for scenarios with numerous object instantiations. ```scala import com.typesafe.scalalogging.LazyLogging class RequestHandler extends LazyLogging { def handleRequest(id: String): Unit = { // logger is initialized on first use logger.info(s"Handling request $id") if (someCondition) { logger.debug("Debug information") } } } // Create many instances — logger only initialized when needed val handlers = (1 to 1000).map(_ => new RequestHandler()) ``` -------------------------------- ### Define Cross Scala Versions in Build Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Specify the Scala versions for which your project should be cross-compiled. This example includes Scala 2.12, 2.13, and 3. ```scala crossScalaVersions := Seq("2.12.21", "2.13.16", "3.7.4") ``` -------------------------------- ### CanLog Context for Complex Transformation Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/CanLog.md An example of CanLog for a complex Context type, transforming the log message and optionally propagating context to MDC. ```scala import org.slf4j.MDC case class Context(userId: Int, traceId: String, environment: String) implicit object CanLogContext extends CanLog[Context] { override def logMessage(msg: String, ctx: Context): String = { s"[$ctx.environment:$ctx.traceId:user=${ctx.userId}] $msg" } override def afterLog(ctx: Context): Unit = { // Optional: propagate to MDC for downstream systems MDC.put("traceId", ctx.traceId) } } ``` -------------------------------- ### AnyLogging Trait Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/README.md Shows the AnyLogging trait, which requires explicit logger definition. This is useful for traits that need logger access without committing to a specific implementation. ```scala class AnyLoggingExample extends AnyLogging { override protected val logger: Logger = Logger("name") logger.info("This is Any Logging ;-)") logger.whenInfoEnabled { println("This would only execute when the info level is enabled.") (1 to 10).foreach(x => println("Scala logging is great!")) } } ``` -------------------------------- ### Request Handler with Lifecycle Logging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/examples.md Implement a request handler that logs the lifecycle of a request, including start, completion, and potential errors. Use different log levels for different events. ```scala import com.typesafe.scalalogging.StrictLogging case class Request(id: String, userId: Int, action: String) case class Response(status: Int, message: String) class RequestHandler extends StrictLogging { def handle(request: Request): Response = { logger.info(s"Handling request ${request.id} from user ${request.userId}") try { val startTime = System.currentTimeMillis() val result = processRequest(request) val duration = System.currentTimeMillis() - startTime logger.info(s"Request ${request.id} completed in ${duration}ms") Response(200, result) } catch { case e: ValidationException => logger.warn(s"Request ${request.id} validation failed: ${e.getMessage}") Response(400, "Validation error") case e: Exception => logger.error(s"Request ${request.id} failed unexpectedly", e) Response(500, "Internal error") } } private def processRequest(request: Request): String = { logger.debug(s"Processing action: ${request.action}") // Process... "success" } } ``` -------------------------------- ### Configure Logback Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/getting-started.md Optional: Configure Logback by creating a logback.xml file in src/main/resources. ```xml %date{ISO8601} [%thread] %-5level %logger - %msg%n ``` -------------------------------- ### Logback Configuration with Patterns and Appenders Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/examples.md A sample logback.xml configuration defining logging patterns, console and file appenders, and asynchronous file logging. It also shows package-level logger configurations. ```xml ${LOG_PATTERN} logs/application.log ${LOG_PATTERN} 512 ``` -------------------------------- ### Set Log Level via Java System Property Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Demonstrates how to set the LOG_LEVEL using a Java system property when running an application. ```bash java -DLOG_LEVEL=debug -Dapp.name=MyApp application.jar ``` -------------------------------- ### Exception Logging with Placeholders (Works) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/README.md Demonstrates the correct pattern for logging exceptions with details using SLF4J placeholders. ```scala logger.error("Failed: {}", detail) // Use this pattern ``` -------------------------------- ### Automatic Level Checking Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Macros automatically wrap logging calls with level checks to avoid expensive argument evaluation when the log level is disabled. This example shows how a debug log with string interpolation is transformed. ```scala // Your code logger.debug(s"Computing result: ${expensiveComputation()}") // Becomes (via macro) if (logger.isDebugEnabled) { logger.debug("Computing result: {}", expensiveComputation()) } ``` -------------------------------- ### Add SLF4J Simple Dependency for Testing Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Include SLF4J Simple, a minimal SLF4J backend, for testing purposes. It provides basic console output without complex configuration. ```scala libraryDependencies += "org.slf4j" % "slf4j-simple" % "2.0.0" ``` -------------------------------- ### Set Log Level via Environment Variable Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Shows how to set the LOG_LEVEL using an environment variable before running the application. ```bash export LOG_LEVEL=debug java application.jar ``` -------------------------------- ### Create Logger by Name Source: https://github.com/lightbend-labs/scala-logging/blob/main/README.md Instantiate a Logger by providing a name string. This is a common way to identify log sources. ```scala val logger = Logger("name") ``` -------------------------------- ### Configure Logback for Testing Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/getting-started.md Create a `logback-test.xml` file in `src/test/resources` to configure logging specifically for tests. Logback automatically picks up this file, setting the root level to 'debug' for testing purposes. ```xml %-5level %logger - %msg%n ``` -------------------------------- ### Configure Logback XML for Package-Specific Log Levels Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/getting-started.md This XML configuration sets up Logback to use a console appender and defines root log level as 'info'. It further specifies 'debug' level for 'com.example' package and 'warn' for 'org.springframework'. ```xml %date %-5level %logger - %msg%n ``` -------------------------------- ### Mocking Logger with AnyLogging for Testing Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Logging-Traits.md Shows how to mock the logger when using AnyLogging to make traits testable. This is useful for unit testing without actual logging output. ```scala import org.mockito.Mockito._ class MyTraitImpl extends AnyLogging { override protected val logger: Logger = mock[Logger] // Mock logger for testing } ``` -------------------------------- ### Logging Static Messages with Marker Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Shows how to log a static message with a marker, including the generated level check. ```scala logger.error(marker, "Static message") // Becomes: if (logger.isErrorEnabled(marker)) { logger.error(marker, "Static message") } ``` -------------------------------- ### Testing Dependencies Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Lists the testing dependencies required for scala-logging, including logback-classic, scalatest, and mockito-scala. ```text ch.qos.logback:logback-classic (test) org.scalatest:scalatest (test) org.scalatestplus:mockito-scala (test) ``` -------------------------------- ### StrictLogging Trait Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/README.md Illustrates the StrictLogging trait. Log messages and conditional blocks are evaluated strictly. Use this when logging is expected to be enabled or for singletons. ```scala class StrictLoggingExample extends StrictLogging { logger.debug("This is Strict Logging ;-)") logger.whenDebugEnabled { println("This would only execute when the debug level is enabled.") (1 to 10).foreach(x => println("Scala logging is great!")) } } ``` -------------------------------- ### Logging in Service with Exception Handling Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/getting-started.md Implement logging within a service class, including handling potential exceptions during payment processing. ```scala import com.typesafe.scalalogging.StrictLogging class PaymentService extends StrictLogging { def processPayment(amount: Double): Unit = { logger.info(s"Processing payment of $$amount") try { executePayment(amount) logger.info("Payment completed successfully") } catch { case e: Exception => logger.error("Payment failed", e) throw e } } } ``` -------------------------------- ### String Interpolation Transformation Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/INDEX.md Scala string interpolations are automatically converted to SLF4J format by the macro system. This example shows an error log with string interpolation. ```scala logger.error(s"User $id failed") // User code logger.error("User {} failed", id) // Generated by macro ``` -------------------------------- ### LazyLogging Trait Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/README.md Demonstrates the use of the LazyLogging trait. Log messages and conditional blocks are evaluated lazily, which can improve performance when logging is often disabled. ```scala class LazyLoggingExample extends LazyLogging { logger.debug("This is Lazy Logging ;-)") logger.whenDebugEnabled { println("This would only execute when the debug level is enabled.") (1 to 10).foreach(x => println("Scala logging is great!")) } } ``` -------------------------------- ### Fallback Error Handling Best Practice Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Demonstrates a best practice for handling potential exceptions during logging by falling back to printing to System.err. This ensures that even if the primary logging mechanism fails, error messages are not lost. ```scala try { logger.info("Something") } catch { case e: Exception => // Log to stderr as fallback System.err.println("Logging failed: " + e) } ``` -------------------------------- ### Runtime Dependencies Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Lists the runtime dependencies for the scala-logging library, including slf4j-api. ```text scala-logging └── org.slf4j:slf4j-api (provided) ``` -------------------------------- ### Automatic Level Checking Example Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/INDEX.md Scala Logging automatically wraps logging calls with level checks. This snippet shows how user code for debug logging is transformed. ```scala logger.debug("msg") // User code if (logger.isDebugEnabled) // Generated by macro logger.debug("msg") ``` -------------------------------- ### Logback Async Appender Configuration Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Configure Logback with an async appender for high-throughput applications to improve performance by logging in a separate thread. ```xml 512 0 ``` -------------------------------- ### Organizing CanLog Instances by Module Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/CanLog.md Shows how to organize CanLog instances within a package object for better modularity in complex applications. This approach centralizes related implicit definitions. ```scala package com.example.logging object CanLogInstances { case class RequestContext(userId: Int, requestId: String) implicit object CanLogRequestContext extends CanLog[RequestContext] { override def logMessage(msg: String, ctx: RequestContext): String = s"[user=${ctx.userId}:${ctx.requestId}] $msg" } case class ServiceContext(serviceName: String, version: String) implicit object CanLogServiceContext extends CanLog[ServiceContext] { override def logMessage(msg: String, ctx: ServiceContext): String = s"[${ctx.serviceName}:${ctx.version}] $msg" } } // Import to make instances available import com.example.logging.CanLogInstances._ ``` -------------------------------- ### Logger Naming in Inheritance Hierarchies Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Logging-Traits.md Illustrates how logger names are automatically derived from class names when using traits like StrictLogging in an inheritance hierarchy. Each subclass gets its own logger. ```scala import com.typesafe.scalalogging.StrictLogging abstract class BaseService extends StrictLogging { // logger name = "com.example.BaseService" def start(): Unit = { logger.info("Service starting") } } class ConcreteService extends BaseService { // logger name = "com.example.ConcreteService" (overrides parent's logger) override def start(): Unit = { logger.info("Concrete service starting") // Uses ConcreteService's logger super.start() } } ``` -------------------------------- ### Scala 3 Macro Debugging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Demonstrates how to print generated code for macros in Scala 3 using the -explain flag. ```scala scalacOptions += "-explain" ``` -------------------------------- ### Correlation ID with MDC Logging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/CanLog.md Implements CanLog for a CorrelationId type, including the ID in the log message and setting it in SLF4J's MDC for downstream correlation. This example shows how to integrate with MDC for distributed tracing. ```scala import com.typesafe.scalalogging.{CanLog, Logger} import org.slf4j.MDC import scala.util.Using case class CorrelationId(value: String) { // Helper to execute code with this ID in MDC def withMDC[R](f: => R): R = { val previous = MDC.get("correlationId") try { MDC.put("correlationId", value) f } finally { if (previous == null) MDC.remove("correlationId") else MDC.put("correlationId", previous) } } } implicit object CanLogCorrelationId extends CanLog[CorrelationId] { // Include correlation ID in the message itself override def logMessage(msg: String, id: CorrelationId): String = s"[${id.value}] $msg" // Also set it in MDC for downstream log appenders override def afterLog(id: CorrelationId): Unit = { MDC.put("correlationId", id.value) } } // Usage in a service class PaymentService { private val logger = Logger.takingImplicit[CorrelationId]("payment") def processPayment(amount: Double)(implicit correlationId: CorrelationId): Unit = { logger.info(s"Processing payment of $$amount") try { // Process payment... logger.debug(s"Payment authorized for $$amount") logger.info("Payment processed successfully") } catch { case e: Exception => logger.error("Payment processing failed", e) throw e } } } // In request handler def handlePaymentRequest(correlationId: String, amount: Double): Unit = { implicit val id = CorrelationId(correlationId) val service = new PaymentService() service.processPayment(amount) } ``` -------------------------------- ### Build Dependencies for Scala 2 Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Lists the build dependencies for scala-logging when using Scala 2.12 or 2.13, including scala-reflect and scala-compiler for macros. ```text Scala 2.12/2.13: ├── scala-reflect (for macros) └── org.scala-lang:scala-compiler (for macros) ``` -------------------------------- ### Simple Logging Data Flow Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Visualizes the standard path of a logging request from user code through macro-generated code to the SLF4J logger and finally to the logging backend and appenders. ```text User Code ↓ Logger Method Call (e.g., logger.info("msg")) ↓ Macro-Generated Code: - Check: if (logger.isInfoEnabled) - Interpolation: transform s"..." to "...", arg1, arg2 - Call: logger.info(format, args...) ↓ SLF4J Logger ↓ Logging Backend (Logback/Log4j/etc) ↓ Appenders (console, file, etc) ``` -------------------------------- ### Create Logger with SLF4J Instance Source: https://github.com/lightbend-labs/scala-logging/blob/main/README.md Create a Logger by passing an existing SLF4J logger instance. Useful for integrating with existing logging configurations. ```scala val logger = Logger(LoggerFactory.getLogger("name")) ``` -------------------------------- ### Multi-Layer Logging with Custom Loggers Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/examples.md Demonstrates using multiple named loggers (e.g., 'audit', 'performance') alongside the default logger for different logging concerns within a class. ```scala import com.typesafe.scalalogging.StrictLogging class DataProcessor extends StrictLogging { private val auditLogger = Logger("audit") private val performanceLogger = Logger("performance") def processUser(userId: Int): Unit = { val startTime = System.currentTimeMillis() logger.info(s"Processing user: $userId") auditLogger.info(s"User processing initiated by admin") try { val user = fetchUser(userId) val result = transform(user) logger.info("Processing successful") auditLogger.info(s"User $userId transformation completed") } finally { val duration = System.currentTimeMillis() - startTime performanceLogger.info(s"Processing completed in ${duration}ms") } } private def fetchUser(id: Int) = User(id, "Name") private def transform(user: User) = user.copy(name = user.name.toUpperCase) } case class User(id: Int, name: String) ``` -------------------------------- ### Include MDC Context in Logback Pattern Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/getting-started.md Configure the Logback pattern to include contextual information stored in the MDC. The `[%X{userId}]` part will render the value associated with the 'userId' key from the MDC. ```xml %date [%X{userId}] %msg%n ``` -------------------------------- ### Add Logback Dependency Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/README.md Add the Logback classic dependency to your project to use Scala Logging. This is the recommended SLF4J backend. ```scala libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.4.14" ``` -------------------------------- ### Simple Info Message Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/examples.md Log a simple informational message. Ensure the logger is properly initialized. ```scala import com.typesafe.scalalogging.StrictLogging class Application extends StrictLogging { def main(): Unit = { logger.info("Application starting") } } ``` -------------------------------- ### Instantiate Logger with Implicit Context Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/LoggerTakingImplicit.md Demonstrates how to create a LoggerTakingImplicit instance for a specific context type, such as CorrelationId. This logger will automatically include the provided context in log messages. ```scala import com.typesafe.scalalogging.LoggerTakingImplicit import com.typesafe.scalalogging.CanLog case class CorrelationId(value: String) implicit object CanLogCorrelationId extends CanLog[CorrelationId] { override def logMessage(msg: String, id: CorrelationId): String = s"[${id.value}] $msg" } implicit val correlationId = CorrelationId("req-123") val logger = Logger.takingImplicit[CorrelationId]("app") ``` -------------------------------- ### Test Configuration with Console Appender Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/configuration.md Override production logging configuration for tests by using `logback-test.xml` and a console appender. Place this file in `src/test/resources/`. ```xml %level %logger - %msg%n ``` -------------------------------- ### Scala 3 Inline Macro for Zero-Cost Logging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Illustrates how Scala 3's inline mechanism can enable zero-cost abstractions for logging when the logging level is disabled. ```scala inline def debug(inline msg: String): Unit = ${...} // JVM can inline this completely away if level is disabled ``` -------------------------------- ### Using AnyLogging in a Trait Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Logging-Traits.md Demonstrates how to use the AnyLogging trait in a base trait and its implementations. Each implementation can define its own logger. ```scala import com.typesafe.scalalogging.{AnyLogging, Logger} // Base trait that multiple classes extend trait Repository extends AnyLogging { def find(id: Int): Option[User] = { logger.debug(s"Finding user: $id") // ... query logic None } } // Implementation class defines logger initialization class UserRepository extends Repository { override protected val logger: Logger = Logger("com.example.repository.UserRepository") } // Another implementation with different logger class ProductRepository extends Repository { override protected val logger: Logger = Logger("com.example.repository.ProductRepository") } ``` -------------------------------- ### Create Logger from SLF4J Logger Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Logger.md Wraps an existing SLF4J logger instance. Ensure you have imported org.slf4j.LoggerFactory and com.typesafe.scalalogging.Logger. ```scala import org.slf4j.LoggerFactory val underlying = LoggerFactory.getLogger("name") val logger = Logger(underlying) ``` -------------------------------- ### Handling Multiple Interpolations Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Demonstrates how the macro transforms a log message with multiple string interpolations into a format string with arguments. ```scala logger.info(s"User $userId action $action status $status") // Becomes: logger.info("User {} action {} status {}", userId, action, status) ``` -------------------------------- ### Structured Logging with Consistent Message Templates Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/String-Interpolation.md Ensure consistent message templates for structured logging tools like Sentry or Datadog. This allows them to group similar log events effectively. ```scala logger.error(s"User $u1 failed") // Message: "User 42 failed" logger.error(s"User $u2 failed") // Message: "User 99 failed" // Sentry sees 2 different errors (grouped separately) ``` ```scala logger.error(s"User $u1 failed") // SLF4J message: "User {}", arg: 42 logger.error(s"User $u2 failed") // SLF4J message: "User {}", arg: 99 // Sentry sees the same error template "User {}" (grouped together) ``` ```scala // Good: consistent message template logger.error(s"Database query failed for user $userId") logger.error(s"Database query failed for resource $resourceId") // Both have template: "Database query failed for" // Avoid: inconsistent templates logger.error(s"Failed to query database for user $userId") logger.error(s"Query error for user $userId") // Different templates, won't be grouped together ``` -------------------------------- ### Mocking SLF4J Logger in Unit Tests Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Demonstrates how to mock the underlying SLF4J logger using Mockito for unit testing scala-logging. ```scala import org.mockito.Mockito._ import org.slf4j.Logger as Underlying val underlying = mock[Underlying] when(underlying.isInfoEnabled).thenReturn(true) val logger = Logger(underlying) logger.info("test") verify(underlying).info("test") ``` -------------------------------- ### takingImplicit[A](clazz: Class[_]) Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Logger.md Creates a LoggerTakingImplicit from a class. The logger's name is derived from the provided class's name. ```APIDOC ## takingImplicit[A](clazz: Class[_]) ### Description Create a `LoggerTakingImplicit` from a class. The logger's name is derived from the provided class's name. ### Method Signature takingImplicit[A](clazz: Class[_])(implicit ev: CanLog[A]): LoggerTakingImplicit[A] ### Parameters #### Implicit Parameters - **ev** (CanLog[A]) - Required - Evidence that type `A` can be logged #### Path Parameters - **clazz** (Class[_]) - Required - Class object whose name becomes the logger name ### Returns `LoggerTakingImplicit[A]` named after the class ### Example ```scala val logger = Logger.takingImplicit[CorrelationId](classOf[MyClass]) ``` ``` -------------------------------- ### Scala 2.13 and Scala 3 Cross-Compilation Structure Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Outlines the directory structure and dependencies used when cross-compiling the library for both Scala 2.13 and Scala 3. It highlights the shared code, version-specific implementations, and macro implementations. ```text Scala 2.13 compilation: ├── Uses: core/src/main/scala (shared) ├── Uses: core/src/main/scala-2 (LoggerImpl with macro signatures) └── Uses: scala2macros (Scala2LoggerMacro implementations) Scala 3 compilation: ├── Uses: core/src/main/scala (shared) ├── Uses: core/src/main/scala-3 (LoggerImpl with inline + Scala 2 compat) └── Uses: core/src/main/scala-3 (LoggerMacro implementations) ``` -------------------------------- ### Contextual Logging with Implicit Parameters Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/README.md Enables contextual logging using implicit parameters and a type class system. The logger automatically includes the implicit context. ```scala case class CorrelationId(value: String) val logger = Logger.takingImplicit[CorrelationId]("app") implicit val id = CorrelationId("req-123") logger.info("Processing") // Automatically includes correlation ID ``` -------------------------------- ### trace(marker: Marker, message: String, args: Any*)(implicit a: A): Unit Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/LoggerTakingImplicit.md Logs a trace message with a marker, arguments for interpolation, and implicit context. This allows for dynamic and categorized trace logs. ```APIDOC ## trace(marker: Marker, message: String, args: Any*)(implicit a: A): Unit ### Description Logs a trace message with a marker, arguments for interpolation, and implicit context. ### Method `trace` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **marker** (org.slf4j.Marker) - Required - SLF4J Marker - **message** (String) - Required - Log message (may contain string interpolations) - **args** (Any*) - Optional - Arguments to interpolate - **a** (A) - implicit - Context value ### Response #### Success Response Unit ``` -------------------------------- ### warn(marker: Marker, message: String, args: Any*)(implicit a: A): Unit Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/LoggerTakingImplicit.md Logs a warning message with a marker, arguments for interpolation, and implicit context. This allows for dynamic and categorized warning logs. ```APIDOC ## warn(marker: Marker, message: String, args: Any*)(implicit a: A): Unit ### Description Logs a warning message with a marker, arguments for interpolation, and implicit context. ### Method `warn` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **marker** (org.slf4j.Marker) - Required - SLF4J Marker - **message** (String) - Required - Log message (may contain string interpolations) - **args** (Any*) - Optional - Arguments to interpolate - **a** (A) - implicit - Context value ### Response #### Success Response Unit ``` -------------------------------- ### Create Logger using Factory Method Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/getting-started.md Create a logger instance by providing a custom name to the Logger factory method. ```scala import com.typesafe.scalalogging.Logger val logger = Logger("myapp") logger.info("Starting") ``` -------------------------------- ### info(marker: Marker, message: String, args: Any*)(implicit a: A): Unit Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/LoggerTakingImplicit.md Logs an informational message with a marker, arguments for interpolation, and implicit context. This allows for dynamic and categorized informational logs. ```APIDOC ## info(marker: Marker, message: String, args: Any*)(implicit a: A): Unit ### Description Logs an informational message with a marker, arguments for interpolation, and implicit context. ### Method `info` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **marker** (org.slf4j.Marker) - Required - SLF4J Marker - **message** (String) - Required - Log message (may contain string interpolations) - **args** (Any*) - Optional - Arguments to interpolate - **a** (A) - implicit - Context value ### Response #### Success Response Unit ``` -------------------------------- ### info(message: String, args: Any*)(implicit a: A): Unit Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/LoggerTakingImplicit.md Logs an informational message with arguments for interpolation and implicit context. Use this for dynamic informational logs. ```APIDOC ## info(message: String, args: Any*)(implicit a: A): Unit ### Description Logs an informational message with arguments for interpolation and implicit context. ### Method `info` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **message** (String) - Required - Log message (may contain string interpolations) - **args** (Any*) - Optional - Arguments to interpolate - **a** (A) - implicit - Context value ### Response #### Success Response Unit ``` -------------------------------- ### Contextual Logging Data Flow Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/architecture.md Depicts the data flow for contextual logging, showing how implicit context is integrated into the macro-generated code to enrich log messages. ```text User Code: implicit val context = CorrelationId("123") logger.info("message") ↓ Macro-Generated Code: - Check: if (logger.isInfoEnabled) - Transform: canLogEv.logMessage("message", context) - Call: logger.info(transformedMsg) - Cleanup: canLogEv.afterLog(context) ↓ SLF4J Logger ↓ Logging Backend ↓ Appenders ``` -------------------------------- ### Tracing Macro Behavior with Logging Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Macro-System.md Suggests adding explicit logging statements to trace macro behavior during debugging. ```scala logger.error("message") // Add explicit logging to trace macro behavior ``` -------------------------------- ### Combining String Interpolation with MDC Context Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/String-Interpolation.md Integrate string interpolation with MDC (Mapped Diagnostic Context) for rich, context-aware logging. Logback can be configured to include MDC values in the output pattern. ```scala import org.slf4j.MDC case class RequestContext(userId: Int, requestId: String) def processRequest(ctx: RequestContext): Unit = { MDC.put("userId", ctx.userId.toString) MDC.put("requestId", ctx.requestId) try { val result = complexOperation() logger.info(s"Operation completed: $result") // SLF4J sees: "Operation completed: {}" // Logback appender includes userId and requestId from MDC } finally { MDC.clear() } } ``` ```xml %date [%thread] %-5level %logger - [user=%X{userId} req=%X{requestId}] - %msg%n ``` ```text 2025-02-15 10:23:45,123 [main] INFO MyService - [user=42 req=req-123] - Operation completed: success ``` -------------------------------- ### Create Logger using Type Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/getting-started.md Create a logger instance using the Logger factory method with a type parameter, automatically naming it after the specified class. ```scala val logger = Logger[UserService] // Logger named: com.example.UserService ``` -------------------------------- ### Create Logger by Class Name Source: https://github.com/lightbend-labs/scala-logging/blob/main/README.md Instantiate a Logger using the name of the current class. This automatically names the logger based on its enclosing class. ```scala val logger = Logger(getClass.getName) ``` -------------------------------- ### Asserting Log Statements with Logback Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/examples.md Shows how to assert log statements in tests by capturing logs using Logback's ListAppender. This is useful for verifying that specific messages or levels are logged. ```scala import org.slf4j.LoggerFactory import ch.qos.logback.classic.{LoggerContext, Level} import ch.qos.logback.core.read.ListAppender "Service" should { "log errors on failure" in { val loggerContext = LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext] val logbackLogger = loggerContext.getLogger("MyService").asInstanceOf[ch.qos.logback.classic.Logger] val listAppender = new ListAppender[ch.qos.logback.classic.spi.ILoggingEvent] listAppender.start() logbackLogger.addAppender(listAppender) logbackLogger.setLevel(Level.INFO) // Run code that logs service.performOperation() // Assert logs val events = listAppender.list events.size should be > 0 events.head.getFormattedMessage should include("operation") } } ``` -------------------------------- ### Cats Effect Logging Integration Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/examples.md Shows how to integrate Scala Logging with Cats Effect IO for effectful operations. The logger is available within the effect's context. ```scala import com.typesafe.scalalogging.StrictLogging import cats.effect.{IO, Sync} class FileService[F[_]: Sync] extends StrictLogging { def readFile(path: String): F[String] = Sync[F].delay { logger.info(s"Reading file: $path") // File reading logic "" } } ``` -------------------------------- ### Mocking Logger in ScalaTest Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/examples.md Demonstrates how to mock the SLF4J logger using Mockito within a ScalaTest test case. This allows for isolated testing of service logic without actual logging. ```scala import org.mockito.Mockito._ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec class UserServiceSpec extends AnyWordSpec with Matchers { "UserService" should { "log user creation" in { val mockLogger = mock[org.slf4j.Logger] when(mockLogger.isInfoEnabled).thenReturn(true) val logger = Logger(mockLogger) val service = new UserService { override val logger = new Logger(mockLogger) } service.createUser("Alice") // Verify that info was called verify(mockLogger).info(anyString(), any()) } } } ``` -------------------------------- ### Logger(name: String): Logger Source: https://github.com/lightbend-labs/scala-logging/blob/main/_autodocs/api-reference/Logger.md Creates a Logger instance by its name. The logger is obtained using `LoggerFactory.getLogger(name)`, allowing you to create loggers for specific contexts like application modules or classes. ```APIDOC ## Logger(name: String): Logger ### Description Creates a Logger instance by its name. The logger is obtained using `LoggerFactory.getLogger(name)`, allowing you to create loggers for specific contexts like application modules or classes. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **name** (String) - Required - Logger name, typically a package or class name ### Returns - **Logger** - A Logger instance with the specified name ### Example ```scala val logger = Logger("application") logger.info("Application started") ``` ```