or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

async-testing.mdconfiguration.mdindex.mdlogging.mdsync-testing.mdtest-probes.mdtime-control.md
tile.json

logging.mddocs/

Log Verification

Comprehensive log testing with filtering, assertion, and verification capabilities requiring Logback integration. Enables testing of log output from actors and behaviors.

Capabilities

LoggingTestKit

Main API for log verification testing with flexible filtering and assertion capabilities.

/**
 * Factory methods for creating LoggingTestKit instances
 */
object LoggingTestKit {
  /** Empty filter that doesn't match any events */
  def empty: LoggingTestKit
  /** Filter for events with message containing the string */
  def messageContains(str: String): LoggingTestKit
  /** Filter for TRACE level events with message containing string */
  def trace(messageIncludes: String): LoggingTestKit
  /** Filter for DEBUG level events with message containing string */
  def debug(messageIncludes: String): LoggingTestKit
  /** Filter for INFO level events with message containing string */
  def info(messageIncludes: String): LoggingTestKit
  /** Filter for WARN level events with message containing string */
  def warn(messageIncludes: String): LoggingTestKit
  /** Filter for WARN level events with specific throwable type */
  def warn[A <: Throwable: ClassTag]: LoggingTestKit
  /** Filter for ERROR level events with message containing string */
  def error(messageIncludes: String): LoggingTestKit
  /** Filter for ERROR level events with specific throwable type */
  def error[A <: Throwable: ClassTag]: LoggingTestKit
  /** Custom filter using function */
  def custom(test: Function[LoggingEvent, Boolean]): LoggingTestKit
  /** Filter for dead letter logging */
  def deadLetters(): LoggingTestKit
}

/**
 * TestKit for verifying log output with flexible filtering
 */
trait LoggingTestKit {
  /** Set expected number of matching events (default 1) */
  def withOccurrences(newOccurrences: Int): LoggingTestKit
  /** Set log level filter */
  def withLogLevel(newLogLevel: Level): LoggingTestKit
  /** Set logger name filter (supports sub-names) */
  def withLoggerName(newLoggerName: String): LoggingTestKit
  /** Set akka source filter (typically actor path) */
  def withSource(newSource: String): LoggingTestKit
  /** Set message content filter */
  def withMessageContains(newMessageContains: String): LoggingTestKit
  /** Set message regex filter */
  def withMessageRegex(newMessageRegex: String): LoggingTestKit
  /** Set throwable type filter */
  def withCause[A <: Throwable: ClassTag]: LoggingTestKit
  /** Set MDC filter (event must contain all specified entries) */
  def withMdc(newMdc: Map[String, String]): LoggingTestKit
  /** Control checking for excess messages after expected count */
  def withCheckExcess(checkExcess: Boolean): LoggingTestKit
  /** Set custom filter function */
  def withCustom(newCustom: Function[LoggingEvent, Boolean]): LoggingTestKit
  
  /** Test if event matches the filter conditions */
  def matches(event: LoggingEvent): Boolean
  /** Run code block and assert log expectations are met */
  def expect[T](code: => T)(implicit system: ActorSystem[_]): T
}

Usage Examples:

import akka.actor.testkit.typed.scaladsl.{ActorTestKit, LoggingTestKit}
import akka.actor.typed.scaladsl.Behaviors
import org.slf4j.event.Level

val testKit = ActorTestKit()

// Behavior that logs messages
val loggingBehavior = Behaviors.setup[String] { context =>
  Behaviors.receiveMessage { msg =>
    context.log.info("Processing message: {}", msg)
    context.log.warn("This is a warning")
    Behaviors.same
  }
}

val actor = testKit.spawn(loggingBehavior)

// Test INFO level logging
LoggingTestKit.info("Processing message").expect {
  actor ! "test"
}

// Test multiple occurrences
LoggingTestKit.warn("This is a warning")
  .withOccurrences(2)
  .expect {
    actor ! "msg1"
    actor ! "msg2"
  }

testKit.shutdownTestKit()

Log Level Filtering

Factory methods for creating filters based on specific log levels with optional message content matching.

/**
 * Create filter for TRACE level events
 * @param messageIncludes String that must be contained in log message
 * @returns LoggingTestKit configured for TRACE level
 */
def trace(messageIncludes: String): LoggingTestKit

/**
 * Create filter for DEBUG level events
 * @param messageIncludes String that must be contained in log message
 * @returns LoggingTestKit configured for DEBUG level
 */
def debug(messageIncludes: String): LoggingTestKit

/**
 * Create filter for INFO level events
 * @param messageIncludes String that must be contained in log message
 * @returns LoggingTestKit configured for INFO level
 */
def info(messageIncludes: String): LoggingTestKit

/**
 * Create filter for WARN level events with message content
 * @param messageIncludes String that must be contained in log message
 * @returns LoggingTestKit configured for WARN level
 */
def warn(messageIncludes: String): LoggingTestKit

/**
 * Create filter for WARN level events with specific exception type
 * @tparam A Throwable type that must be present in log event
 * @returns LoggingTestKit configured for WARN level with exception filter
 */
def warn[A <: Throwable: ClassTag]: LoggingTestKit

/**
 * Create filter for ERROR level events with message content
 * @param messageIncludes String that must be contained in log message
 * @returns LoggingTestKit configured for ERROR level
 */
def error(messageIncludes: String): LoggingTestKit

/**
 * Create filter for ERROR level events with specific exception type
 * @tparam A Throwable type that must be present in log event
 * @returns LoggingTestKit configured for ERROR level with exception filter
 */
def error[A <: Throwable: ClassTag]: LoggingTestKit

Filter Configuration

Methods for configuring various aspects of log event filtering including occurrences, sources, and custom conditions.

/**
 * Set expected number of matching events
 * @param newOccurrences Expected count (0 means expect no matching events)
 * @returns Configured LoggingTestKit
 */
def withOccurrences(newOccurrences: Int): LoggingTestKit

/**
 * Set log level filter
 * @param newLogLevel Log level to match (TRACE, DEBUG, INFO, WARN, ERROR)
 * @returns Configured LoggingTestKit
 */
def withLogLevel(newLogLevel: Level): LoggingTestKit

/**
 * Set logger name filter (supports hierarchical matching like logback.xml)
 * @param newLoggerName Logger name or parent name to match
 * @returns Configured LoggingTestKit
 */
def withLoggerName(newLoggerName: String): LoggingTestKit

/**
 * Set akka source filter (typically actor path)
 * @param newSource Value that akkaSource MDC must equal
 * @returns Configured LoggingTestKit
 */
def withSource(newSource: String): LoggingTestKit

/**
 * Set message content filter
 * @param newMessageContains String that must be contained in message
 * @returns Configured LoggingTestKit
 */
def withMessageContains(newMessageContains: String): LoggingTestKit

/**
 * Set message regex filter
 * @param newMessageRegex Regular expression that message must match
 * @returns Configured LoggingTestKit
 */
def withMessageRegex(newMessageRegex: String): LoggingTestKit

/**
 * Set throwable type filter
 * @tparam A Throwable class or subclass that must be present
 * @returns Configured LoggingTestKit
 */
def withCause[A <: Throwable: ClassTag]: LoggingTestKit

/**
 * Set MDC filter (all specified entries must be present)
 * @param newMdc Map of MDC key-value pairs that must be present
 * @returns Configured LoggingTestKit
 */
def withMdc(newMdc: Map[String, String]): LoggingTestKit

/**
 * Control excess message checking after expected count reached
 * @param checkExcess Whether to check for excess messages
 * @returns Configured LoggingTestKit
 */
def withCheckExcess(checkExcess: Boolean): LoggingTestKit

/**
 * Set custom filter function
 * @param newCustom Function that returns true for matching events
 * @returns Configured LoggingTestKit
 */
def withCustom(newCustom: Function[LoggingEvent, Boolean]): LoggingTestKit

Usage Examples:

import akka.actor.testkit.typed.scaladsl.LoggingTestKit
import org.slf4j.event.Level

// Test specific logger
LoggingTestKit.info("Started")
  .withLoggerName("akka.actor.Actor")
  .expect {
    // code that should log to akka.actor.Actor
  }

// Test with MDC context
LoggingTestKit.debug("Processing")
  .withMdc(Map("userId" -> "123", "requestId" -> "abc"))
  .expect {
    // code that logs with MDC context
  }

// Test exception logging
LoggingTestKit.error[IllegalArgumentException]
  .withOccurrences(1)
  .expect {
    // code that should log an IllegalArgumentException
  }

// Test with regex
LoggingTestKit.empty
  .withLogLevel(Level.WARN)
  .withMessageRegex("Actor .* failed with .*")
  .expect {
    // code that logs warnings matching the pattern
  }

Assertion and Execution

Core functionality for running code blocks while asserting that specific log events occur.

/**
 * Test if a log event matches the configured filter conditions
 * @param event LoggingEvent to test
 * @returns true if event matches all configured conditions
 */
def matches(event: LoggingEvent): Boolean

/**
 * Run code block and assert that log expectations are met
 * @param code Code block to execute
 * @param system Implicit ActorSystem for log interception
 * @tparam T Return type of code block
 * @returns Result of code block execution
 */
def expect[T](code: => T)(implicit system: ActorSystem[_]): T

Special Purpose Filters

Pre-configured filters for common logging scenarios in Akka applications.

/**
 * Create empty filter that matches no events (for building custom filters)
 * @returns Empty LoggingTestKit
 */
def empty: LoggingTestKit

/**
 * Create filter for message content matching
 * @param str String that must be contained in log message
 * @returns LoggingTestKit configured for message content
 */
def messageContains(str: String): LoggingTestKit

/**
 * Create custom filter using provided function
 * @param test Function that returns true for matching events
 * @returns LoggingTestKit with custom filter
 */
def custom(test: Function[LoggingEvent, Boolean]): LoggingTestKit

/**
 * Create filter for dead letter logging events
 * @returns LoggingTestKit configured to match dead letter logs
 */
def deadLetters(): LoggingTestKit

Usage Examples:

import akka.actor.testkit.typed.scaladsl.LoggingTestKit

// Test dead letters
LoggingTestKit.deadLetters().expect {
  // Send message to stopped actor
  stoppedActor ! "message"
}

// Build custom filter from empty
LoggingTestKit.empty
  .withLogLevel(Level.INFO)
  .withSource("akka://TestSystem/user/myactor")
  .withMessageContains("completed")
  .expect {
    // code that should produce the expected log
  }

// Complex custom filter
LoggingTestKit.custom { event =>
  event.getLevel == Level.ERROR && 
  event.getMessage.contains("database") &&
  event.getThrowable != null
}.expect {
  // code that should produce database error logs
}

LogCapturing

Utility traits for conditional log capture in test frameworks.

/**
 * ScalaTest mixin that captures logs for failed tests only
 */
trait LogCapturing // extends TestSuite

/**
 * Java TestRule for conditional log capture
 */
class LogCapturing extends TestRule // for JUnit integration

Usage Examples:

// ScalaTest integration
class MyActorSpec extends ScalaTestWithActorTestKit with LogCapturing {
  "MyActor" should {
    "handle messages correctly" in {
      // Logs will only be displayed if this test fails
      val actor = spawn(myBehavior)
      // ... test logic
    }
  }
}

// JUnit integration  
class MyActorTest {
  @Rule
  val logCapturing = new LogCapturing()
  
  @Test
  def testActorBehavior() {
    // Logs captured only on test failure
    // ... test logic
  }
}