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 LoggingAdapter
of the RequestContext
.
This directive is a combination of logRequest and logResult.
See logRequest for the general description how these directives work.
Example¶
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"
}
sourceimport static org.apache.pekko.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 DebuggingDirectives
. The built logResponseTime directive will log the request time (or rejection reason):
source
def pekkoResponseTimeLoggingFunction(
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
pekkoResponseTimeLoggingFunction(log, requestTimestamp) _
}
val logResponseTime = DebuggingDirectives.logRequestResult(LoggingMagnet(printResponseTime))
Get("/") ~> logResponseTime(complete("logged")) ~> check {
responseAs[String] shouldEqual "logged"
}
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");
1.0.1