Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust public contract of Logger Middlewares #6927

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,32 @@ object Logger {
)
)

def logBodyText[F[_]: Async](
def logWithEntity[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
logEntity: Entity[F] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = defaultRedactHeadersWhen,
logAction: Option[String => F[Unit]] = None,
)(client: Client[F]): Client[F] =
ResponseLogger.logBodyText(logHeaders, logBody, redactHeadersWhen, logAction)(
RequestLogger.logBodyText(logHeaders, logBody, redactHeadersWhen, logAction)(
ResponseLogger.logWithEntity(logHeaders, logEntity, redactHeadersWhen, logAction)(
RequestLogger.logWithEntity(logHeaders, logEntity, redactHeadersWhen, logAction)(
client
)
)

@deprecated("Use Logger.logWithEntity that utilizes Entity model for a Message body", "1.0.0-M39")
def logBodyText[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = defaultRedactHeadersWhen,
logAction: Option[String => F[Unit]] = None,
)(client: Client[F]): Client[F] =
logWithEntity(
logHeaders,
(entity: Entity[F]) => logBody(entity.body),
redactHeadersWhen,
logAction,
)(client)

def logMessage[F[_]](message: Message[F])(
logHeaders: Boolean,
logBody: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,38 @@ object RequestLogger {
)(logAction.getOrElse(defaultLogAction[F]))
}

def logBodyText[F[_]: Async](
def logWithEntity[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
logEntity: Entity[F] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
logAction: Option[String => F[Unit]] = None,
)(client: Client[F]): Client[F] =
impl(client, logBody = true) { request =>
InternalLogger.logMessageWithBodyText(request)(
InternalLogger.logMessageWithEntity(request)(
logHeaders,
logBody,
logEntity,
logAction.getOrElse(defaultLogAction[F]),
redactHeadersWhen,
)(logAction.getOrElse(defaultLogAction[F]))
)
}

@deprecated(
"Use RequestLogger.logWithEntity that utilizes Entity model for a Message body",
"1.0.0-M39",
)
def logBodyText[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
logAction: Option[String => F[Unit]] = None,
)(client: Client[F]): Client[F] =
logWithEntity(
logHeaders,
(entity: Entity[F]) => logBody(entity.body),
redactHeadersWhen,
logAction,
)(client)

def customized[F[_]: Async](
client: Client[F],
logBody: Boolean = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,38 @@ object ResponseLogger {
)(logAction.getOrElse(defaultLogAction[F]))
}

def logBodyText[F[_]: Async](
def logWithEntity[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
logEntity: Entity[F] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
logAction: Option[String => F[Unit]] = None,
)(client: Client[F]): Client[F] =
impl(client, logBody = true) { response =>
InternalLogger.logMessageWithBodyText(response)(
InternalLogger.logMessageWithEntity(response)(
logHeaders,
logBody,
logEntity,
logAction.getOrElse(defaultLogAction[F]),
redactHeadersWhen,
)(logAction.getOrElse(defaultLogAction[F]))
)
}

@deprecated(
"Use ResponseLogger.logWithEntity that utilizes Entity model for a Message body",
"1.0.0-M39",
)
def logBodyText[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
logAction: Option[String => F[Unit]] = None,
)(client: Client[F]): Client[F] =
logWithEntity(
logHeaders,
(entity: Entity[F]) => logBody(entity.body),
redactHeadersWhen,
logAction,
)(client)

def customized[F[_]: Async](
client: Client[F],
logBody: Boolean = true,
Expand Down
28 changes: 22 additions & 6 deletions core/shared/src/main/scala/org/http4s/internal/Logger.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,17 @@ object Logger {
logBody: Boolean,
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
)(log: String => F[Unit])(implicit F: Concurrent[F]): F[Unit] = {
val logBodyText = (_: Stream[F, Byte]) => defaultLogBody(message)(logBody)
val logBodyText = (_: Entity[F]) => defaultLogBody(message)(logBody)

logMessageWithBodyText(message)(logHeaders, logBodyText, redactHeadersWhen)(log)
logMessageWithEntity(message)(logHeaders, logBodyText, log, redactHeadersWhen)
}

def logMessageWithBodyText[F[_]](message: Message[F])(
def logMessageWithEntity[F[_]](message: Message[F])(
logHeaders: Boolean,
logBodyText: Stream[F, Byte] => Option[F[String]],
logEntity: Entity[F] => Option[F[String]],
log: String => F[Unit],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
)(log: String => F[Unit])(implicit F: Monad[F]): F[Unit] = {
)(implicit F: Monad[F]): F[Unit] = {
def prelude =
message match {
case req: Request[_] => s"${req.httpVersion} ${req.method} ${req.uri}"
Expand All @@ -93,7 +94,7 @@ object Logger {
val headers: String = defaultLogHeaders(message)(logHeaders, redactHeadersWhen)

val bodyText: F[String] =
logBodyText(message.body) match {
logEntity(message.entity) match {
case Some(textF) => textF.map(text => s"""body="$text"""")
case None => F.pure("")
}
Expand All @@ -105,4 +106,19 @@ object Logger {
.flatMap(log)
}

@deprecated(
"Use Logger.logMessageWithEntity that utilizes Entity model for a Message body",
"1.0.0-M39",
)
def logMessageWithBodyText[F[_]](message: Message[F])(
logHeaders: Boolean,
logBodyText: Stream[F, Byte] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
)(log: String => F[Unit])(implicit F: Monad[F]): F[Unit] =
logMessageWithEntity(message)(
logHeaders,
(entity: Entity[F]) => logBodyText(entity.body),
log,
redactHeadersWhen,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,42 @@ object Logger {
)
}

def logBodyText[G[_], F[_]](
def logWithEntity[G[_], F[_]](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
logEntity: Entity[F] => Option[F[String]],
fk: F ~> G,
redactHeadersWhen: CIString => Boolean = defaultRedactHeadersWhen,
logAction: Option[String => F[Unit]] = None,
)(http: Http[G, F])(implicit G: MonadCancelThrow[G], F: Async[F]): Http[G, F] = {
val log: String => F[Unit] = logAction.getOrElse { s =>
logger.info(s).to[F]
}
ResponseLogger.impl(logHeaders, Right(logBody), fk, redactHeadersWhen, log.pure[Option])(
RequestLogger.impl(logHeaders, Right(logBody), fk, redactHeadersWhen, log.pure[Option])(http)
ResponseLogger.impl(logHeaders, Right(logEntity), fk, redactHeadersWhen, log.pure[Option])(
RequestLogger.impl(logHeaders, Right(logEntity), fk, redactHeadersWhen, log.pure[Option])(
http
)
)
}

@deprecated(
"Use Logger.logWithEntity that utilizes Entity model for a Message body",
"1.0.0-M39",
)
def logBodyText[G[_], F[_]](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
fk: F ~> G,
redactHeadersWhen: CIString => Boolean = defaultRedactHeadersWhen,
logAction: Option[String => F[Unit]] = None,
)(http: Http[G, F])(implicit G: MonadCancelThrow[G], F: Async[F]): Http[G, F] =
logWithEntity[G, F](
logHeaders,
(entity: Entity[F]) => logBody(entity.body),
fk,
redactHeadersWhen,
logAction,
)(http)

def httpApp[F[_]: Async](
logHeaders: Boolean,
logBody: Boolean,
Expand All @@ -73,13 +94,30 @@ object Logger {
)(httpApp: HttpApp[F]): HttpApp[F] =
apply(logHeaders, logBody, FunctionK.id[F], redactHeadersWhen, logAction)(httpApp)

def httpAppLogEntity[F[_]: Async](
logHeaders: Boolean,
logEntity: Entity[F] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = defaultRedactHeadersWhen,
logAction: Option[String => F[Unit]] = None,
)(httpApp: HttpApp[F]): HttpApp[F] =
logWithEntity(logHeaders, logEntity, FunctionK.id[F], redactHeadersWhen, logAction)(httpApp)

@deprecated(
"Use Logger.httpAppLogEntity that utilizes Entity model for a Message body",
"1.0.0-M39",
)
def httpAppLogBodyText[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = defaultRedactHeadersWhen,
logAction: Option[String => F[Unit]] = None,
)(httpApp: HttpApp[F]): HttpApp[F] =
logBodyText(logHeaders, logBody, FunctionK.id[F], redactHeadersWhen, logAction)(httpApp)
httpAppLogEntity(
logHeaders,
(entity: Entity[F]) => logBody(entity.body),
redactHeadersWhen,
logAction,
)(httpApp)

def httpRoutes[F[_]: Async](
logHeaders: Boolean,
Expand All @@ -89,13 +127,30 @@ object Logger {
)(httpRoutes: HttpRoutes[F]): HttpRoutes[F] =
apply(logHeaders, logBody, OptionT.liftK[F], redactHeadersWhen, logAction)(httpRoutes)

def httpRoutesLogEntity[F[_]: Async](
logHeaders: Boolean,
logEntity: Entity[F] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = defaultRedactHeadersWhen,
logAction: Option[String => F[Unit]] = None,
)(httpRoutes: HttpRoutes[F]): HttpRoutes[F] =
logWithEntity(logHeaders, logEntity, OptionT.liftK[F], redactHeadersWhen, logAction)(httpRoutes)

@deprecated(
"Use Logger.httpRoutesLogEntity that utilizes Entity model for a Message body",
"1.0.0-M39",
)
def httpRoutesLogBodyText[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = defaultRedactHeadersWhen,
logAction: Option[String => F[Unit]] = None,
)(httpRoutes: HttpRoutes[F]): HttpRoutes[F] =
logBodyText(logHeaders, logBody, OptionT.liftK[F], redactHeadersWhen, logAction)(httpRoutes)
httpRoutesLogEntity(
logHeaders,
(entity: Entity[F]) => logBody(entity.body),
redactHeadersWhen,
logAction,
)(httpRoutes)

def logMessage[F[_], A <: Message[F]](message: A)(
logHeaders: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ object RequestLogger {

private[server] def impl[G[_], F[_]](
logHeaders: Boolean,
logBodyText: Either[Boolean, Stream[F, Byte] => Option[F[String]]],
logBodyText: Either[Boolean, Entity[F] => Option[F[String]]],
fk: F ~> G,
redactHeadersWhen: CIString => Boolean,
logAction: Option[String => F[Unit]],
Expand All @@ -69,7 +69,7 @@ object RequestLogger {
Logger.logMessage[F, Request[F]](r)(logHeaders, bool, redactHeadersWhen)(log(_))
case Right(f) =>
org.http4s.internal.Logger
.logMessageWithBodyText(r)(logHeaders, f, redactHeadersWhen)(log(_))
.logMessageWithEntity(r)(logHeaders, f, log(_), redactHeadersWhen)
}

val logBody: Boolean = logBodyText match {
Expand Down Expand Up @@ -135,25 +135,59 @@ object RequestLogger {
)(httpRoutes: HttpRoutes[F]): HttpRoutes[F] =
apply(logHeaders, logBody, OptionT.liftK[F], redactHeadersWhen, logAction)(httpRoutes)

def httpAppLogEntity[F[_]: Async](
logHeaders: Boolean,
logEntity: Entity[F] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
logAction: Option[String => F[Unit]] = None,
)(httpApp: HttpApp[F]): HttpApp[F] =
impl[F, F](logHeaders, Right(logEntity), FunctionK.id[F], redactHeadersWhen, logAction)(httpApp)

@deprecated(
"Use RequestLogger.httpAppLogEntity that utilizes Entity model for a Message body",
"1.0.0-M39",
)
def httpAppLogBodyText[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
logAction: Option[String => F[Unit]] = None,
)(httpApp: HttpApp[F]): HttpApp[F] =
impl[F, F](logHeaders, Right(logBody), FunctionK.id[F], redactHeadersWhen, logAction)(httpApp)
httpAppLogEntity[F](
logHeaders,
(entity: Entity[F]) => logBody(entity.body),
redactHeadersWhen,
logAction,
)(httpApp)

def httpRoutesLogBodyText[F[_]: Async](
def httpRoutesLogEntity[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
logEntity: Entity[F] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
logAction: Option[String => F[Unit]] = None,
)(httpRoutes: HttpRoutes[F]): HttpRoutes[F] =
impl[OptionT[F, *], F](
logHeaders,
Right(logBody),
Right(logEntity),
OptionT.liftK[F],
redactHeadersWhen,
logAction,
)(httpRoutes)

@deprecated(
"Use RequestLogger.httpRoutesLogEntity that utilizes Entity model for a Message body",
"1.0.0-M39",
)
def httpRoutesLogBodyText[F[_]: Async](
logHeaders: Boolean,
logBody: Stream[F, Byte] => Option[F[String]],
redactHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
logAction: Option[String => F[Unit]] = None,
)(httpRoutes: HttpRoutes[F]): HttpRoutes[F] =
httpRoutesLogEntity[F](
logHeaders,
(entity: Entity[F]) => logBody(entity.body),
redactHeadersWhen,
logAction,
)(httpRoutes)
}