### 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")
```
```