aboutsummaryrefslogblamecommitdiff
path: root/kamon-core/src/main/scala/kamon/http/HttpServerMetrics.scala
blob: dfa4bcb817066b3fc196d4ce51b5f40c102507e3 (plain) (tree)



















































































                                                                                                                              

                                            
 







                                                                              

 
package kamon.http

import akka.actor.ActorSystem
import com.typesafe.config.Config
import kamon.metric.instrument.Counter
import kamon.metric._

import scala.collection.concurrent.TrieMap

object HttpServerMetrics extends MetricGroupIdentity {
  val name: String = "http-server-metrics-recorder"
  val category = new MetricGroupCategory {
    val name: String = "http-server"
  }

  type TraceName = String
  type StatusCode = String

  case class CountPerStatusCode(statusCode: String) extends MetricIdentity {
    def name: String = statusCode
  }

  case class TraceCountPerStatus(traceName: TraceName, statusCode: StatusCode) extends MetricIdentity {
    def name: String = traceName + "_" + statusCode
  }

  class HttpServerMetricsRecorder extends MetricGroupRecorder {

    private val counters = TrieMap[StatusCode, Counter]()
    private val countersPerTrace = TrieMap[TraceName, TrieMap[StatusCode, Counter]]()

    def recordResponse(statusCode: StatusCode): Unit = recordResponse(statusCode, 1L)

    def recordResponse(statusCode: StatusCode, count: Long): Unit =
      counters.getOrElseUpdate(statusCode, Counter()).increment(count)

    def recordResponse(traceName: TraceName, statusCode: StatusCode): Unit = recordResponse(traceName, statusCode, 1L)

    def recordResponse(traceName: TraceName, statusCode: StatusCode, count: Long): Unit = {
      recordResponse(statusCode, count)
      countersPerTrace.getOrElseUpdate(traceName, TrieMap()).getOrElseUpdate(statusCode, Counter()).increment(count)
    }

    def collect(context: CollectionContext): HttpServerMetricsSnapshot = {
      val countsPerStatusCode = counters.map {
        case (statusCode, counter)  (statusCode, counter.collect(context))
      }.toMap

      val countsPerTraceAndStatus = countersPerTrace.map {
        case (traceName, countsPerStatus) 
          (traceName, countsPerStatus.map { case (statusCode, counter)  (statusCode, counter.collect(context)) }.toMap)
      }.toMap

      HttpServerMetricsSnapshot(countsPerStatusCode, countsPerTraceAndStatus)
    }

    def cleanup: Unit = {}
  }

  case class HttpServerMetricsSnapshot(countsPerStatusCode: Map[StatusCode, Counter.Snapshot],
      countsPerTraceAndStatusCode: Map[TraceName, Map[StatusCode, Counter.Snapshot]]) extends MetricGroupSnapshot {

    type GroupSnapshotType = HttpServerMetricsSnapshot

    def merge(that: HttpServerMetricsSnapshot, context: CollectionContext): HttpServerMetricsSnapshot = {
      val combinedCountsPerStatus = combineMaps(countsPerStatusCode, that.countsPerStatusCode)((l, r)  l.merge(r, context))
      val combinedCountsPerTraceAndStatus = combineMaps(countsPerTraceAndStatusCode, that.countsPerTraceAndStatusCode) {
        (leftCounts, rightCounts)  combineMaps(leftCounts, rightCounts)((l, r)  l.merge(r, context))
      }
      HttpServerMetricsSnapshot(combinedCountsPerStatus, combinedCountsPerTraceAndStatus)
    }

    def metrics: Map[MetricIdentity, MetricSnapshot] = {
      countsPerStatusCode.map {
        case (statusCode, count)  (CountPerStatusCode(statusCode), count)
      } ++ {
        for (
          (traceName, countsPerStatus)  countsPerTraceAndStatusCode;
          (statusCode, count)  countsPerStatus
        ) yield (TraceCountPerStatus(traceName, statusCode), count)
      }
    }
  }

  val Factory = HttpServerMetricGroupFactory
}

case object HttpServerMetricGroupFactory extends MetricGroupFactory {

  import HttpServerMetrics._

  type GroupRecorder = HttpServerMetricsRecorder

  def create(config: Config, system: ActorSystem): HttpServerMetricsRecorder =
    new HttpServerMetricsRecorder()

}