一个日志Akka HTTP客户端请求如何 [英] How does one log Akka HTTP client requests

查看:106
本文介绍了一个日志Akka HTTP客户端请求如何的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要记录akka http客户端请求及其响应。尽管似乎有用于记录这些请求的API提示,但是没有明确的文档说明如何完成这些请求。我的方法是创建一个记录请求,该请求透明地包装 Http()。singleRequest(req)如下:

I need to log akka http client requests as well as their responses. While there seems to be a hint of API for logging these requests, there is no clear documentation on how it should be done. My approach has been to create a logged request which transparently wraps Http().singleRequest(req) as follows:

def loggedRequest(req: HttpRequest)
                  (implicit system: ActorSystem, ctx: ExecutionContext, m: Materializer): Future[HttpResponse] = {

  Http().singleRequest(req).map { resp ⇒
    Unmarshal(resp.entity).to[String].foreach{s ⇒
      system.log.info(req.toString)
      system.log.info(resp.toString + "\n" + s)
    }
    resp
  }
}

不幸的是,我必须通过取消编组或简单地请求 resp.entity.dataBytes 以恢复正文的响应。我得到了日志记录,但是诺言完成了,我再也无法将实体解组到实际数据了。一个有效的解决方案将记录请求和响应,并通过此测试用例,而不会抛出 IllegalStateException 且抛出承诺已完成的情况:

Unfortunately, I have to grab the future either through the unmarshal or by simply requesting resp.entity.dataBytes in order to recover the body of the response. I get the logging but the promise gets completed and I can no longer unmarshal the entity to the actual data. A working solution would log the request and response and pass this test case without an IllegalStateException with "Promise already completed" being thrown:

describe("Logged rest requests") {

  it("deliver typed responses") {
    val foo = Rest.loggedRequest(Get(s"http://127.0.0.1:9000/some/path"))
    val resp = foo.futureValue(patience)
    resp.status shouldBe StatusCodes.OK
    val res = Unmarshal(resp.entity).to[MyClass].futureValue
  }
}

欢迎想法。

推荐答案

我发现的解决方案之一是使用:

One of the solution I've found is to use a:

import akka.http.scaladsl.server.directives.DebuggingDirectives

val clientRouteLogged = DebuggingDirectives.logRequestResult("Client ReST", Logging.InfoLevel)(clientRoute)
Http().bindAndHandle(clientRouteLogged, interface, port)

哪个可以轻松记录搜寻并以原始(位元组)格式显示结果。问题在于这些日志是完全不可读的。在这里变得复杂起来。

Which can easily log the request and result in raw(bytes) format. The problem is that those logs are completely unreadable. And here is place where it became complicated.

这里是我的示例,该示例对请求/响应的实体进行编码并将其写入记录器。

Here is my example that encode the entity of the request/response and write it to the logger.

您可以将函数传递给:

DebuggingDirectives.logRequestResult

def logRequestResult(magnet: LoggingMagnet[HttpRequest ⇒ RouteResult ⇒ Unit])

那是使用磁铁模式编写的函数:

LoggingMagnet[HttpRequest ⇒ RouteResult ⇒ Unit]

位置:

LoggingMagnet[T](f: LoggingAdapter ⇒ T)

感谢我们可以访问记录请求和结果所需的所有部分。我们有LoggingAdapter,HttpRequest和RouteResult

Thanks to that we have access to all parts that we need to log the request and result. We have LoggingAdapter, HttpRequest and RouteResult

对于我来说,我已经创建了一个内部函数。我不想再次传递所有参数。

In my case I've create an inside function. I don't want to pass all the parameters again.

def logRequestResult(level: LogLevel, route: Route)
                      (implicit m: Materializer, ex: ExecutionContext) = {
  def myLoggingFunction(logger: LoggingAdapter)(req: HttpRequest)(res: Any): Unit = {
    val entry = res match {
      case Complete(resp) =>
        entityAsString(resp.entity).map(data ⇒ LogEntry(s"${req.method} ${req.uri}: ${resp.status} \n entity: $data", level))
      case other =>
        Future.successful(LogEntry(s"$other", level))
    }
    entry.map(_.logTo(logger))
  }
  DebuggingDirectives.logRequestResult(LoggingMagnet(log => myLoggingFunction(log)))(route)
}

最重要的部分是我将myLoggingFunction放入logRequestResult的最后一行。

The most important part is the last line where I put myLoggingFunction in to logRequestResult.

名为myLoggingFunction的函数可以简单地匹配服务器计算的结果,并根据该结果创建一个LogEntry。

The function called myLoggingFunction, simple matched the result of server computation and create a LogEntry based on it.

最后一件事是一种允许从流中解码结果实体的方法。

The last thing is a method that allows to decode the result entity from a stream.

def entityAsString(entity: HttpEntity)
                   (implicit m: Materializer, ex: ExecutionContext): Future[String] = {
entity.dataBytes
  .map(_.decodeString(entity.contentType().charset().value))
  .runWith(Sink.head)
}

该方法很容易

val myLoggedRoute = logRequestResult(Logging.InfoLevel, clinetRoute)
Http().bindAndHandle(myLoggedRoute, interface, port)

这篇关于一个日志Akka HTTP客户端请求如何的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆