Skip to content

Commit

Permalink
Add Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherDavenport committed Jul 7, 2023
1 parent a85fefe commit 27aaebd
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 22 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ lazy val core = crossProject(JVMPlatform, JSPlatform)
"org.typelevel" %%% "log4cats-core" % "2.6.0",

"org.typelevel" %%% "munit-cats-effect" % munitCatsEffectV % Test,
"org.typelevel" %%% "log4cats-testing" % "2.6.0" % Test,

)
).jsSettings(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ object ServerMiddleware {
def withAdditionalResponseContext(responseAdditionalContext: ResponsePrelude => Map[String, String]) =
copy(responseAdditionalContext = responseAdditionalContext)

def withLogRequestBody(boolean: Boolean) =
copy(requestLogBody = boolean)
def withLogResponseBody(boolean: Boolean) =
copy(responseLogBody = boolean)

def withRequestBodyMaxSize(l: Long) =
copy(requestBodyMaxSize = l)
def withResponseBodyMaxSize(l: Long) =
copy(responseBodyMaxSize = l)

def withLogLevel(logLevel: (RequestPrelude, Outcome[Option, Throwable, ResponsePrelude]) => LogLevel) =
copy(logLevel = logLevel)
def withLogMessage(logMessage: (RequestPrelude, Outcome[Option, Throwable, ResponsePrelude], FiniteDuration) => String) =
Expand Down Expand Up @@ -210,16 +220,15 @@ object ServerMiddleware {
reqBodyS <- reqBodyFinal.traverse(chunk => logBody(req.withBodyStream(fs2.Stream.chunk(chunk))))
respBodyFinal <- respBody.get
respBodyS <- respBodyFinal.traverse(chunk => logBody(resp.withBodyStream(fs2.Stream.chunk(chunk))))
} yield {
val duration = "http.duration_ms" -> end.minus(start).toMillis.toString()
val requestBodyCtx = reqBodyS.map(body => Map("http.request.body" -> body)).getOrElse(Map.empty)
val responseCtx = response(resp, respHeaders, responseAdditionalContext)
val responseBodyCtx = respBodyS.map(body => Map("http.response.body" -> body)).getOrElse(Map.empty)
val outcome = Outcome.succeeded[Option, Throwable, ResponsePrelude](resp.responsePrelude.some)
val outcomeCtx = outcomeContext(outcome)
val finalCtx = reqContext ++ responseCtx + outcomeCtx + duration ++ requestBodyCtx ++ responseBodyCtx
logLevelAware(logger, finalCtx, req.requestPrelude, outcome, end, logLevel, logMessage)
}
duration = "http.duration_ms" -> end.minus(start).toMillis.toString()
requestBodyCtx = reqBodyS.map(body => Map("http.request.body" -> body)).getOrElse(Map.empty)
responseCtx = response(resp, respHeaders, responseAdditionalContext)
responseBodyCtx = respBodyS.map(body => Map("http.response.body" -> body)).getOrElse(Map.empty)
outcome = Outcome.succeeded[Option, Throwable, ResponsePrelude](resp.responsePrelude.some)
outcomeCtx = outcomeContext(outcome)
finalCtx = reqContext ++ responseCtx + outcomeCtx + duration ++ requestBodyCtx ++ responseBodyCtx
_ <- logLevelAware(logger, finalCtx, req.requestPrelude, outcome, end, logLevel, logMessage)
} yield ()
}
)
}
Expand Down Expand Up @@ -308,16 +317,15 @@ object ServerMiddleware {
reqBodyS <- reqBodyFinal.traverse(chunk => logBody(req.withBodyStream(fs2.Stream.chunk(chunk))))
respBodyFinal <- respBody.get
respBodyS <- respBodyFinal.traverse(chunk => logBody(resp.withBodyStream(fs2.Stream.chunk(chunk))))
} yield {
val duration = "http.duration_ms" -> end.minus(start).toMillis.toString()
val requestBodyCtx = reqBodyS.map(body => Map("http.request.body" -> body)).getOrElse(Map.empty)
val responseCtx = response(resp, respHeaders, responseAdditionalContext)
val responseBodyCtx = respBodyS.map(body => Map("http.response.body" -> body)).getOrElse(Map.empty)
val outcome = Outcome.succeeded[Option, Throwable, ResponsePrelude](resp.responsePrelude.some)
val outcomeCtx = outcomeContext(outcome)
val finalCtx = reqContext ++ responseCtx + outcomeCtx + duration ++ requestBodyCtx ++ responseBodyCtx
logLevelAware(logger, finalCtx, req.requestPrelude, outcome, end, logLevel, logMessage)
}
duration = "http.duration_ms" -> end.minus(start).toMillis.toString()
requestBodyCtx = reqBodyS.map(body => Map("http.request.body" -> body)).getOrElse(Map.empty)
responseCtx = response(resp, respHeaders, responseAdditionalContext)
responseBodyCtx = respBodyS.map(body => Map("http.response.body" -> body)).getOrElse(Map.empty)
outcome = Outcome.succeeded[Option, Throwable, ResponsePrelude](resp.responsePrelude.some)
outcomeCtx = outcomeContext(outcome)
finalCtx = reqContext ++ responseCtx + outcomeCtx + duration ++ requestBodyCtx ++ responseBodyCtx
_ <- logLevelAware(logger, finalCtx, req.requestPrelude, outcome, end, logLevel, logMessage)
} yield ()
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,105 @@ package io.chrisdavenport.http4s.log4cats

import munit.CatsEffectSuite
import cats.effect._
import cats.syntax.all._
import org.http4s._
import org.typelevel.log4cats.testing.StructuredTestingLogger
import org.typelevel.log4cats.extras._
import org.typelevel.log4cats.testing.StructuredTestingLogger.TRACE
import org.typelevel.log4cats.testing.StructuredTestingLogger.DEBUG
import org.typelevel.log4cats.testing.StructuredTestingLogger.INFO
import org.typelevel.log4cats.testing.StructuredTestingLogger.WARN
import org.typelevel.log4cats.testing.StructuredTestingLogger.ERROR

class MainSpec extends CatsEffectSuite {

test("Main should exit succesfully") {
assertEquals(ExitCode.Success, ExitCode.Success)
test("Successfully Create a Context Log") {
val logger = StructuredTestingLogger.impl[IO]()

val server = HttpRoutes.of[IO]{
case _ => Response(Status.Ok).pure[IO]
}.orNotFound

val builder = ServerMiddleware.fromLogger(logger)

val finalApp = builder.httpApp(server)

(finalApp.run(Request[IO](Method.GET)) *> logger.logged).map{
logged =>
assertEquals(
logged.map(removeDuration),
Vector(
INFO(
"Http Server - GET",
None,
Map(

"http.target" -> "/",
"exit.case" -> "succeeded",
"http.method" -> "GET",

"http.status_code" -> "200",

"http.host" -> "localhost",
"http.flavor" -> "1.1",
"http.url" -> "/"
)
)
))
}
}

test("Successfully Create a Context Log with Body") {
val logger = StructuredTestingLogger.impl[IO]()

val server = HttpRoutes.of[IO]{
case req => req.body.compile.drain >> Response[IO](Status.Ok).withEntity("Hello from Response!").pure[IO]
}.orNotFound

val builder = ServerMiddleware.fromLogger(logger)
.withLogRequestBody(true)
.withLogResponseBody(true)

val finalApp = builder.httpApp(server)
val request = Request[IO](Method.GET).withEntity("Hello from Request!")

(finalApp.run(request).flatMap(_.body.compile.drain) *> logger.logged).map{
logged =>
assertEquals(
logged.map(removeDuration),
Vector(
INFO(
"Http Server - GET",
None,
Map(
"http.response.header.content-length" -> "20",
"http.target" -> "/",
"exit.case" -> "succeeded",
"http.method" -> "GET",
"http.request_content_length" -> "19",
"http.status_code" -> "200",
"http.request.body" -> "Hello from Request!",
"http.response.body" -> "Hello from Response!",
"http.request.header.content-length" -> "19",
"http.request.header.content-type" -> "text/plain; charset=UTF-8",
"http.response.header.content-type" -> "text/plain; charset=UTF-8",
"http.response_content_length" -> "20",
"http.host" -> "localhost",
"http.flavor" -> "1.1",
"http.url" -> "/"
)
)
))
}
}

def removeDuration(lm: StructuredTestingLogger.LogMessage): StructuredTestingLogger.LogMessage = lm match {
case TRACE(message, throwOpt, ctx) => TRACE(message, throwOpt, ctx - "http.duration_ms")
case DEBUG(message, throwOpt, ctx) => DEBUG(message, throwOpt, ctx - "http.duration_ms")
case INFO(message, throwOpt, ctx) => INFO(message, throwOpt, ctx - "http.duration_ms")
case WARN(message, throwOpt, ctx) => WARN(message, throwOpt, ctx - "http.duration_ms")
case ERROR(message, throwOpt, ctx) => ERROR(message, throwOpt, ctx - "http.duration_ms")
}


}

0 comments on commit 27aaebd

Please sign in to comment.