Skip to content

Instantly share code, notes, and snippets.

@calvinlfer
Created February 17, 2023 19:42
Show Gist options
  • Save calvinlfer/a1f1ea2af83ae3955b1b4a51f5565f6d to your computer and use it in GitHub Desktop.
Save calvinlfer/a1f1ea2af83ae3955b1b4a51f5565f6d to your computer and use it in GitHub Desktop.
getting tracing to work with zio-http 0.0.4's new Handler abstraction
package io.kaizensolutions.trace4cats.zio.extras.ziohttp.server
import trace4cats.ErrorHandler
import trace4cats.model.AttributeValue.{LongValue, StringValue}
import trace4cats.model.SemanticAttributeKeys.*
import trace4cats.model.{AttributeValue, SpanKind, SpanStatus}
import io.kaizensolutions.trace4cats.zio.extras.ZTracer
import io.kaizensolutions.trace4cats.zio.extras.ziohttp.{extractTraceHeaders, toSpanStatus}
import zio.*
import zio.http.*
import zio.http.model.*
import zio.http.model.Headers.Header
object ZioHttpServerTracer {
type SpanNamer = Request => String
def traceMiddleware(
dropHeadersWhen: String => Boolean = SensitiveHeaders.contains,
spanNamer: SpanNamer = req => s"${req.method.toString()} ${req.url.path.toString()}",
errorHandler: ErrorHandler = ErrorHandler.empty
): HttpAppMiddleware[ZTracer, Nothing] =
new HttpAppMiddleware[ZTracer, Nothing] {
override def apply[R1 <: ZTracer, Err1 >: Nothing](
http: Http[R1, Err1, Request, Response]
)(implicit trace: Trace): Http[R1, Err1, Request, Response] =
Http.fromOptionalHandlerZIO[Request] { request =>
val reqFields = requestFields(request, dropHeadersWhen)
val traceHeaders = extractTraceHeaders(request.headers)
val nameOfSpan = spanNamer(request)
http
.runHandler(request)
.mapError(Option(_))
.flatMap {
case Some(handler) =>
ZIO.succeed(
Handler.fromZIO(
ZIO.serviceWithZIO[ZTracer](
_.fromHeaders(traceHeaders, nameOfSpan, SpanKind.Server, errorHandler) { span =>
span.putAll(reqFields*) *>
handler.runZIO(request).onExit {
case Exit.Success(response) =>
span.putAll(responseFields(response, dropHeadersWhen)*) *>
span.setStatus(toSpanStatus(response.status))
case Exit.Failure(cause) =>
span.setStatus(SpanStatus.Internal(cause.prettyPrint))
}
}
)
)
)
case None =>
ZIO.fail(None)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment