Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ lazy val scache = (project in file("scache"))
ProblemFilters.exclude[MissingClassProblem]("com.evolution.scache.LoadingCache$EntryRefs$"),
ProblemFilters.exclude[MissingClassProblem]("com.evolution.scache.ExpiringCache$MapOps"),
ProblemFilters.exclude[MissingClassProblem]("com.evolution.scache.ExpiringCache$MapOps$"),
// CacheMetrics.load takes LoadResult, reviewed in https://github.com/evolution-gaming/scache/issues/386
ProblemFilters.exclude[ReversedMissingMethodProblem]("com.evolution.scache.CacheMetrics.load"),
),
libraryDependencies ++= Seq(
Cats.core,
Expand Down
12 changes: 7 additions & 5 deletions scache/src/main/scala/com/evolution/scache/CacheMetered.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.evolution.scache

import cats.effect.implicits.*
import cats.effect.{Resource, Temporal}
import cats.kernel.CommutativeMonoid
import cats.syntax.all.*
import com.evolution.scache.Cache.Directive
import com.evolution.scache.CacheMetrics.LoadResult
import com.evolutiongaming.catshelper.{MeasureDuration, Schedule}

import scala.concurrent.duration.*
Expand Down Expand Up @@ -67,13 +69,13 @@ object CacheMetered {
for {
_ <- metrics.get(false)
start <- MeasureDuration[F].start
value <- value.attempt
value <- value.attempt.onCancel { start.flatMap { metrics.load(_, LoadResult.Cancelled) } }
duration <- start
loadSucceed = value match {
case Right(_) | Left(CacheOpsCompat.NoneError) => true
case Left(_) => false
result = value match {
case Right(_) | Left(CacheOpsCompat.NoneError) => LoadResult.Success
case Left(_) => LoadResult.Failure
}
_ <- metrics.load(duration, loadSucceed)
_ <- metrics.load(duration, result)
value <- value.liftTo[F]
} yield {
val (a, v, release) = value
Expand Down
73 changes: 46 additions & 27 deletions scache/src/main/scala/com/evolution/scache/CacheMetrics.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.evolution.scache
import cats.effect.{Concurrent, Ref, Resource}
import cats.syntax.all.*
import cats.{Applicative, Monad}
import com.evolution.scache.CacheMetrics.Directive
import com.evolution.scache.CacheMetrics.{Directive, LoadResult}
import com.evolutiongaming.smetrics.MetricsHelper.*
import com.evolutiongaming.smetrics.{CollectorRegistry, LabelNames, Quantile, Quantiles}

Expand All @@ -14,7 +14,11 @@ trait CacheMetrics[F[_]] {

def get(hit: Boolean): F[Unit]

def load(time: FiniteDuration, success: Boolean): F[Unit]
def load(time: FiniteDuration, result: LoadResult): F[Unit]

@deprecated("use load(time, LoadResult)", "7.0.0")
def load(time: FiniteDuration, success: Boolean): F[Unit] =
load(time, if (success) LoadResult.Success else LoadResult.Failure)

def life(time: FiniteDuration): F[Unit]

Expand Down Expand Up @@ -48,7 +52,7 @@ object CacheMetrics {

def get(hit: Boolean) = unit

def load(time: FiniteDuration, success: Boolean) = unit
def load(time: FiniteDuration, result: LoadResult) = unit

def life(time: FiniteDuration) = unit

Expand Down Expand Up @@ -82,6 +86,25 @@ object CacheMetrics {
case object Remove extends Directive
}

/**
* Outcome of a value computation started by `getOrUpdate`: it produced a value, failed, or was
* cancelled before doing either.
*/
sealed trait LoadResult {
override def toString: Prefix = this match {
case LoadResult.Success => "success"
case LoadResult.Failure => "failure"
case LoadResult.Cancelled => "cancelled"
}
}
object LoadResult {
case object Success extends LoadResult
case object Failure extends LoadResult
case object Cancelled extends LoadResult

val values: List[LoadResult] = List(Success, Failure, Cancelled)
}

type Name = String

type Prefix = String
Expand Down Expand Up @@ -121,7 +144,7 @@ object CacheMetrics {

val loadResultCounter = collectorRegistry.counter(
name = s"${ prefix }_load_result",
help = "Load result: success or failure",
help = "Load result: success, failure or cancelled",
labels = LabelNames("name", "result"),
)

Expand Down Expand Up @@ -176,13 +199,13 @@ object CacheMetrics {

val missCounter = getsCounter.labels(name, "miss")

val successCounter = loadResultCounter.labels(name, "success")

val failureCounter = loadResultCounter.labels(name, "failure")
val loadCounters = LoadResult.values.map { result =>
(result, loadResultCounter.labels(name, result.toString))
}.toMap

val successSummary = loadTimeSummary.labels(name, "success")

val failureSummary = loadTimeSummary.labels(name, "failure")
val loadSummaries = LoadResult.values.map { result =>
(result, loadTimeSummary.labels(name, result.toString))
}.toMap

val putCounter1 = putCounter.labels(name)

Expand All @@ -205,12 +228,10 @@ object CacheMetrics {
counter.inc()
}

def load(time: FiniteDuration, success: Boolean) = {
val resultCounter = if (success) successCounter else failureCounter
val timeSummary = if (success) successSummary else failureSummary
def load(time: FiniteDuration, result: LoadResult) = {
for {
_ <- resultCounter.inc()
_ <- timeSummary.observe(time.toNanos.nanosToSeconds)
_ <- loadCounters(result).inc()
_ <- loadSummaries(result).observe(time.toNanos.nanosToSeconds)
} yield {}
}

Expand Down Expand Up @@ -283,7 +304,7 @@ object CacheMetrics {

val loadResultCounter = collectorRegistry.counter(
name = s"${ prefix }_load_result",
help = "Load result: success or failure",
help = "Load result: success, failure or cancelled",
labels = LabelNames("name", "result"),
)

Expand Down Expand Up @@ -336,13 +357,13 @@ object CacheMetrics {

val missCounter = getsCounter.labels(name, "miss")

val successCounter = loadResultCounter.labels(name, "success")

val failureCounter = loadResultCounter.labels(name, "failure")

val successSummary = loadTimeSummary.labels(name, "success")
val loadCounters = LoadResult.values.map { result =>
(result, loadResultCounter.labels(name, result.toString))
}.toMap

val failureSummary = loadTimeSummary.labels(name, "failure")
val loadSummaries = LoadResult.values.map { result =>
(result, loadTimeSummary.labels(name, result.toString))
}.toMap

val putCounter1 = putCounter.labels(name)

Expand All @@ -365,12 +386,10 @@ object CacheMetrics {
counter.inc()
}

def load(time: FiniteDuration, success: Boolean) = {
val resultCounter = if (success) successCounter else failureCounter
val timeSummary = if (success) successSummary else failureSummary
def load(time: FiniteDuration, result: LoadResult) = {
for {
_ <- resultCounter.inc()
_ <- timeSummary.observe(time.toNanos.nanosToSeconds)
_ <- loadCounters(result).inc()
_ <- loadSummaries(result).observe(time.toNanos.nanosToSeconds)
} yield {}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class CacheMeteredSpec extends AsyncFunSuite with Matchers {

private def sizeRecorder(sizes: Ref[IO, List[Int]]): CacheMetrics[IO] = new CacheMetrics[IO] {
def get(hit: Boolean): IO[Unit] = IO.unit
def load(time: FiniteDuration, success: Boolean): IO[Unit] = IO.unit
def load(time: FiniteDuration, result: CacheMetrics.LoadResult): IO[Unit] = IO.unit
def life(time: FiniteDuration): IO[Unit] = IO.unit
def put: IO[Unit] = IO.unit
def modify(entryExisted: Boolean, directive: CacheMetrics.Directive): IO[Unit] = IO.unit
Expand Down
Loading
Loading