logRequestResult

Signature

def logRequestResult(marker: String)(implicit log: LoggingContext): Directive0
def logRequestResult(marker: String, level: LogLevel)(implicit log: LoggingContext): Directive0
def logRequestResult(show: HttpRequest => RouteResult => Option[LogEntry])(implicit log: LoggingContext): Directive0

The signature shown is simplified, the real signature uses magnets. [1]

[1] See The Magnet Pattern for an explanation of magnet-based overloading.

Description

Logs both the request and the response using the LoggingAdapterLoggingAdapter of the RequestContextRequestContext.

This directive is a combination of logRequest and logResult.

See logRequest for the general description how these directives work.

Example

Scala
source// different possibilities of using logRequestResult

// The first alternatives use an implicitly available LoggingContext for logging
// marks with "get-user", log with debug level, HttpRequest.toString, HttpResponse.toString
DebuggingDirectives.logRequestResult("get-user")

// marks with "get-user", log with info level, HttpRequest.toString, HttpResponse.toString
DebuggingDirectives.logRequestResult(("get-user", Logging.InfoLevel))

// logs just the request method and response status at info level
def requestMethodAndResponseStatusAsInfo(req: HttpRequest): RouteResult => Option[LogEntry] = {
  case RouteResult.Complete(res) => Some(LogEntry(req.method.name + ": " + res.status, Logging.InfoLevel))
  case _                         => None // no log entries for rejections
}
DebuggingDirectives.logRequestResult(requestMethodAndResponseStatusAsInfo _)

// This one will only log rejections
val rejectionLogger: HttpRequest => RouteResult => Option[LogEntry] = req => {
  case Rejected(rejections) => Some(LogEntry(s"Request: $req\nwas rejected with rejections:\n$rejections", Logging.DebugLevel))
  case _                    => None
}
DebuggingDirectives.logRequestResult(rejectionLogger)

// This one doesn't use the implicit LoggingContext but uses `println` for logging
def printRequestMethodAndResponseStatus(req: HttpRequest)(res: RouteResult): Unit =
  println(requestMethodAndResponseStatusAsInfo(req)(res).map(_.obj.toString).getOrElse(""))
val logRequestResultPrintln = DebuggingDirectives.logRequestResult(LoggingMagnet(_ => printRequestMethodAndResponseStatus))

// tests:
Get("/") ~> logRequestResultPrintln(complete("logged")) ~> check {
  responseAs[String] shouldEqual "logged"
}
Java
sourceimport static akka.http.javadsl.server.Directives.logRequestResultOptional;

// using logRequestResult
// handle request to optionally generate a log entry
BiFunction<HttpRequest, HttpResponse, Optional<LogEntry>> requestMethodAsInfo =
  (request, response) ->
    (response.status().isSuccess()) ?
      Optional.of(
        LogEntry.create(
          request.method().name() + ":" + response.status().intValue(),
          InfoLevel()))
      : Optional.empty(); // not a successful response

// handle rejections to optionally generate a log entry
BiFunction<HttpRequest, List<Rejection>, Optional<LogEntry>> rejectionsAsInfo =
  (request, rejections) ->
    (!rejections.isEmpty()) ?
      Optional.of(
        LogEntry.create(
          rejections
            .stream()
            .map(Rejection::toString)
            .collect(Collectors.joining(", ")),
          InfoLevel()))
      : Optional.empty(); // no rejections

final Route route = get(() -> logRequestResultOptional(
  requestMethodAsInfo,
  rejectionsAsInfo,
  () -> complete("logged")));
// tests:
testRoute(route).run(HttpRequest.GET("/")).assertEntity("logged");

Building Advanced Directives

This example will showcase the advanced logging using the DebuggingDirectivesDebuggingDirectives. The built logResponseTime directive will log the request time (or rejection reason):

Scala
source
def akkaResponseTimeLoggingFunction( loggingAdapter: LoggingAdapter, requestTimestamp: Long, level: LogLevel = Logging.InfoLevel)(req: HttpRequest)(res: RouteResult): Unit = { val entry = res match { case Complete(resp) => val responseTimestamp: Long = System.nanoTime val elapsedTime: Long = (responseTimestamp - requestTimestamp) / 1000000 val loggingString = s"""Logged Request:${req.method}:${req.uri}:${resp.status}:$elapsedTime""" LogEntry(loggingString, level) case Rejected(reason) => LogEntry(s"Rejected Reason: ${reason.mkString(",")}", level) } entry.logTo(loggingAdapter) } def printResponseTime(log: LoggingAdapter) = { val requestTimestamp = System.nanoTime akkaResponseTimeLoggingFunction(log, requestTimestamp)_ } val logResponseTime = DebuggingDirectives.logRequestResult(LoggingMagnet(printResponseTime)) Get("/") ~> logResponseTime(complete("logged")) ~> check { responseAs[String] shouldEqual "logged" }
Java
source// using logRequestResultOptional for generating Response Time
// handle request to optionally generate a log entry
BiFunction<HttpRequest, HttpResponse, Optional<LogEntry>> requestMethodAsInfo() {
  Long requestTime = System.nanoTime();
  return new BiFunction<HttpRequest, HttpResponse, Optional<LogEntry>>() {
    @Override
    public Optional<LogEntry> apply(HttpRequest request, HttpResponse response) {
      return printResponseTime(request, response, requestTime);
    }
  };
}

@Test
public void testLogRequestResultWithResponseTime() {
  // handle rejections to optionally generate a log entry
  BiFunction<HttpRequest, List<Rejection>, Optional<LogEntry>> rejectionsAsInfo =
    (request, rejections) ->
      (!rejections.isEmpty()) ?
        Optional.of(
          LogEntry.create(
            rejections
              .stream()
              .map(Rejection::toString)
              .collect(Collectors.joining(", ")),
            InfoLevel()))
        : Optional.empty(); // no rejections

  final Route route = get(() -> logRequestResultOptional(
    requestMethodAsInfo(),
    rejectionsAsInfo,
    () -> complete("logged")));
  // tests:
  testRoute(route).run(HttpRequest.GET("/")).assertEntity("logged");
Found an error in this documentation? The source code for this page can be found here. Please feel free to edit and contribute a pull request.