From 669143ffe5744f299ccd6758d7aa65744062ac25 Mon Sep 17 00:00:00 2001 From: Arthur Sengileyev Date: Wed, 31 Mar 2021 00:53:55 +0300 Subject: [PATCH] Migration to cats-effect 3.0 --- build.sbt | 18 ++--- .../epimetheus/http4s/EpimetheusOps.scala | 7 +- .../epimetheus/http4s/Scraper.scala | 71 +++++++++++++++++-- project/build.properties | 2 +- project/plugins.sbt | 4 +- .../http4s/pushgateway/PushGateway.scala | 10 +-- 6 files changed, 87 insertions(+), 25 deletions(-) diff --git a/build.sbt b/build.sbt index 0a10b4f..44c74a1 100644 --- a/build.sbt +++ b/build.sbt @@ -31,26 +31,26 @@ lazy val contributors = Seq( "ChristopherDavenport" -> "Christopher Davenport" ) -val catsV = "2.1.1" -val catsEffectV = "2.1.4" +val catsV = "2.6.1" +val catsEffectV = "3.1.1" val shapelessV = "2.3.3" -val fs2V = "2.4.6" -val http4sV = "0.21.18" +val fs2V = "3.0.4" +val http4sV = "1.0.0-M23" -lazy val epimetheusV = "0.4.0" +lazy val epimetheusV = "0.5.0-M1" val specs2V = "4.10.6" -val kindProjectorV = "0.11.3" +val kindProjectorV = "0.13.0" val betterMonadicForV = "0.3.1" // General Settings lazy val commonSettings = Seq( organization := "io.chrisdavenport", - scalaVersion := "2.13.1", - crossScalaVersions := Seq(scalaVersion.value, "2.12.10"), + scalaVersion := "2.13.6", + crossScalaVersions := Seq(scalaVersion.value, "2.12.14"), scalacOptions in (Compile, doc) ++= Seq( "-groups", @@ -193,7 +193,7 @@ lazy val micrositeSettings = { "-Ywarn-unused:imports", "-Xlint:-missing-interpolator,_" ), - libraryDependencies += "com.47deg" %% "github4s" % "0.20.1", + libraryDependencies += "com.47deg" %% "github4s" % "0.28.1", micrositePushSiteWith := GitHub4s, micrositeGithubToken := sys.env.get("GITHUB_TOKEN"), micrositeExtraMdFiles := Map( diff --git a/core/src/main/scala/io/chrisdavenport/epimetheus/http4s/EpimetheusOps.scala b/core/src/main/scala/io/chrisdavenport/epimetheus/http4s/EpimetheusOps.scala index 8c6a37b..fbf6e20 100644 --- a/core/src/main/scala/io/chrisdavenport/epimetheus/http4s/EpimetheusOps.scala +++ b/core/src/main/scala/io/chrisdavenport/epimetheus/http4s/EpimetheusOps.scala @@ -6,7 +6,7 @@ import cats.effect._ import org.http4s.{Method, Status} import org.http4s.metrics.MetricsOps import org.http4s.metrics.TerminationType -import org.http4s.metrics.TerminationType.{Abnormal, Error, Timeout} +import org.http4s.metrics.TerminationType.{Abnormal, Canceled, Error, Timeout} import shapeless._ import io.chrisdavenport.epimetheus._ @@ -215,8 +215,9 @@ object EpimetheusOps { def secondaryReportMethod(m: Method): String = m.name.toLowerCase() private def reportTermination(t: TerminationType): String = t match { - case Abnormal => "abnormal" - case Error => "error" + case Abnormal(_) => "abnormal" + case Error(_) => "error" + case Canceled => "canceled" case Timeout => "timeout" } diff --git a/core/src/main/scala/io/chrisdavenport/epimetheus/http4s/Scraper.scala b/core/src/main/scala/io/chrisdavenport/epimetheus/http4s/Scraper.scala index c1dec73..e60a536 100644 --- a/core/src/main/scala/io/chrisdavenport/epimetheus/http4s/Scraper.scala +++ b/core/src/main/scala/io/chrisdavenport/epimetheus/http4s/Scraper.scala @@ -2,20 +2,81 @@ package io.chrisdavenport.epimetheus.http4s import cats._ import cats.implicits._ -import cats.effect._ import org.http4s._ import org.http4s.dsl.Http4sDsl import io.chrisdavenport.epimetheus.CollectorRegistry +import io.prometheus.client.exporter.common.TextFormat +import org.http4s.Header.Raw +import org.typelevel.ci.CIString object Scraper { - def response[F[_]: Functor](cr: CollectorRegistry[F]): F[Response[F]] = - cr.write004.map(Response[F](Status.Ok).withEntity(_)) + lazy val prometheusContentTypeHeader = Raw(CIString("Content-Type"), TextFormat.CONTENT_TYPE_004) + lazy val openMetricsContentTypeHeader = Raw(CIString("Content-Type"), TextFormat.CONTENT_TYPE_OPENMETRICS_100) - def routes[F[_]: Sync](cr: CollectorRegistry[F]): HttpRoutes[F] = { + private def makeResponse004[F[_], T](b: T)(implicit w: EntityEncoder[F, T]) = + Response[F](Status.Ok).withEntity(b).putHeaders(prometheusContentTypeHeader) + + def response004[F[_]: Functor](cr: CollectorRegistry[F]): F[Response[F]] = + cr.write004.map(makeResponse004(_)) + + def response004[F[_]: Applicative, T[_]: Foldable](c: T[CollectorRegistry[F]]): F[Response[F]] = + c.foldMapA(_.write004).map(makeResponse004(_)) + + def responsePar004[F[_]: Applicative: Parallel, T[_]: Foldable](c: T[CollectorRegistry[F]]): F[Response[F]] = + c.parFoldMapA(_.write004).map(makeResponse004(_)) + + def routes004[F[_]: Monad](cr: CollectorRegistry[F]): HttpRoutes[F] = { + val dsl = new Http4sDsl[F]{}; import dsl._ + HttpRoutes.of[F] { + case GET -> Root / "metrics" => response004(cr) + } + } + + def routes004[F[_]: Monad, T[_]: Foldable](c: T[CollectorRegistry[F]]): HttpRoutes[F] = { + val dsl = new Http4sDsl[F]{}; import dsl._ + HttpRoutes.of[F] { + case GET -> Root / "metrics" => response004(c) + } + } + + def routesPar004[F[_]: Monad: Parallel, T[_]: Foldable](c: T[CollectorRegistry[F]]): HttpRoutes[F] = { + val dsl = new Http4sDsl[F]{}; import dsl._ + HttpRoutes.of[F] { + case GET -> Root / "metrics" => responsePar004(c) + } + } + + private def makeResponseOpenMetrics100[F[_], T](b: T)(implicit w: EntityEncoder[F, T]) = + Response[F](Status.Ok).withEntity(b).putHeaders(openMetricsContentTypeHeader) + + def responseOpenMetrics100[F[_]: Functor](cr: CollectorRegistry[F]): F[Response[F]] = + cr.writeOpenMetrics100.map(makeResponseOpenMetrics100(_)) + + def responseOpenMetrics100[F[_]: Applicative, T[_]: Foldable](c: T[CollectorRegistry[F]]): F[Response[F]] = + c.foldMapA(_.writeOpenMetrics100).map(makeResponseOpenMetrics100(_)) + + def responseParOpenMetrics100[F[_]: Applicative: Parallel, T[_]: Foldable](c: T[CollectorRegistry[F]]): F[Response[F]] = + c.parFoldMapA(_.write004).map(makeResponseOpenMetrics100(_)) + + def routesOpenMetrics100[F[_]: Monad](cr: CollectorRegistry[F]): HttpRoutes[F] = { + val dsl = new Http4sDsl[F]{}; import dsl._ + HttpRoutes.of[F] { + case GET -> Root / "metrics" => responseOpenMetrics100(cr) + } + } + + def routesOpenMetrics100[F[_]: Monad, T[_]: Foldable](c: T[CollectorRegistry[F]]): HttpRoutes[F] = { + val dsl = new Http4sDsl[F]{}; import dsl._ + HttpRoutes.of[F] { + case GET -> Root / "metrics" => responseOpenMetrics100(c) + } + } + + def routesParOpenMetrics100[F[_]: Monad: Parallel, T[_]: Foldable](c: T[CollectorRegistry[F]]): HttpRoutes[F] = { val dsl = new Http4sDsl[F]{}; import dsl._ HttpRoutes.of[F] { - case GET -> Root / "metrics" => response(cr) + case GET -> Root / "metrics" => responseParOpenMetrics100(c) } } } \ No newline at end of file diff --git a/project/build.properties b/project/build.properties index 0837f7a..dbae93b 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.13 +sbt.version=1.4.9 diff --git a/project/plugins.sbt b/project/plugins.sbt index de348d5..d8dff89 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -3,6 +3,6 @@ addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.7.0") addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.6.13") addSbtPlugin("com.47deg" % "sbt-microsites" % "0.9.7") addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.3") -addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "0.6.1") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.1.1") +addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.5.0") addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.5") \ No newline at end of file diff --git a/pushgateway/src/main/scala/io/chrisdavenport/epimetheus/http4s/pushgateway/PushGateway.scala b/pushgateway/src/main/scala/io/chrisdavenport/epimetheus/http4s/pushgateway/PushGateway.scala index 8cc8084..178c924 100644 --- a/pushgateway/src/main/scala/io/chrisdavenport/epimetheus/http4s/pushgateway/PushGateway.scala +++ b/pushgateway/src/main/scala/io/chrisdavenport/epimetheus/http4s/pushgateway/PushGateway.scala @@ -21,11 +21,11 @@ abstract class PushGateway[F[_]]{ object PushGateway { - def fromClient[F[_]: Sync](c: Client[F], serverUri: Uri): PushGateway[F] = + def fromClient[F[_]: Async](c: Client[F], serverUri: Uri): PushGateway[F] = new BasicPushGateway[F](c, serverUri) - private class BasicPushGateway[F[_]: Sync](val client: Client[F], uri: Uri) extends PushGateway[F]{ + private class BasicPushGateway[F[_]: Async](val client: Client[F], uri: Uri) extends PushGateway[F]{ def push(cr: CollectorRegistry[F], job: String): F[Unit] = push(cr, job, Map.empty) def push(cr: CollectorRegistry[F], job: String, groupingKey: Map[String, String]): F[Unit] = @@ -52,7 +52,7 @@ object PushGateway { private def requestUrl(baseUri: Uri, job: String, groupingKey: Map[String, String]): Uri = groupingKey.toList.foldLeft(baseUri / "metrics" / "job" / job){ case (next, (k, v)) => next / k / v } - private def doDelete[F[_]: Sync]( + private def doDelete[F[_]: Async]( client: Client[F], baseUri: Uri, job: String, @@ -62,7 +62,7 @@ object PushGateway { client.expectOr[Unit](Request[F](Method.DELETE, uri))(errorHandler(uri)) } - private def doPost[F[_]: Sync]( + private def doPost[F[_]: Async]( client: Client[F], baseUri: Uri, job: String, @@ -75,7 +75,7 @@ object PushGateway { } } - private def doPut[F[_]: Sync]( + private def doPut[F[_]: Async]( client: Client[F], baseUri: Uri, job: String,