All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ovoenergy.natchez.extras.http4s.server.TraceMiddleware.scala Maven / Gradle / Ivy

The newest version!
package com.ovoenergy.natchez.extras.http4s.server

import cats.data.Kleisli
import cats.effect.Sync
import cats.~>
import natchez._
import org.http4s._
import cats.syntax.flatMap._
import cats.syntax.functor._
import com.ovoenergy.natchez.extras.http4s.Configuration
import org.http4s.Uri

object TraceMiddleware {

  /**
   * Given a URI produce its path but with any segments containing only two or more numbers
   * replace with an underscore. This is to stop things like Account IDs showing up in URLs
   */
  def removeNumericPathSegments(uri: Uri): String =
    uri.path.renderString.replaceAll("(^|/)[^/]*[0-9]{2,}[^/]*", "$1_")

  private def runTracing[F[_]](s: Span[F]): Kleisli[F, Span[F], *] ~> F =
    new (Kleisli[F, Span[F], *] ~> F) { def apply[A](a: Kleisli[F, Span[F], A]): F[A] = a.run(s) }

  /**
   * Wrap the given traced HTTP4s routes and upon receiving requests
   * create a new trace and pass the root span to the routes
   */
  def apply[F[_]](
    entryPoint: EntryPoint[F],
    configuration: Configuration[F]
  )(
    service: HttpApp[Kleisli[F, Span[F], *]],
    redactSensitiveData: Uri => String = removeNumericPathSegments
  )(implicit F: Sync[F]): HttpApp[F] =
    Kleisli { r =>
      val spanName = s"http.request:${redactSensitiveData(r.uri)}"
      val kernel = Kernel(r.headers.headers.map(h => h.name -> h.value).toMap)
      val traceRequest = r.mapK(Kleisli.liftK[F, Span[F]])

      entryPoint
        .continueOrElseRoot(spanName, kernel)
        .use { span =>
          for {
            reqTags    <- configuration.request.value.run(r)
            _          <- span.put(reqTags.toSeq: _*)
            tracedResp <- service.run(traceRequest).run(span)
            response = tracedResp.mapK(runTracing(span))
            respTags <- configuration.response.value.run(response)
            _        <- span.put(respTags.toSeq: _*)
          } yield response
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy