aboutsummaryrefslogtreecommitdiff
path: root/kamon-system-metrics/src
diff options
context:
space:
mode:
authorIvan Topolnjak <ivantopo@gmail.com>2015-01-12 01:45:27 +0100
committerIvan Topolnjak <ivantopo@gmail.com>2015-01-24 23:19:01 +0100
commit01a34f67ff75419c440f2e69c0a0db888a670a34 (patch)
tree9c4dee4e9c13c26937356950f9e4927c3f9dfb7d /kamon-system-metrics/src
parent4a47e92d23af371f1d50b40af6cbe00a5ffc0105 (diff)
downloadKamon-01a34f67ff75419c440f2e69c0a0db888a670a34.tar.gz
Kamon-01a34f67ff75419c440f2e69c0a0db888a670a34.tar.bz2
Kamon-01a34f67ff75419c440f2e69c0a0db888a670a34.zip
! all: improve the metric recorders infrastructure
Diffstat (limited to 'kamon-system-metrics/src')
-rw-r--r--kamon-system-metrics/src/main/resources/reference.conf277
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/CPUMetrics.scala88
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/ClassLoadingMetrics.scala85
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/ContextSwitchesMetrics.scala81
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/DiskMetrics.scala85
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala77
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/HeapMetrics.scala87
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/LoadAverageMetrics.scala80
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/MemoryMetrics.scala92
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/NetworkMetrics.scala91
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/NonHeapMetrics.scala86
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/ProcessCPUMetrics.scala76
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/ThreadMetrics.scala85
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/GcMetricsCollector.scala77
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala78
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsBanner.scala91
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala266
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsExtension.scala70
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala96
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/ClassLoadingMetrics.scala28
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala34
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/HeapMemoryMetrics.scala29
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala13
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/NonHeapMemoryMetrics.scala33
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/ThreadsMetrics.scala28
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/CpuMetrics.scala29
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/DiffRecordingHistogram.scala41
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/FileSystemMetrics.scala25
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/LoadAverageMetrics.scala25
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/MemoryMetrics.scala36
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/NetworkMetrics.scala33
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/ProcessCpuMetrics.scala39
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala59
-rw-r--r--kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala450
34 files changed, 874 insertions, 1996 deletions
diff --git a/kamon-system-metrics/src/main/resources/reference.conf b/kamon-system-metrics/src/main/resources/reference.conf
index ba439024..7f65e477 100644
--- a/kamon-system-metrics/src/main/resources/reference.conf
+++ b/kamon-system-metrics/src/main/resources/reference.conf
@@ -2,129 +2,180 @@
# Kamon-System-Metrics Reference Configuration #
# ============================================ #
-# Sigar provisioner native library extract location.
-# Use per-application-instance scoped location, such as program working directory.
-kamon.sigar.folder = ${user.dir}"/native"
-
kamon {
system-metrics {
- default-gauge-precision {
- refresh-interval = 1 second
- highest-trackable-value = 999999999
- significant-value-digits = 2
+ # Sigar provisioner native library extract location. Use per-application-instance scoped location, such as program
+ # working directory.
+ sigar-native-folder = ${user.dir}"/native"
+
+ # Frequency with which all Sigar-based metrics will be updated. Setting this value to less than 1 second
+ # might cause some Sigar metrics to behave incorrectly.
+ sigar-metrics-refresh-interval = 1 second
+
+ # Frequency with which context-switches metrics will be updated.
+ context-switches-refresh-interval = 1 second
+
+ # Dispatcher to be used by the SigarMetricsUpdater actor.
+ sigar-dispatcher {
+ executor = "thread-pool-executor"
+ type = PinnedDispatcher
}
- # Default dispatcher for all system-metrics module operations
- dispatcher = ${kamon.default-dispatcher}
+ # Dispatcher to be used by the ContextSwitchesUpdater actor.
+ context-switches-dispatcher {
+ executor = "thread-pool-executor"
+ type = PinnedDispatcher
+ }
}
- metrics {
- precision {
-
- system {
- process-cpu {
- cpu-percentage = {
- highest-trackable-value = 999999999
- significant-value-digits = 2
- }
- total-process-time = {
- highest-trackable-value = 999999999
- significant-value-digits = 2
- }
- }
-
- cpu {
- user = {
- highest-trackable-value = 999
- significant-value-digits = 2
- }
- system = {
- highest-trackable-value = 999
- significant-value-digits = 2
- }
- wait = {
- highest-trackable-value = 999
- significant-value-digits = 2
- }
- idle = {
- highest-trackable-value = 999
- significant-value-digits = 2
- }
- stolen = {
- highest-trackable-value = 999
- significant-value-digits = 2
- }
- }
-
- network {
- rx-bytes = ${kamon.metrics.precision.default-histogram-precision}
- tx-bytes = ${kamon.metrics.precision.default-histogram-precision}
- rx-errors = ${kamon.metrics.precision.default-histogram-precision}
- tx-errors = ${kamon.metrics.precision.default-histogram-precision}
- rx-dropped = ${kamon.metrics.precision.default-histogram-precision}
- tx-dropped = ${kamon.metrics.precision.default-histogram-precision}
- }
-
- memory {
- used = ${kamon.metrics.precision.default-histogram-precision}
- free = ${kamon.metrics.precision.default-histogram-precision}
- buffer = ${kamon.metrics.precision.default-histogram-precision}
- cache = ${kamon.metrics.precision.default-histogram-precision}
- swap-used = ${kamon.metrics.precision.default-histogram-precision}
- swap-free = ${kamon.metrics.precision.default-histogram-precision}
- }
-
- context-switches {
- per-process-voluntary = ${kamon.metrics.precision.default-histogram-precision}
- per-process-non-voluntary = ${kamon.metrics.precision.default-histogram-precision}
- global = ${kamon.metrics.precision.default-histogram-precision}
- }
-
- disk {
- reads = ${kamon.metrics.precision.default-histogram-precision}
- writes = ${kamon.metrics.precision.default-histogram-precision}
- queue = ${kamon.metrics.precision.default-histogram-precision}
- service-time = ${kamon.metrics.precision.default-histogram-precision}
- }
-
- load-average {
- one = ${kamon.metrics.precision.default-histogram-precision}
- five = ${kamon.metrics.precision.default-histogram-precision}
- fifteen = ${kamon.metrics.precision.default-histogram-precision}
- }
+ metrics.instrument-settings {
+ system-metric {
+
+ #
+ # CPU
+ #
+ cpu-user {
+ highest-trackable-value = 100
+ }
+
+ cpu-system = ${kamon.metrics.instrument-settings.system-metric.cpu-user}
+ cpu-wait = ${kamon.metrics.instrument-settings.system-metric.cpu-user}
+ cpu-idle = ${kamon.metrics.instrument-settings.system-metric.cpu-user}
+ cpu-stolen = ${kamon.metrics.instrument-settings.system-metric.cpu-user}
+
+
+ #
+ # Process CPU
+ #
+ process-user-cpu = ${kamon.metrics.instrument-settings.system-metric.cpu-user}
+ process-system-cpu = ${kamon.metrics.instrument-settings.system-metric.cpu-user}
+ process-cpu = ${kamon.metrics.instrument-settings.system-metric.cpu-user}
+
+
+ #
+ # Garbage Collection
+ #
+ garbage-collection-count {
+ highest-trackable-value = 1000000
+ refresh-interval = 1 second
+ }
+
+ garbage-collection-time {
+ highest-trackable-value = 3600000
+ refresh-interval = 1 second
+ }
+
+
+ #
+ # Heap Memory
+ #
+ heap-used {
+ # 50 GB, which is way too much for a non-Zing JVM
+ highest-trackable-value = 5368709120
+ refresh-interval = 1 second
}
- jvm {
- heap {
- used = ${kamon.system-metrics.default-gauge-precision}
- max = ${kamon.system-metrics.default-gauge-precision}
- committed = ${kamon.system-metrics.default-gauge-precision}
- }
-
- non-heap {
- used = ${kamon.system-metrics.default-gauge-precision}
- max = ${kamon.system-metrics.default-gauge-precision}
- committed = ${kamon.system-metrics.default-gauge-precision}
- }
-
- thread {
- daemon = ${kamon.system-metrics.default-gauge-precision}
- count = ${kamon.system-metrics.default-gauge-precision}
- peak = ${kamon.system-metrics.default-gauge-precision}
- }
-
- classes {
- total-loaded = ${kamon.system-metrics.default-gauge-precision}
- total-unloaded = ${kamon.system-metrics.default-gauge-precision}
- current-loaded = ${kamon.system-metrics.default-gauge-precision}
- }
-
- gc {
- count = ${kamon.metrics.precision.default-histogram-precision}
- time = ${kamon.metrics.precision.default-histogram-precision}
- }
+ heap-max = ${kamon.metrics.instrument-settings.system-metric.heap-used}
+ heap-committed = ${kamon.metrics.instrument-settings.system-metric.heap-used}
+
+
+ #
+ # Non-Heap Memory
+ #
+ non-heap-used {
+ highest-trackable-value = 5368709120
+ refresh-interval = 1 second
+ }
+ non-heap-max = ${kamon.metrics.instrument-settings.system-metric.non-heap-used}
+ non-heap-committed = ${kamon.metrics.instrument-settings.system-metric.non-heap-used}
+
+
+ #
+ # JVM Threads
+ #
+ thread-count {
+ highest-trackable-value = 10000
+ refresh-interval = 1 second
+ }
+
+ daemon-thread-count = ${kamon.metrics.instrument-settings.system-metric.thread-count}
+ peak-thread-count = ${kamon.metrics.instrument-settings.system-metric.thread-count}
+
+
+ #
+ # Class Loading
+ #
+ classes-loaded {
+ highest-trackable-value = 10000000
+ refresh-interval = 1 second
}
+
+ classes-unloaded = ${kamon.metrics.instrument-settings.system-metric.classes-loaded}
+ classes-currently-loaded = ${kamon.metrics.instrument-settings.system-metric.classes-loaded}
+
+
+ #
+ # File System
+ #
+ file-system-reads {
+ highest-trackable-value = 107374182400
+ }
+
+ file-system-writes = ${kamon.metrics.instrument-settings.system-metric.file-system-reads}
+
+
+ #
+ # Load Average
+ #
+ one-minute {
+ highest-trackable-value = 10000
+ }
+
+ five-minutes = ${kamon.metrics.instrument-settings.system-metric.one-minute}
+ fifteen-minutes = ${kamon.metrics.instrument-settings.system-metric.one-minute}
+
+
+ #
+ # System Memory
+ #
+ memory-used {
+ highest-trackable-value = 5368709120
+ }
+
+ memory-free = ${kamon.metrics.instrument-settings.system-metric.memory-used}
+ swap-free = ${kamon.metrics.instrument-settings.system-metric.memory-used}
+ swap-used = ${kamon.metrics.instrument-settings.system-metric.memory-used}
+
+
+ #
+ # Network
+ #
+ tx-bytes {
+ highest-trackable-value = 107374182400
+ }
+
+ rx-bytes = ${kamon.metrics.instrument-settings.system-metric.tx-bytes}
+
+ tx-errors {
+ highest-trackable-value = 10000000
+ }
+
+ rx-errors = ${kamon.metrics.instrument-settings.system-metric.tx-errors}
+ tx-dropped = ${kamon.metrics.instrument-settings.system-metric.tx-errors}
+ rx-dropped = ${kamon.metrics.instrument-settings.system-metric.tx-errors}
+
+
+ #
+ # Context Switches
+ #
+ context-switches-process-voluntary {
+ highest-trackable-value = 10000000
+ }
+
+ context-switches-process-non-voluntary = ${kamon.metrics.instrument-settings.system-metric.context-switches-process-voluntary}
+ context-switches-global = ${kamon.metrics.instrument-settings.system-metric.context-switches-process-voluntary}
+
}
}
} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/CPUMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/CPUMetrics.scala
deleted file mode 100644
index 20789039..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/CPUMetrics.scala
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.Histogram
-
-case class CPUMetrics(name: String) extends MetricGroupIdentity {
- val category = CPUMetrics
-}
-
-object CPUMetrics extends MetricGroupCategory {
- val name = "cpu"
-
- case object User extends MetricIdentity { val name = "user" }
- case object System extends MetricIdentity { val name = "system" }
- case object Wait extends MetricIdentity { val name = "wait" }
- case object Idle extends MetricIdentity { val name = "idle" }
- case object Stolen extends MetricIdentity { val name = "stolen" }
-
- case class CPUMetricRecorder(user: Histogram, system: Histogram, cpuWait: Histogram, idle: Histogram, stolen: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- CPUMetricSnapshot(user.collect(context), system.collect(context), cpuWait.collect(context), idle.collect(context), stolen.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class CPUMetricSnapshot(user: Histogram.Snapshot, system: Histogram.Snapshot, cpuWait: Histogram.Snapshot, idle: Histogram.Snapshot, stolen: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = CPUMetricSnapshot
-
- def merge(that: CPUMetricSnapshot, context: CollectionContext): GroupSnapshotType = {
- CPUMetricSnapshot(user.merge(that.user, context), system.merge(that.system, context), cpuWait.merge(that.cpuWait, context), idle.merge(that.idle, context), stolen.merge(that.stolen, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- User -> user,
- System -> system,
- Wait -> cpuWait,
- Idle -> idle,
- Stolen -> stolen)
- }
-
- val Factory = CPUMetricGroupFactory
-}
-
-case object CPUMetricGroupFactory extends MetricGroupFactory {
-
- import CPUMetrics._
-
- type GroupRecorder = CPUMetricRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.system.cpu")
-
- val userConfig = settings.getConfig("user")
- val systemConfig = settings.getConfig("system")
- val cpuWaitConfig = settings.getConfig("wait")
- val idleConfig = settings.getConfig("idle")
- val stolenConfig = settings.getConfig("stolen")
-
- new CPUMetricRecorder(
- Histogram.fromConfig(userConfig),
- Histogram.fromConfig(systemConfig),
- Histogram.fromConfig(cpuWaitConfig),
- Histogram.fromConfig(idleConfig),
- Histogram.fromConfig(stolenConfig))
- }
-}
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/ClassLoadingMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/ClassLoadingMetrics.scala
deleted file mode 100644
index 1e3bee27..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/ClassLoadingMetrics.scala
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import java.lang.management.ManagementFactory
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.{ Gauge, Histogram }
-
-case class ClassLoadingMetrics(name: String) extends MetricGroupIdentity {
- val category = ClassLoadingMetrics
-}
-
-object ClassLoadingMetrics extends MetricGroupCategory {
- val name = "classes"
-
- case object Loaded extends MetricIdentity { val name = "total-loaded" }
- case object Unloaded extends MetricIdentity { val name = "total-unloaded" }
- case object Current extends MetricIdentity { val name = "current-loaded" }
-
- case class ClassLoadingMetricRecorder(loaded: Gauge, unloaded: Gauge, current: Gauge)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- ClassLoadingMetricSnapshot(loaded.collect(context), unloaded.collect(context), current.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class ClassLoadingMetricSnapshot(loaded: Histogram.Snapshot, unloaded: Histogram.Snapshot, current: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = ClassLoadingMetricSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- ClassLoadingMetricSnapshot(loaded.merge(that.loaded, context), unloaded.merge(that.unloaded, context), current.merge(that.current, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- Loaded -> loaded,
- Unloaded -> unloaded,
- Current -> current)
- }
-
- val Factory = ClassLoadingMetricGroupFactory
-}
-
-case object ClassLoadingMetricGroupFactory extends MetricGroupFactory {
-
- import ClassLoadingMetrics._
-
- val classes = ManagementFactory.getClassLoadingMXBean
-
- type GroupRecorder = ClassLoadingMetricRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.jvm.classes")
-
- val totalLoadedConfig = settings.getConfig("total-loaded")
- val totalUnloadedConfig = settings.getConfig("total-unloaded")
- val currentLoadedConfig = settings.getConfig("current-loaded")
-
- new ClassLoadingMetricRecorder(
- Gauge.fromConfig(totalLoadedConfig, system)(() ⇒ classes.getTotalLoadedClassCount),
- Gauge.fromConfig(totalUnloadedConfig, system)(() ⇒ classes.getUnloadedClassCount),
- Gauge.fromConfig(currentLoadedConfig, system)(() ⇒ classes.getLoadedClassCount.toLong))
- }
-}
-
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/ContextSwitchesMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/ContextSwitchesMetrics.scala
deleted file mode 100644
index 86aeabce..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/ContextSwitchesMetrics.scala
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-
-package kamon.metrics
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.Histogram
-
-case class ContextSwitchesMetrics(name: String) extends MetricGroupIdentity {
- val category = ContextSwitchesMetrics
-}
-
-object ContextSwitchesMetrics extends MetricGroupCategory {
- val name = "context-switches"
-
- case object PerProcessVoluntary extends MetricIdentity { val name = "per-process-voluntary" }
- case object PerProcessNonVoluntary extends MetricIdentity { val name = "per-process-non-voluntary" }
- case object Global extends MetricIdentity { val name = "global" }
-
- case class ContextSwitchesMetricsRecorder(perProcessVoluntary: Histogram, perProcessNonVoluntary: Histogram, global: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- ContextSwitchesMetricsSnapshot(perProcessVoluntary.collect(context), perProcessNonVoluntary.collect(context), global.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class ContextSwitchesMetricsSnapshot(perProcessVoluntary: Histogram.Snapshot, perProcessNonVoluntary: Histogram.Snapshot, global: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = ContextSwitchesMetricsSnapshot
-
- def merge(that: ContextSwitchesMetricsSnapshot, context: CollectionContext): GroupSnapshotType = {
- ContextSwitchesMetricsSnapshot(perProcessVoluntary.merge(that.perProcessVoluntary, context), perProcessVoluntary.merge(that.perProcessVoluntary, context), global.merge(that.global, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- PerProcessVoluntary -> perProcessVoluntary,
- PerProcessNonVoluntary -> perProcessNonVoluntary,
- Global -> global)
- }
-
- val Factory = ContextSwitchesMetricGroupFactory
-}
-
-case object ContextSwitchesMetricGroupFactory extends MetricGroupFactory {
- import ContextSwitchesMetrics._
-
- type GroupRecorder = ContextSwitchesMetricsRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.system.context-switches")
-
- val perProcessVoluntary = settings.getConfig("per-process-voluntary")
- val perProcessNonVoluntary = settings.getConfig("per-process-non-voluntary")
- val global = settings.getConfig("global")
-
- new ContextSwitchesMetricsRecorder(
- Histogram.fromConfig(perProcessVoluntary),
- Histogram.fromConfig(perProcessNonVoluntary),
- Histogram.fromConfig(global))
- }
-}
-
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/DiskMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/DiskMetrics.scala
deleted file mode 100644
index eeb6002b..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/DiskMetrics.scala
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.Histogram
-
-case class DiskMetrics(name: String) extends MetricGroupIdentity {
- val category = DiskMetrics
-}
-
-object DiskMetrics extends MetricGroupCategory {
- val name = "disk"
-
- case object Reads extends MetricIdentity { val name = "reads" }
- case object Writes extends MetricIdentity { val name = "writes" }
- case object Queue extends MetricIdentity { val name = "queue" }
- case object ServiceTime extends MetricIdentity { val name = "service-time" }
-
- case class DiskMetricsRecorder(reads: Histogram, writes: Histogram, queue: Histogram, serviceTime: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- DiskMetricsSnapshot(reads.collect(context), writes.collect(context), queue.collect(context), serviceTime.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class DiskMetricsSnapshot(reads: Histogram.Snapshot, writes: Histogram.Snapshot, queue: Histogram.Snapshot, serviceTime: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = DiskMetricsSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- DiskMetricsSnapshot(reads.merge(that.reads, context), writes.merge(that.writes, context), queue.merge(that.queue, context), serviceTime.merge(that.serviceTime, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- Reads -> reads,
- Writes -> writes,
- Queue -> queue,
- ServiceTime -> serviceTime)
- }
-
- val Factory = DiskMetricGroupFactory
-}
-
-case object DiskMetricGroupFactory extends MetricGroupFactory {
-
- import DiskMetrics._
-
- type GroupRecorder = DiskMetricsRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.system.disk")
-
- val readsDiskConfig = settings.getConfig("reads")
- val writesDiskConfig = settings.getConfig("writes")
- val queueDiskConfig = settings.getConfig("queue")
- val serviceTimeDiskConfig = settings.getConfig("service-time")
-
- new DiskMetricsRecorder(
- Histogram.fromConfig(readsDiskConfig),
- Histogram.fromConfig(writesDiskConfig),
- Histogram.fromConfig(queueDiskConfig),
- Histogram.fromConfig(serviceTimeDiskConfig))
- }
-}
-
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala
deleted file mode 100644
index 5aa679c9..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import java.lang.management.GarbageCollectorMXBean
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.Histogram
-
-case class GCMetrics(name: String) extends MetricGroupIdentity {
- val category = GCMetrics
-}
-
-object GCMetrics extends MetricGroupCategory {
- val name = "gc"
-
- case object CollectionCount extends MetricIdentity { val name = "collection-count" }
- case object CollectionTime extends MetricIdentity { val name = "collection-time" }
-
- case class GCMetricRecorder(count: Histogram, time: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- GCMetricSnapshot(count.collect(context), time.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class GCMetricSnapshot(count: Histogram.Snapshot, time: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = GCMetricSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- GCMetricSnapshot(count.merge(that.count, context), time.merge(that.time, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- CollectionCount -> count,
- CollectionTime -> time)
- }
-
- def Factory(gc: GarbageCollectorMXBean) = GCMetricGroupFactory(gc)
-}
-
-case class GCMetricGroupFactory(gc: GarbageCollectorMXBean) extends MetricGroupFactory {
- import GCMetrics._
-
- type GroupRecorder = GCMetricRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.jvm.gc")
-
- val countConfig = settings.getConfig("count")
- val timeConfig = settings.getConfig("time")
-
- new GCMetricRecorder(
- Histogram.fromConfig(countConfig),
- Histogram.fromConfig(timeConfig))
- }
-} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/HeapMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/HeapMetrics.scala
deleted file mode 100644
index 5bba5bf6..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/HeapMetrics.scala
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import java.lang.management.ManagementFactory
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.{ Gauge, Histogram }
-
-case class HeapMetrics(name: String) extends MetricGroupIdentity {
- val category = HeapMetrics
-}
-
-object HeapMetrics extends MetricGroupCategory {
- val name = "heap"
-
- case object Used extends MetricIdentity { val name = "used" }
- case object Max extends MetricIdentity { val name = "max" }
- case object Committed extends MetricIdentity { val name = "committed" }
-
- case class HeapMetricRecorder(used: Gauge, max: Gauge, committed: Gauge)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- HeapMetricSnapshot(used.collect(context), max.collect(context), committed.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class HeapMetricSnapshot(used: Histogram.Snapshot, max: Histogram.Snapshot, committed: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = HeapMetricSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- HeapMetricSnapshot(used.merge(that.used, context), max.merge(that.max, context), committed.merge(that.committed, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- Used -> used,
- Max -> max,
- Committed -> committed)
- }
-
- val Factory = HeapMetricGroupFactory
-}
-
-case object HeapMetricGroupFactory extends MetricGroupFactory {
-
- import HeapMetrics._
- import kamon.system.SystemMetricsExtension._
-
- def heap = ManagementFactory.getMemoryMXBean.getHeapMemoryUsage
-
- type GroupRecorder = HeapMetricRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.jvm.heap")
-
- val usedHeapConfig = settings.getConfig("used")
- val maxHeapConfig = settings.getConfig("max")
- val committedHeapConfig = settings.getConfig("committed")
-
- new HeapMetricRecorder(
- Gauge.fromConfig(usedHeapConfig, system, Scale.Mega)(() ⇒ toMB(heap.getUsed)),
- Gauge.fromConfig(maxHeapConfig, system, Scale.Mega)(() ⇒ toMB(heap.getMax)),
- Gauge.fromConfig(committedHeapConfig, system, Scale.Mega)(() ⇒ toMB(heap.getCommitted)))
- }
-
-}
-
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/LoadAverageMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/LoadAverageMetrics.scala
deleted file mode 100644
index cd196adf..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/LoadAverageMetrics.scala
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.Histogram
-
-case class LoadAverageMetrics(name: String) extends MetricGroupIdentity {
- val category = LoadAverageMetrics
-}
-
-object LoadAverageMetrics extends MetricGroupCategory {
- val name = "load-average"
-
- case object OneMinute extends MetricIdentity { val name = "last-minute" }
- case object FiveMinutes extends MetricIdentity { val name = "last-five-minutes" }
- case object FifteenMinutes extends MetricIdentity { val name = "last-fifteen-minutes" }
-
- case class LoadAverageMetricsRecorder(one: Histogram, five: Histogram, fifteen: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- LoadAverageMetricsSnapshot(one.collect(context), five.collect(context), fifteen.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class LoadAverageMetricsSnapshot(one: Histogram.Snapshot, five: Histogram.Snapshot, fifteen: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = LoadAverageMetricsSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- LoadAverageMetricsSnapshot(one.merge(that.one, context), five.merge(that.five, context), fifteen.merge(that.fifteen, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- OneMinute -> one,
- FiveMinutes -> five,
- FifteenMinutes -> fifteen)
- }
-
- val Factory = LoadAverageMetricGroupFactory
-}
-
-case object LoadAverageMetricGroupFactory extends MetricGroupFactory {
-
- import LoadAverageMetrics._
-
- type GroupRecorder = LoadAverageMetricsRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.system.load-average")
-
- val oneMinuteConfig = settings.getConfig("one")
- val fiveMinutesConfig = settings.getConfig("five")
- val fifteenMinutesConfig = settings.getConfig("fifteen")
-
- new LoadAverageMetricsRecorder(
- Histogram.fromConfig(oneMinuteConfig),
- Histogram.fromConfig(fiveMinutesConfig),
- Histogram.fromConfig(fifteenMinutesConfig))
- }
-}
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/MemoryMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/MemoryMetrics.scala
deleted file mode 100644
index 14051427..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/MemoryMetrics.scala
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.Histogram
-
-case class MemoryMetrics(name: String) extends MetricGroupIdentity {
- val category = MemoryMetrics
-}
-
-object MemoryMetrics extends MetricGroupCategory {
- val name = "memory"
-
- case object Used extends MetricIdentity { val name = "used" }
- case object Free extends MetricIdentity { val name = "free" }
- case object Buffer extends MetricIdentity { val name = "buffer" }
- case object Cache extends MetricIdentity { val name = "cache" }
- case object SwapUsed extends MetricIdentity { val name = "swap-used" }
- case object SwapFree extends MetricIdentity { val name = "swap-free" }
-
- case class MemoryMetricRecorder(used: Histogram, free: Histogram, buffer: Histogram, cache: Histogram, swapUsed: Histogram, swapFree: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- MemoryMetricSnapshot(used.collect(context), free.collect(context), buffer.collect(context), cache.collect(context), swapUsed.collect(context), swapFree.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class MemoryMetricSnapshot(used: Histogram.Snapshot, free: Histogram.Snapshot, buffer: Histogram.Snapshot, cache: Histogram.Snapshot, swapUsed: Histogram.Snapshot, swapFree: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = MemoryMetricSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- MemoryMetricSnapshot(used.merge(that.used, context), free.merge(that.free, context), buffer.merge(that.buffer, context), cache.merge(that.cache, context), swapUsed.merge(that.swapUsed, context), swapFree.merge(that.swapFree, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- Used -> used,
- Free -> free,
- Buffer -> buffer,
- Cache -> cache,
- SwapUsed -> swapUsed,
- SwapFree -> swapFree)
- }
-
- val Factory = MemoryMetricGroupFactory
-}
-
-case object MemoryMetricGroupFactory extends MetricGroupFactory {
-
- import MemoryMetrics._
-
- type GroupRecorder = MemoryMetricRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.system.memory")
-
- val usedConfig = settings.getConfig("used")
- val freeConfig = settings.getConfig("free")
- val bufferConfig = settings.getConfig("buffer")
- val cacheConfig = settings.getConfig("cache")
- val swapUsedConfig = settings.getConfig("swap-used")
- val swapFreeConfig = settings.getConfig("swap-free")
-
- new MemoryMetricRecorder(
- Histogram.fromConfig(usedConfig, Scale.Mega),
- Histogram.fromConfig(freeConfig, Scale.Mega),
- Histogram.fromConfig(swapUsedConfig, Scale.Mega),
- Histogram.fromConfig(swapFreeConfig, Scale.Mega),
- Histogram.fromConfig(bufferConfig, Scale.Mega),
- Histogram.fromConfig(cacheConfig, Scale.Mega))
- }
-} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/NetworkMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/NetworkMetrics.scala
deleted file mode 100644
index d8a38f6d..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/NetworkMetrics.scala
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.Histogram
-
-case class NetworkMetrics(name: String) extends MetricGroupIdentity {
- val category = NetworkMetrics
-}
-
-object NetworkMetrics extends MetricGroupCategory {
- val name = "network"
-
- case object RxBytes extends MetricIdentity { val name = "rx-bytes" }
- case object TxBytes extends MetricIdentity { val name = "tx-bytes" }
- case object RxErrors extends MetricIdentity { val name = "rx-errors" }
- case object TxErrors extends MetricIdentity { val name = "tx-errors" }
- case object RxDropped extends MetricIdentity { val name = "rx-dropped" }
- case object TxDropped extends MetricIdentity { val name = "tx-dropped" }
-
- case class NetworkMetricRecorder(rxBytes: Histogram, txBytes: Histogram, rxErrors: Histogram, txErrors: Histogram, rxDropped: Histogram, txDropped: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- NetworkMetricSnapshot(rxBytes.collect(context), txBytes.collect(context), rxErrors.collect(context), txErrors.collect(context), rxDropped.collect(context), txDropped.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class NetworkMetricSnapshot(rxBytes: Histogram.Snapshot, txBytes: Histogram.Snapshot, rxErrors: Histogram.Snapshot, txErrors: Histogram.Snapshot, rxDropped: Histogram.Snapshot, txDropped: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = NetworkMetricSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- NetworkMetricSnapshot(rxBytes.merge(that.rxBytes, context), txBytes.merge(that.txBytes, context), rxErrors.merge(that.rxErrors, context), txErrors.merge(that.txErrors, context), rxDropped.merge(that.rxDropped, context), txDropped.merge(that.txDropped, context))
- }
-
- val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- RxBytes -> rxBytes,
- TxBytes -> txBytes,
- RxErrors -> rxErrors,
- TxErrors -> txErrors,
- RxDropped -> rxDropped,
- TxDropped -> txDropped)
- }
-
- val Factory = NetworkMetricGroupFactory
-}
-
-case object NetworkMetricGroupFactory extends MetricGroupFactory {
- import NetworkMetrics._
-
- type GroupRecorder = NetworkMetricRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.system.network")
-
- val rxBytesConfig = settings.getConfig("rx-bytes")
- val txBytesConfig = settings.getConfig("tx-bytes")
- val rxErrorsConfig = settings.getConfig("rx-errors")
- val txErrorsConfig = settings.getConfig("tx-errors")
- val rxDroppedConfig = settings.getConfig("rx-dropped")
- val txDroppedConfig = settings.getConfig("tx-dropped")
-
- new NetworkMetricRecorder(
- Histogram.fromConfig(rxBytesConfig, Scale.Kilo),
- Histogram.fromConfig(txBytesConfig, Scale.Kilo),
- Histogram.fromConfig(rxErrorsConfig),
- Histogram.fromConfig(txErrorsConfig),
- Histogram.fromConfig(rxDroppedConfig),
- Histogram.fromConfig(txDroppedConfig))
- }
-} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/NonHeapMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/NonHeapMetrics.scala
deleted file mode 100644
index c2b9f9af..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/NonHeapMetrics.scala
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import java.lang.management.ManagementFactory
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.{ Gauge, Histogram }
-
-case class NonHeapMetrics(name: String) extends MetricGroupIdentity {
- val category = NonHeapMetrics
-}
-
-object NonHeapMetrics extends MetricGroupCategory {
- val name = "non-heap"
-
- case object Used extends MetricIdentity { val name = "used" }
- case object Max extends MetricIdentity { val name = "max" }
- case object Committed extends MetricIdentity { val name = "committed" }
-
- case class NonHeapMetricRecorder(used: Gauge, max: Gauge, committed: Gauge)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- NonHeapMetricSnapshot(used.collect(context), max.collect(context), committed.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class NonHeapMetricSnapshot(used: Histogram.Snapshot, max: Histogram.Snapshot, committed: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = NonHeapMetricSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- NonHeapMetricSnapshot(used.merge(that.used, context), max.merge(that.max, context), committed.merge(that.committed, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- Used -> used,
- Max -> max,
- Committed -> committed)
- }
-
- val Factory = NonHeapMetricGroupFactory
-}
-
-case object NonHeapMetricGroupFactory extends MetricGroupFactory {
-
- import NonHeapMetrics._
- import kamon.system.SystemMetricsExtension._
-
- def nonHeap = ManagementFactory.getMemoryMXBean.getNonHeapMemoryUsage
-
- type GroupRecorder = NonHeapMetricRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.jvm.non-heap")
-
- val usedNonHeapConfig = settings.getConfig("used")
- val maxNonHeapConfig = settings.getConfig("max")
- val committedNonHeapConfig = settings.getConfig("committed")
-
- new NonHeapMetricRecorder(
- Gauge.fromConfig(usedNonHeapConfig, system, Scale.Mega)(() ⇒ toMB(nonHeap.getUsed)),
- Gauge.fromConfig(maxNonHeapConfig, system, Scale.Mega)(() ⇒ toMB(nonHeap.getMax)),
- Gauge.fromConfig(committedNonHeapConfig, system, Scale.Mega)(() ⇒ toMB(nonHeap.getCommitted)))
- }
-}
-
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/ProcessCPUMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/ProcessCPUMetrics.scala
deleted file mode 100644
index ebd79d48..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/ProcessCPUMetrics.scala
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.Histogram
-
-case class ProcessCPUMetrics(name: String) extends MetricGroupIdentity {
- val category = ProcessCPUMetrics
-}
-
-object ProcessCPUMetrics extends MetricGroupCategory {
- val name = "proc-cpu"
-
- case object CpuPercent extends MetricIdentity { val name = "cpu-percentage" }
- case object TotalProcessTime extends MetricIdentity { val name = "total-process-time" }
-
- case class ProcessCPUMetricsRecorder(cpuPercent: Histogram, totalProcessTime: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- ProcessCPUMetricsSnapshot(cpuPercent.collect(context), totalProcessTime.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class ProcessCPUMetricsSnapshot(cpuPercent: Histogram.Snapshot, totalProcessTime: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = ProcessCPUMetricsSnapshot
-
- def merge(that: ProcessCPUMetricsSnapshot, context: CollectionContext): GroupSnapshotType = {
- ProcessCPUMetricsSnapshot(cpuPercent.merge(that.cpuPercent, context), totalProcessTime.merge(that.totalProcessTime, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- CpuPercent -> cpuPercent,
- TotalProcessTime -> totalProcessTime)
- }
-
- val Factory = ProcessCPUMetricGroupFactory
-}
-
-case object ProcessCPUMetricGroupFactory extends MetricGroupFactory {
- import ProcessCPUMetrics._
-
- type GroupRecorder = ProcessCPUMetricsRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.system.process-cpu")
-
- val cpuPercentageConfig = settings.getConfig("cpu-percentage")
- val totalProcessTimeConfig = settings.getConfig("total-process-time")
-
- new ProcessCPUMetricsRecorder(
- Histogram.fromConfig(cpuPercentageConfig),
- Histogram.fromConfig(totalProcessTimeConfig))
- }
-}
-
diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/ThreadMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/ThreadMetrics.scala
deleted file mode 100644
index fc039ffa..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/ThreadMetrics.scala
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.metrics
-
-import java.lang.management.ManagementFactory
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.{ Gauge, Histogram }
-
-case class ThreadMetrics(name: String) extends MetricGroupIdentity {
- val category = ThreadMetrics
-}
-
-object ThreadMetrics extends MetricGroupCategory {
- val name = "thread"
-
- case object Damon extends MetricIdentity { val name = "daemon-count" }
- case object Count extends MetricIdentity { val name = "count" }
- case object Peak extends MetricIdentity { val name = "peak-count" }
-
- case class ThreadMetricRecorder(daemon: Gauge, count: Gauge, peak: Gauge)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- ThreadMetricSnapshot(daemon.collect(context), count.collect(context), peak.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class ThreadMetricSnapshot(daemon: Histogram.Snapshot, count: Histogram.Snapshot, peak: Histogram.Snapshot)
- extends MetricGroupSnapshot {
-
- type GroupSnapshotType = ThreadMetricSnapshot
-
- def merge(that: GroupSnapshotType, context: CollectionContext): GroupSnapshotType = {
- ThreadMetricSnapshot(daemon.merge(that.daemon, context), count.merge(that.count, context), peak.merge(that.peak, context))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- Damon -> daemon,
- Count -> count,
- Peak -> peak)
- }
-
- val Factory = ThreadMetricGroupFactory
-}
-
-case object ThreadMetricGroupFactory extends MetricGroupFactory {
-
- import ThreadMetrics._
-
- def threads = ManagementFactory.getThreadMXBean
-
- type GroupRecorder = ThreadMetricRecorder
-
- def create(config: Config, system: ActorSystem): GroupRecorder = {
- val settings = config.getConfig("precision.jvm.thread")
-
- val daemonThreadConfig = settings.getConfig("daemon")
- val countThreadsConfig = settings.getConfig("count")
- val peakThreadsConfig = settings.getConfig("peak")
-
- new ThreadMetricRecorder(
- Gauge.fromConfig(daemonThreadConfig, system)(() ⇒ threads.getDaemonThreadCount.toLong),
- Gauge.fromConfig(countThreadsConfig, system)(() ⇒ threads.getThreadCount.toLong),
- Gauge.fromConfig(peakThreadsConfig, system)(() ⇒ threads.getPeakThreadCount.toLong))
- }
-}
-
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/GcMetricsCollector.scala b/kamon-system-metrics/src/main/scala/kamon/system/GcMetricsCollector.scala
deleted file mode 100644
index ae2f50cf..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/system/GcMetricsCollector.scala
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-
-package kamon.system
-
-import java.lang.management.GarbageCollectorMXBean
-
-import akka.actor.{ Actor, Props }
-import kamon.metrics.GCMetrics.GCMetricRecorder
-
-import scala.concurrent.duration.FiniteDuration
-
-class GcMetricsCollector(collectInterval: FiniteDuration, recorder: Option[GCMetricRecorder], extractor: GcMetricExtractor) extends Actor {
- import kamon.system.GcMetricsCollector._
-
- val collectSchedule = context.system.scheduler.schedule(collectInterval, collectInterval, self, Collect)(SystemMetrics(context.system).dispatcher)
-
- def receive: Receive = {
- case Collect ⇒ collectMetrics()
- }
-
- override def postStop() = collectSchedule.cancel()
-
- def collectMetrics(): Unit = recorder.map(recordGc)
-
- private def recordGc(gcr: GCMetricRecorder) = {
- val gcMeasure = extractor.extract()
-
- gcr.count.record(gcMeasure.collectionCount)
- gcr.time.record(gcMeasure.collectionTime)
- }
-}
-
-object GcMetricsCollector {
- case object Collect
-
- def props(collectInterval: FiniteDuration, recorder: Option[GCMetricRecorder], extractor: GcMetricExtractor): Props = Props(classOf[GcMetricsCollector], collectInterval, recorder, extractor)
-}
-
-case class GcMeasure(collectionCount: Long, collectionTime: Long)
-
-case class GcMetricExtractor(gc: GarbageCollectorMXBean) {
- var previousGcCount = 0L
- var previousGcTime = 0L
-
- def extract(): GcMeasure = {
- var diffCollectionCount = 0L
- var diffCollectionTime = 0L
-
- val collectionCount = gc.getCollectionCount
- val collectionTime = gc.getCollectionTime
-
- if (collectionCount > 0)
- diffCollectionCount = collectionCount - previousGcCount
-
- if (collectionTime > 0)
- diffCollectionTime = collectionTime - previousGcTime
-
- previousGcCount = collectionCount
- previousGcTime = collectionTime
-
- GcMeasure(diffCollectionCount, diffCollectionTime)
- }
-} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala
deleted file mode 100644
index cb3e2695..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.system
-
-import java.lang.management.ManagementFactory
-import akka.actor._
-import akka.event.Logging
-import kamon.Kamon
-import kamon.metric.Metrics
-import kamon.metrics._
-import scala.collection.JavaConverters._
-import scala.concurrent.duration._
-
-object SystemMetrics extends ExtensionId[SystemMetricsExtension] with ExtensionIdProvider {
- override def lookup(): ExtensionId[_ <: Extension] = SystemMetrics
- override def createExtension(system: ExtendedActorSystem): SystemMetricsExtension = new SystemMetricsExtension(system)
-}
-
-class SystemMetricsExtension(private val system: ExtendedActorSystem) extends Kamon.Extension {
- import kamon.system.SystemMetricsExtension._
-
- val log = Logging(system, classOf[SystemMetricsExtension])
- log.info(s"Starting the Kamon(SystemMetrics) extension")
-
- val config = system.settings.config.getConfig("kamon.system-metrics")
- val dispatcher = system.dispatchers.lookup(config.getString("dispatcher"))
- val sigarFolder = system.settings.config.getString("kamon.sigar.folder")
- val systemMetricsExtension = Kamon(Metrics)(system)
-
- //System Metrics
- system.actorOf(SystemMetricsCollector.props(1 second), "system-metrics-collector")
-
- //JVM Metrics
- systemMetricsExtension.register(HeapMetrics(Heap), HeapMetrics.Factory)
- systemMetricsExtension.register(NonHeapMetrics(NonHeap), NonHeapMetrics.Factory)
- systemMetricsExtension.register(ClassLoadingMetrics(Classes), ClassLoadingMetrics.Factory)
- systemMetricsExtension.register(ThreadMetrics(Threads), ThreadMetrics.Factory)
-
- garbageCollectors.map { gc ⇒
- val gcName = sanitize(gc.getName)
- val recorder = systemMetricsExtension.register(GCMetrics(gcName), GCMetrics.Factory(gc))
- system.actorOf(GcMetricsCollector.props(1 second, recorder, GcMetricExtractor(gc)), s"$gcName-collector")
- }
-}
-
-object SystemMetricsExtension {
- val CPU = "cpu"
- val ProcessCPU = "process-cpu"
- val Network = "network"
- val Memory = "memory"
- val Heap = "heap"
- val NonHeap = "non-heap"
- val Classes = "classes"
- val Threads = "thread"
- val ContextSwitches = "context-switches"
- val Disk = "disk"
- val LoadAverage = "load-average"
-
- def toKB(value: Long): Long = value / 1024
- def toMB(value: Long): Long = value / 1024 / 1024
- def toLong(value: Double): Long = math round (value * 100L)
- def sanitize(str: String): String = str.replaceAll("""[^\w]""", "-")
-
- val garbageCollectors = ManagementFactory.getGarbageCollectorMXBeans.asScala.filter(_.isValid)
-}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsBanner.scala b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsBanner.scala
deleted file mode 100644
index 99e09da9..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsBanner.scala
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-
-package kamon.system
-
-import akka.actor.ActorLogging
-import org.hyperic.sigar._
-
-import scala.util.control.NoStackTrace
-
-trait SystemMetricsBanner {
- self: ActorLogging ⇒
-
- def printBanner(sigar: Sigar) = {
- val os = OperatingSystem.getInstance
-
- def loadAverage(sigar: Sigar) = try {
- val average = sigar.getLoadAverage
- (average(0), average(1), average(2))
- } catch {
- case s: org.hyperic.sigar.SigarNotImplementedException ⇒ (0d, 0d, 0d)
- }
-
- def uptime(sigar: Sigar) = {
- def formatUptime(uptime: Double): String = {
- var retval: String = ""
- val days: Int = uptime.toInt / (60 * 60 * 24)
- var minutes: Int = 0
- var hours: Int = 0
-
- if (days != 0) {
- retval += s"$days ${if (days > 1) "days" else "day"}, "
- }
-
- minutes = uptime.toInt / 60
- hours = minutes / 60
- hours %= 24
- minutes %= 60
-
- if (hours != 0) {
- retval += hours + ":" + minutes
- } else {
- retval += minutes + " min"
- }
- retval
- }
-
- val uptime = sigar.getUptime
- val now = System.currentTimeMillis()
-
- s"up ${formatUptime(uptime.getUptime)}"
- }
-
- val message =
- """
- |
- | _____ _ __ __ _ _ _ _ _
- | / ____| | | | \/ | | | (_) | | | | | |
- || (___ _ _ ___| |_ ___ _ __ ___ | \ / | ___| |_ _ __ _ ___ ___| | ___ __ _ __| | ___ __| |
- | \___ \| | | / __| __/ _ \ '_ ` _ \| |\/| |/ _ \ __| '__| |/ __/ __| | / _ \ / _` |/ _` |/ _ \/ _` |
- | ____) | |_| \__ \ || __/ | | | | | | | | __/ |_| | | | (__\__ \ |___| (_) | (_| | (_| | __/ (_| |
- ||_____/ \__, |___/\__\___|_| |_| |_|_| |_|\___|\__|_| |_|\___|___/______\___/ \__,_|\__,_|\___|\__,_|
- | __/ |
- | |___/
- |
- | [System Status] [OS Information]
- | |--------------------------------| |----------------------------------------|
- | Up Time: %-10s Description: %s
- | Load Average: %-16s Name: %s
- | Version: %s
- | Arch: %s
- |
- """.stripMargin.format(uptime(sigar), os.getDescription, loadAverage(sigar), os.getName, os.getVersion, os.getArch)
- log.info(message)
- }
-
- class UnexpectedSigarException(message: String) extends RuntimeException(message) with NoStackTrace
-}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala
deleted file mode 100644
index 4391240a..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2014 the kamon project <http://kamon.io/>
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- * =========================================================================================
- */
-package kamon.system
-
-import java.io.{ File, IOException }
-
-import akka.actor.{ Actor, ActorLogging, Props }
-import kamon.Kamon
-import kamon.metric.Metrics
-import kamon.metrics.CPUMetrics.CPUMetricRecorder
-import kamon.metrics.ContextSwitchesMetrics.ContextSwitchesMetricsRecorder
-import kamon.metrics.DiskMetrics.DiskMetricsRecorder
-import kamon.metrics.LoadAverageMetrics.LoadAverageMetricsRecorder
-import kamon.metrics.MemoryMetrics.MemoryMetricRecorder
-import kamon.metrics.NetworkMetrics.NetworkMetricRecorder
-import kamon.metrics.ProcessCPUMetrics.ProcessCPUMetricsRecorder
-import kamon.metrics._
-import kamon.sigar.SigarProvisioner
-import org.hyperic.sigar._
-
-import scala.collection.concurrent.TrieMap
-import scala.concurrent.duration.FiniteDuration
-import scala.io.Source
-import scala.collection.mutable
-
-class SystemMetricsCollector(collectInterval: FiniteDuration) extends Actor with ActorLogging with SystemMetricsBanner {
- import kamon.system.SystemMetricsCollector._
- import kamon.system.SystemMetricsExtension._
-
- lazy val sigar = createSigarInstance
- def pid = sigar.getPid
-
- val interfaces = sigar.getNetInterfaceList.filterNot(NetworkFilter).toSet
- val fileSystems = sigar.getFileSystemList.filter(_.getType == FileSystem.TYPE_LOCAL_DISK).map(_.getDevName).toSet
-
- val metricExtension = Kamon(Metrics)(context.system)
- val collectSchedule = context.system.scheduler.schedule(collectInterval, collectInterval, self, Collect)(SystemMetrics(context.system).dispatcher)
-
- val cpuRecorder = metricExtension.register(CPUMetrics(CPU), CPUMetrics.Factory)
- val processCpuRecorder = metricExtension.register(ProcessCPUMetrics(ProcessCPU), ProcessCPUMetrics.Factory)
- val memoryRecorder = metricExtension.register(MemoryMetrics(Memory), MemoryMetrics.Factory)
- val networkRecorder = metricExtension.register(NetworkMetrics(Network), NetworkMetrics.Factory)
- val contextSwitchesRecorder = metricExtension.register(ContextSwitchesMetrics(ContextSwitches), ContextSwitchesMetrics.Factory)
- val diskRecorder = metricExtension.register(DiskMetrics(Disk), DiskMetrics.Factory)
- val loadAverageRecorder = metricExtension.register(LoadAverageMetrics(LoadAverage), LoadAverageMetrics.Factory)
-
- def receive: Receive = {
- case Collect ⇒ collectMetrics()
- }
-
- override def postStop() = collectSchedule.cancel()
-
- def collectMetrics() = {
- cpuRecorder.map(recordCpu)
- processCpuRecorder.map(recordProcessCpu)
- memoryRecorder.map(recordMemory)
- networkRecorder.map(recordNetwork)
- diskRecorder.map(recordDisk)
- loadAverageRecorder.map(recordLoadAverage)
-
- if (OsUtils.isLinux)
- contextSwitchesRecorder.map(recordContextSwitches)
- }
-
- private def recordCpu(cpur: CPUMetricRecorder) = {
- val cpuPerc = sigar.getCpuPerc
- cpur.user.record(toLong(cpuPerc.getUser))
- cpur.system.record(toLong(cpuPerc.getSys))
- cpur.cpuWait.record(toLong(cpuPerc.getWait))
- cpur.idle.record(toLong(cpuPerc.getIdle))
- cpur.stolen.record(toLong(cpuPerc.getStolen))
- }
-
- private def recordProcessCpu(pcpur: ProcessCPUMetricsRecorder) = {
- val procCpu = sigar.getProcCpu(pid)
- val procTime = sigar.getProcTime(pid)
-
- pcpur.cpuPercent.record(toLong(procCpu.getPercent))
- pcpur.totalProcessTime.record(procTime.getTotal) // gives an idea of what is really measured and then interpreted as %
- }
-
- private def recordMemory(mr: MemoryMetricRecorder) = {
- val mem = sigar.getMem
- val swap = sigar.getSwap
-
- mr.used.record(toMB(mem.getUsed))
- mr.free.record(toMB(mem.getFree))
- mr.swapUsed.record(toMB(swap.getUsed))
- mr.swapFree.record(toMB(swap.getFree))
- mr.buffer.record(toMB(collectBuffer(mem)))
- mr.cache.record(toMB(collectCache(mem)))
-
- def collectBuffer(mem: Mem): Long = if (mem.getUsed != mem.getActualUsed) mem.getActualUsed else 0L
- def collectCache(mem: Mem): Long = if (mem.getFree != mem.getActualFree) mem.getActualFree else 0L
- }
-
- private def recordNetwork(nr: NetworkMetricRecorder) = {
- import Networks._
- nr.rxBytes.record(collect(sigar, interfaces, RxBytes, previousNetworkMetrics)(net ⇒ toKB(net.getRxBytes)))
- nr.txBytes.record(collect(sigar, interfaces, TxBytes, previousNetworkMetrics)(net ⇒ toKB(net.getTxBytes)))
- nr.rxErrors.record(collect(sigar, interfaces, RxErrors, previousNetworkMetrics)(net ⇒ net.getRxErrors))
- nr.txErrors.record(collect(sigar, interfaces, TxErrors, previousNetworkMetrics)(net ⇒ net.getTxErrors))
- nr.rxDropped.record(collect(sigar, interfaces, RxDropped, previousNetworkMetrics)(net ⇒ net.getRxDropped))
- nr.txDropped.record(collect(sigar, interfaces, TxDropped, previousNetworkMetrics)(net ⇒ net.getTxDropped))
-
- def collect(sigar: SigarProxy, interfaces: Set[String], name: String, previousMetrics: TrieMap[String, mutable.Map[String, Long]])(thunk: NetInterfaceStat ⇒ Long): Long = {
- interfaces.foldLeft(0L) { (acc, interface) ⇒
- {
- val net = sigar.getNetInterfaceStat(interface)
- val previous = previousMetrics.getOrElse(interface, mutable.Map.empty[String, Long])
- val current = thunk(net)
- val delta = current - previous.getOrElse(name, 0L)
- previousMetrics.put(interface, previous += name -> current)
- acc + delta
- }
- }
- }
- }
-
- private def recordDisk(rd: DiskMetricsRecorder) = {
- import Disks._
-
- rd.reads.record(collect(sigar, fileSystems, Reads, previousDiskMetrics)(disk ⇒ disk.getReads))
- rd.writes.record(collect(sigar, fileSystems, Writes, previousDiskMetrics)(disk ⇒ disk.getWrites))
- rd.queue.record(collect(sigar, fileSystems, Queue, previousDiskMetrics)(disk ⇒ toLong(disk.getQueue)))
- rd.serviceTime.record(collect(sigar, fileSystems, Service, previousDiskMetrics)(disk ⇒ toLong(disk.getServiceTime)))
- }
-
- def collect(sigar: SigarProxy, fileSystems: Set[String], name: String, previousMetrics: TrieMap[String, mutable.Map[String, Long]])(thunk: DiskUsage ⇒ Long): Long = {
- fileSystems.foldLeft(0L) { (acc, fileSystem) ⇒
- {
- val disk = sigar.getDiskUsage(fileSystem)
- val previous = previousMetrics.getOrElse(fileSystem, mutable.Map.empty[String, Long])
- val value = thunk(disk)
- val current = if (value == Sigar.FIELD_NOTIMPL) 0L else value
- val delta = current - previous.getOrElse(name, 0L)
- previousMetrics.put(fileSystem, previous += name -> current)
- acc + delta
- }
- }
- }
-
- private def recordLoadAverage(lar: LoadAverageMetricsRecorder) = {
- val loadAverage = sigar.getLoadAverage
- val (one, five, fifteen) = (loadAverage(0), loadAverage(1), loadAverage(2))
-
- lar.one.record(toLong(one))
- lar.five.record(toLong(five))
- lar.fifteen.record(toLong(fifteen))
- }
-
- private def recordContextSwitches(rcs: ContextSwitchesMetricsRecorder) = {
- def contextSwitchesByProcess(pid: Long): (Long, Long) = {
- val filename = s"/proc/$pid/status"
- var voluntaryContextSwitches = 0L
- var nonVoluntaryContextSwitches = 0L
-
- try {
- for (line ← Source.fromFile(filename).getLines()) {
- if (line.startsWith("voluntary_ctxt_switches")) {
- voluntaryContextSwitches = line.substring(line.indexOf(":") + 1).trim.toLong
- }
- if (line.startsWith("nonvoluntary_ctxt_switches")) {
- nonVoluntaryContextSwitches = line.substring(line.indexOf(":") + 1).trim.toLong
- }
- }
- } catch {
- case ex: IOException ⇒ log.error("Error trying to read [{}]", filename)
- }
- (voluntaryContextSwitches, nonVoluntaryContextSwitches)
- }
-
- def contextSwitches: Long = {
- val filename = "/proc/stat"
- var contextSwitches = 0L
-
- try {
- for (line ← Source.fromFile(filename).getLines()) {
- if (line.startsWith("rcs")) {
- contextSwitches = line.substring(line.indexOf(" ") + 1).toLong
- }
- }
- } catch {
- case ex: IOException ⇒ log.error("Error trying to read [{}]", filename)
- }
- contextSwitches
- }
-
- val (perProcessVoluntary, perProcessNonVoluntary) = contextSwitchesByProcess(pid)
- rcs.perProcessVoluntary.record(perProcessVoluntary)
- rcs.perProcessNonVoluntary.record(perProcessNonVoluntary)
- rcs.global.record(contextSwitches)
- }
-
- def verifiedSigarInstance: SigarProxy = {
- val sigar = new Sigar()
- printBanner(sigar)
- sigar
- }
-
- def provisionSigarLibrary: Unit = {
- val folder = SystemMetrics(context.system).sigarFolder
- SigarProvisioner.provision(new File(folder))
- }
-
- def createSigarInstance: SigarProxy = {
- // 1) Assume that library is already provisioned.
- try {
- return verifiedSigarInstance
- } catch {
- // Not using [[Try]] - any error is non-fatal in this case.
- case e: Throwable ⇒ log.info(s"Sigar is not yet provisioned: ${e}")
- }
-
- // 2) Attempt to provision library via sigar-loader.
- try {
- provisionSigarLibrary
- return verifiedSigarInstance
- } catch {
- // Not using [[Try]] - any error is non-fatal in this case.
- case e: Throwable ⇒ throw new UnexpectedSigarException(s"Failed to load Sigar: ${e}")
- }
- }
-}
-
-object SystemMetricsCollector {
- val NetworkFilter = Set("lo")
- val previousDiskMetrics = TrieMap[String, mutable.Map[String, Long]]()
- val previousNetworkMetrics = TrieMap[String, mutable.Map[String, Long]]()
-
- object Networks {
- val RxBytes = "rxBytes"
- val TxBytes = "txBytes"
- val RxErrors = "rxErrors"
- val TxErrors = "txErrors"
- val RxDropped = "rxDropped"
- val TxDropped = "txDropped"
- }
-
- object Disks {
- val Reads = "reads"
- val Writes = "writes"
- val Queue = "queue"
- val Service = "service"
- }
- case object Collect
-
- object OsUtils {
- def isLinux: Boolean = System.getProperty("os.name").indexOf("Linux") != -1
- }
-
- def props(collectInterval: FiniteDuration): Props = Props(classOf[SystemMetricsCollector], collectInterval)
-} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsExtension.scala b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsExtension.scala
new file mode 100644
index 00000000..df120611
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsExtension.scala
@@ -0,0 +1,70 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2014 the kamon project <http://kamon.io/>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ * =========================================================================================
+ */
+package kamon.system
+
+import java.io.File
+import akka.actor._
+import akka.event.Logging
+import kamon.system.custom.{ ContextSwitchesUpdater, ContextSwitchesMetrics }
+import kamon.system.jmx._
+import kamon.{ ModuleSupervisor, Kamon }
+import kamon.metric._
+import kamon.sigar.SigarProvisioner
+import kamon.system.sigar.SigarMetricsUpdater
+
+import kamon.util.ConfigTools.Syntax
+
+object SystemMetrics extends ExtensionId[SystemMetricsExtension] with ExtensionIdProvider {
+ override def lookup(): ExtensionId[_ <: Extension] = SystemMetrics
+ override def createExtension(system: ExtendedActorSystem): SystemMetricsExtension = new SystemMetricsExtension(system)
+}
+
+class SystemMetricsExtension(system: ExtendedActorSystem) extends Kamon.Extension {
+
+ val log = Logging(system, classOf[SystemMetricsExtension])
+ log.info(s"Starting the Kamon(SystemMetrics) extension")
+
+ val config = system.settings.config.getConfig("kamon.system-metrics")
+ val sigarFolder = config.getString("sigar-native-folder")
+ val sigarRefreshInterval = config.getFiniteDuration("sigar-metrics-refresh-interval")
+ val contextSwitchesRefreshInterval = config.getFiniteDuration("context-switches-refresh-interval")
+ val metricsExtension = Kamon(Metrics)(system)
+
+ // Sigar-based metrics
+ SigarProvisioner.provision(new File(sigarFolder))
+ val sigarMetricsRecorder = ModuleSupervisor.get(system).createModule("sigar-metrics-recorder",
+ SigarMetricsUpdater.props(sigarRefreshInterval).withDispatcher("kamon.system-metrics.sigar-dispatcher"))
+
+ // JMX Metrics
+ ClassLoadingMetrics.register(metricsExtension)
+ GarbageCollectionMetrics.register(metricsExtension)
+ HeapMemoryMetrics.register(metricsExtension)
+ NonHeapMemoryMetrics.register(metricsExtension)
+ ThreadsMetrics.register(metricsExtension)
+
+ // If we are in Linux, add ContextSwitchesMetrics as well.
+ if (isLinux) {
+ val contextSwitchesRecorder = ContextSwitchesMetrics.register(system, contextSwitchesRefreshInterval)
+
+ ModuleSupervisor.get(system).createModule("context-switches-metrics-recorder",
+ ContextSwitchesUpdater.props(contextSwitchesRecorder, sigarRefreshInterval)
+ .withDispatcher("kamon.system-metrics.context-switches-dispatcher"))
+ }
+
+ def isLinux: Boolean =
+ System.getProperty("os.name").indexOf("Linux") != -1
+
+} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala
new file mode 100644
index 00000000..a3c56733
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala
@@ -0,0 +1,96 @@
+package kamon.system.custom
+
+import java.io.IOException
+import java.nio.charset.StandardCharsets
+import java.nio.file.{ Paths, Files }
+
+import akka.actor.{ Props, Actor, ActorSystem }
+import akka.event.{ Logging, LoggingAdapter }
+import kamon.Kamon
+import kamon.metric._
+import kamon.metric.instrument.InstrumentFactory
+import kamon.system.custom.ContextSwitchesUpdater.UpdateContextSwitches
+import org.hyperic.sigar.Sigar
+import scala.collection.JavaConverters.iterableAsScalaIterableConverter
+import scala.concurrent.duration.FiniteDuration
+
+class ContextSwitchesMetrics(pid: Long, log: LoggingAdapter, instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) {
+ val perProcessVoluntary = histogram("context-switches-process-voluntary")
+ val perProcessNonVoluntary = histogram("context-switches-process-non-voluntary")
+ val global = histogram("context-switches-global")
+
+ def update(): Unit = {
+ def contextSwitchesByProcess(pid: Long): (Long, Long) = {
+ val filename = s"/proc/$pid/status"
+ var voluntaryContextSwitches = 0L
+ var nonVoluntaryContextSwitches = 0L
+
+ try {
+ for (line ← Files.readAllLines(Paths.get(filename), StandardCharsets.US_ASCII).asScala.toList) {
+ if (line.startsWith("voluntary_ctxt_switches")) {
+ voluntaryContextSwitches = line.substring(line.indexOf(":") + 1).trim.toLong
+ }
+ if (line.startsWith("nonvoluntary_ctxt_switches")) {
+ nonVoluntaryContextSwitches = line.substring(line.indexOf(":") + 1).trim.toLong
+ }
+ }
+ } catch {
+ case ex: IOException ⇒ log.error("Error trying to read [{}]", filename)
+ }
+ (voluntaryContextSwitches, nonVoluntaryContextSwitches)
+ }
+
+ def contextSwitches: Long = {
+ val filename = "/proc/stat"
+ var contextSwitches = 0L
+
+ try {
+ for (line ← Files.readAllLines(Paths.get(filename), StandardCharsets.US_ASCII).asScala.toList) {
+ if (line.startsWith("rcs")) {
+ contextSwitches = line.substring(line.indexOf(" ") + 1).toLong
+ }
+ }
+ } catch {
+ case ex: IOException ⇒ log.error("Error trying to read [{}]", filename)
+ }
+ contextSwitches
+ }
+
+ val (voluntary, nonVoluntary) = contextSwitchesByProcess(pid)
+ perProcessVoluntary.record(voluntary)
+ perProcessNonVoluntary.record(nonVoluntary)
+ global.record(contextSwitches)
+ }
+}
+
+object ContextSwitchesMetrics {
+
+ def register(system: ActorSystem, refreshInterval: FiniteDuration): ContextSwitchesMetrics = {
+ val metricsExtension = Kamon(Metrics)(system)
+ val log = Logging(system, "ContextSwitchesMetrics")
+ val pid = (new Sigar).getPid
+
+ val instrumentFactory = metricsExtension.instrumentFactory("system-metric")
+ metricsExtension.register(Entity("context-switches", "system-metric"), new ContextSwitchesMetrics(pid, log, instrumentFactory)).recorder
+ }
+}
+
+class ContextSwitchesUpdater(csm: ContextSwitchesMetrics, refreshInterval: FiniteDuration) extends Actor {
+ val schedule = context.system.scheduler.schedule(refreshInterval, refreshInterval, self, UpdateContextSwitches)(context.dispatcher)
+
+ def receive = {
+ case UpdateContextSwitches ⇒ csm.update()
+ }
+
+ override def postStop(): Unit = {
+ schedule.cancel()
+ super.postStop()
+ }
+}
+
+object ContextSwitchesUpdater {
+ case object UpdateContextSwitches
+
+ def props(csm: ContextSwitchesMetrics, refreshInterval: FiniteDuration): Props =
+ Props(new ContextSwitchesUpdater(csm, refreshInterval))
+} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/jmx/ClassLoadingMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/jmx/ClassLoadingMetrics.scala
new file mode 100644
index 00000000..d9379738
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/ClassLoadingMetrics.scala
@@ -0,0 +1,28 @@
+package kamon.system.jmx
+
+import java.lang.management.ManagementFactory
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+
+class ClassLoadingMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) {
+ val classLoadingBean = ManagementFactory.getClassLoadingMXBean
+
+ gauge("classes-loaded", Memory.Bytes, () ⇒ {
+ classLoadingBean.getTotalLoadedClassCount
+ })
+
+ gauge("classes-unloaded", Memory.Bytes, () ⇒ {
+ classLoadingBean.getUnloadedClassCount
+ })
+
+ gauge("classes-currently-loaded", Memory.Bytes, () ⇒ {
+ classLoadingBean.getLoadedClassCount.toLong
+ })
+
+}
+
+object ClassLoadingMetrics extends JmxSystemMetricRecorderCompanion("class-loading") {
+ def apply(instrumentFactory: InstrumentFactory): ClassLoadingMetrics =
+ new ClassLoadingMetrics(instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala
new file mode 100644
index 00000000..b7d2fe6a
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala
@@ -0,0 +1,34 @@
+package kamon.system.jmx
+
+import java.lang.management.{ GarbageCollectorMXBean, ManagementFactory }
+
+import kamon.metric.{ Entity, MetricsExtension, GenericEntityRecorder }
+import kamon.metric.instrument.{ DifferentialValueCollector, Time, InstrumentFactory }
+import scala.collection.JavaConverters._
+
+class GarbageCollectionMetrics(gc: GarbageCollectorMXBean, instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) {
+
+ gauge("garbage-collection-count", DifferentialValueCollector(() ⇒ {
+ gc.getCollectionCount
+ }))
+
+ gauge("garbage-collection-time", Time.Milliseconds, DifferentialValueCollector(() ⇒ {
+ gc.getCollectionTime
+ }))
+
+}
+
+object GarbageCollectionMetrics {
+
+ def sanitizeCollectorName(name: String): String =
+ name.replaceAll("""[^\w]""", "-").toLowerCase
+
+ def register(metricsExtension: MetricsExtension): Unit = {
+
+ val instrumentFactory = metricsExtension.instrumentFactory("system-metric")
+ ManagementFactory.getGarbageCollectorMXBeans.asScala.filter(_.isValid) map { gc ⇒
+ val gcName = sanitizeCollectorName(gc.getName)
+ metricsExtension.register(Entity(s"$gcName-garbage-collector", "system-metric"), new GarbageCollectionMetrics(gc, instrumentFactory))
+ }
+ }
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/jmx/HeapMemoryMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/jmx/HeapMemoryMetrics.scala
new file mode 100644
index 00000000..a96b5319
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/HeapMemoryMetrics.scala
@@ -0,0 +1,29 @@
+package kamon.system.jmx
+
+import java.lang.management.ManagementFactory
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+
+class HeapMemoryMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) {
+ val memoryBean = ManagementFactory.getMemoryMXBean
+ def nonHeapUsage = memoryBean.getHeapMemoryUsage
+
+ gauge("heap-used", Memory.Bytes, () ⇒ {
+ nonHeapUsage.getUsed
+ })
+
+ gauge("heap-max", Memory.Bytes, () ⇒ {
+ nonHeapUsage.getMax
+ })
+
+ gauge("heap-committed", Memory.Bytes, () ⇒ {
+ nonHeapUsage.getCommitted
+ })
+
+}
+
+object HeapMemoryMetrics extends JmxSystemMetricRecorderCompanion("heap-memory") {
+ def apply(instrumentFactory: InstrumentFactory): HeapMemoryMetrics =
+ new HeapMemoryMetrics(instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala b/kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala
new file mode 100644
index 00000000..d19622e6
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala
@@ -0,0 +1,13 @@
+package kamon.system.jmx
+
+import kamon.metric.instrument.InstrumentFactory
+import kamon.metric.{ Entity, EntityRecorder, MetricsExtension }
+
+abstract class JmxSystemMetricRecorderCompanion(metricName: String) {
+ def register(metricsExtension: MetricsExtension): EntityRecorder = {
+ val instrumentFactory = metricsExtension.instrumentFactory("system-metric")
+ metricsExtension.register(Entity(metricName, "system-metric"), apply(instrumentFactory)).recorder
+ }
+
+ def apply(instrumentFactory: InstrumentFactory): EntityRecorder
+} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/jmx/NonHeapMemoryMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/jmx/NonHeapMemoryMetrics.scala
new file mode 100644
index 00000000..34a23d4f
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/NonHeapMemoryMetrics.scala
@@ -0,0 +1,33 @@
+package kamon.system.jmx
+
+import java.lang.management.ManagementFactory
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+
+class NonHeapMemoryMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) {
+ val memoryBean = ManagementFactory.getMemoryMXBean
+ def nonHeapUsage = memoryBean.getNonHeapMemoryUsage
+
+ gauge("non-heap-used", Memory.Bytes, () ⇒ {
+ nonHeapUsage.getUsed
+ })
+
+ gauge("non-heap-max", Memory.Bytes, () ⇒ {
+ val max = nonHeapUsage.getMax
+
+ // .getMax can return -1 if the max is not defined.
+ if (max >= 0) max
+ else 0
+ })
+
+ gauge("non-heap-committed", Memory.Bytes, () ⇒ {
+ nonHeapUsage.getCommitted
+ })
+
+}
+
+object NonHeapMemoryMetrics extends JmxSystemMetricRecorderCompanion("non-heap-memory") {
+ def apply(instrumentFactory: InstrumentFactory): NonHeapMemoryMetrics =
+ new NonHeapMemoryMetrics(instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/jmx/ThreadsMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/jmx/ThreadsMetrics.scala
new file mode 100644
index 00000000..b33eb3e6
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/ThreadsMetrics.scala
@@ -0,0 +1,28 @@
+package kamon.system.jmx
+
+import java.lang.management.ManagementFactory
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.InstrumentFactory
+
+class ThreadsMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) {
+ val threadsBean = ManagementFactory.getThreadMXBean
+
+ gauge("daemon-thread-count", () ⇒ {
+ threadsBean.getDaemonThreadCount.toLong
+ })
+
+ gauge("peak-thread-count", () ⇒ {
+ threadsBean.getPeakThreadCount.toLong
+ })
+
+ gauge("thread-count", () ⇒ {
+ threadsBean.getThreadCount.toLong
+ })
+
+}
+
+object ThreadsMetrics extends JmxSystemMetricRecorderCompanion("threads") {
+ def apply(instrumentFactory: InstrumentFactory): ThreadsMetrics =
+ new ThreadsMetrics(instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/CpuMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/CpuMetrics.scala
new file mode 100644
index 00000000..0a5f6494
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/CpuMetrics.scala
@@ -0,0 +1,29 @@
+package kamon.system.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.InstrumentFactory
+import org.hyperic.sigar.Sigar
+
+class CpuMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val user = histogram("cpu-user")
+ val system = histogram("cpu-system")
+ val Wait = histogram("cpu-wait")
+ val idle = histogram("cpu-idle")
+ val stolen = histogram("cpu-stolen")
+
+ def update(sigar: Sigar): Unit = {
+ val cpuPerc = sigar.getCpuPerc
+
+ user.record((cpuPerc.getUser * 100L).toLong)
+ system.record((cpuPerc.getSys * 100L).toLong)
+ Wait.record((cpuPerc.getWait * 100L).toLong)
+ idle.record((cpuPerc.getIdle * 100L).toLong)
+ stolen.record((cpuPerc.getStolen * 100L).toLong)
+ }
+}
+
+object CpuMetrics extends SigarMetricRecorderCompanion("cpu") {
+
+ def apply(instrumentFactory: InstrumentFactory): CpuMetrics =
+ new CpuMetrics(instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/DiffRecordingHistogram.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/DiffRecordingHistogram.scala
new file mode 100644
index 00000000..94aa76d1
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/DiffRecordingHistogram.scala
@@ -0,0 +1,41 @@
+package kamon.system.sigar
+
+import java.util.concurrent.atomic.AtomicLong
+
+import kamon.metric.instrument.{ CollectionContext, Histogram }
+
+/**
+ * Wrapper Histogram for cases in which the recorded values should always be the difference
+ * between the current value and the last recorded value. This is not thread-safe and only
+ * to be used with Sigar-based metrics that are securely updated within an actor.
+ */
+class DiffRecordingHistogram(wrappedHistogram: Histogram) extends Histogram {
+ @volatile private var _recordedAtLeastOnce = false
+ private val _lastObservedValue = new AtomicLong(0)
+
+ private def processRecording(value: Long, count: Long): Unit = {
+ if (_recordedAtLeastOnce)
+ wrappedHistogram.record(value - _lastObservedValue.getAndSet(value), count)
+ else {
+ _lastObservedValue.set(value)
+ _recordedAtLeastOnce = true
+ }
+ }
+
+ def record(value: Long): Unit =
+ processRecording(value, 1)
+
+ def record(value: Long, count: Long): Unit =
+ processRecording(value, count)
+
+ def cleanup: Unit =
+ wrappedHistogram.cleanup
+
+ def collect(context: CollectionContext): Histogram.Snapshot =
+ wrappedHistogram.collect(context)
+}
+
+object DiffRecordingHistogram {
+ def apply(histogram: Histogram): DiffRecordingHistogram =
+ new DiffRecordingHistogram(histogram)
+} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/FileSystemMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/FileSystemMetrics.scala
new file mode 100644
index 00000000..dffebf5a
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/FileSystemMetrics.scala
@@ -0,0 +1,25 @@
+package kamon.system.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+import org.hyperic.sigar.{ DiskUsage, FileSystem, Sigar }
+
+class FileSystemMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val reads = DiffRecordingHistogram(histogram("file-system-reads", Memory.Bytes))
+ val writes = DiffRecordingHistogram(histogram("file-system-writes", Memory.Bytes))
+
+ def sumOfAllFileSystems(sigar: Sigar, thunk: DiskUsage ⇒ Long): Long = {
+ val fileSystems = sigar.getFileSystemList.filter(_.getType == FileSystem.TYPE_LOCAL_DISK).map(_.getDevName).toSet
+ fileSystems.map(i ⇒ thunk(sigar.getDiskUsage(i))).fold(0L)(_ + _)
+ }
+
+ def update(sigar: Sigar): Unit = {
+ reads.record(sumOfAllFileSystems(sigar, _.getReadBytes))
+ writes.record(sumOfAllFileSystems(sigar, _.getWriteBytes))
+ }
+}
+
+object FileSystemMetrics extends SigarMetricRecorderCompanion("file-system") {
+ def apply(instrumentFactory: InstrumentFactory): FileSystemMetrics =
+ new FileSystemMetrics(instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/LoadAverageMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/LoadAverageMetrics.scala
new file mode 100644
index 00000000..3e02cc8f
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/LoadAverageMetrics.scala
@@ -0,0 +1,25 @@
+package kamon.system.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.InstrumentFactory
+import org.hyperic.sigar.Sigar
+
+class LoadAverageMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val oneMinute = histogram("one-minute")
+ val fiveMinutes = histogram("five-minutes")
+ val fifteenMinutes = histogram("fifteen-minutes")
+
+ def update(sigar: Sigar): Unit = {
+ val loadAverage = sigar.getLoadAverage
+
+ oneMinute.record(loadAverage(0).toLong)
+ fiveMinutes.record(loadAverage(1).toLong)
+ fifteenMinutes.record(loadAverage(2).toLong)
+ }
+}
+
+object LoadAverageMetrics extends SigarMetricRecorderCompanion("load-average") {
+
+ def apply(instrumentFactory: InstrumentFactory): LoadAverageMetrics =
+ new LoadAverageMetrics(instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/MemoryMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/MemoryMetrics.scala
new file mode 100644
index 00000000..ab7fcd88
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/MemoryMetrics.scala
@@ -0,0 +1,36 @@
+package kamon.system.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+import org.hyperic.sigar.Sigar
+
+/**
+ * System memory usage metrics, as reported by Sigar:
+ * - used: Total used system memory.
+ * - free: Total free system memory (e.g. Linux plus cached).
+ * - swap-used: Total used system swap..
+ * - swap-free: Total free system swap.
+ */
+class MemoryMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val used = histogram("memory-used", Memory.Bytes)
+ val free = histogram("memory-free", Memory.Bytes)
+ val swapUsed = histogram("swap-used", Memory.Bytes)
+ val swapFree = histogram("swap-free", Memory.Bytes)
+
+ def update(sigar: Sigar): Unit = {
+ val mem = sigar.getMem
+ val swap = sigar.getSwap
+
+ used.record(mem.getUsed)
+ free.record(mem.getFree)
+ swapUsed.record(swap.getUsed)
+ swapFree.record(swap.getFree)
+ }
+}
+
+object MemoryMetrics extends SigarMetricRecorderCompanion("memory") {
+
+ def apply(instrumentFactory: InstrumentFactory): MemoryMetrics =
+ new MemoryMetrics(instrumentFactory)
+}
+
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/NetworkMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/NetworkMetrics.scala
new file mode 100644
index 00000000..fb33b7e4
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/NetworkMetrics.scala
@@ -0,0 +1,33 @@
+package kamon.system.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument._
+import org.hyperic.sigar.{ NetInterfaceStat, Sigar }
+
+class NetworkMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val receivedBytes = DiffRecordingHistogram(histogram("rx-bytes", Memory.Bytes))
+ val transmittedBytes = DiffRecordingHistogram(histogram("tx-bytes", Memory.Bytes))
+ val receiveErrors = DiffRecordingHistogram(histogram("rx-errors"))
+ val transmitErrors = DiffRecordingHistogram(histogram("tx-errors"))
+ val receiveDrops = DiffRecordingHistogram(histogram("rx-dropped"))
+ val transmitDrops = DiffRecordingHistogram(histogram("tx-dropped"))
+
+ def sumOfAllInterfaces(sigar: Sigar, thunk: NetInterfaceStat ⇒ Long): Long = {
+ val interfaces = sigar.getNetInterfaceList.toList.filter(_ != "lo")
+ interfaces.map(i ⇒ thunk(sigar.getNetInterfaceStat(i))).fold(0L)(_ + _)
+ }
+
+ def update(sigar: Sigar): Unit = {
+ receivedBytes.record(sumOfAllInterfaces(sigar, _.getRxBytes))
+ transmittedBytes.record(sumOfAllInterfaces(sigar, _.getTxBytes))
+ receiveErrors.record(sumOfAllInterfaces(sigar, _.getRxErrors))
+ transmitErrors.record(sumOfAllInterfaces(sigar, _.getTxErrors))
+ receiveDrops.record(sumOfAllInterfaces(sigar, _.getRxDropped))
+ transmitDrops.record(sumOfAllInterfaces(sigar, _.getTxDropped))
+ }
+}
+
+object NetworkMetrics extends SigarMetricRecorderCompanion("network") {
+ def apply(instrumentFactory: InstrumentFactory): NetworkMetrics =
+ new NetworkMetrics(instrumentFactory)
+} \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/ProcessCpuMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/ProcessCpuMetrics.scala
new file mode 100644
index 00000000..0ca5c1c8
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/ProcessCpuMetrics.scala
@@ -0,0 +1,39 @@
+package kamon.system.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.InstrumentFactory
+import org.hyperic.sigar.{ ProcCpu, Sigar }
+
+class ProcessCpuMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val processUserCpu = histogram("process-user-cpu")
+ val processSystemCpu = histogram("process-system-cpu")
+ val processTotalCpu = histogram("process-cpu")
+
+ var lastProcCpu: Option[ProcCpu] = None
+
+ def update(sigar: Sigar): Unit = {
+ val pid = sigar.getPid
+ val procCpu = sigar.getProcCpu(pid)
+
+ lastProcCpu.map { last ⇒
+ val timeDiff = procCpu.getLastTime - last.getLastTime
+ if (timeDiff > 0) {
+ val userPercent = (((procCpu.getUser - last.getUser) / timeDiff.toDouble) * 100).toLong
+ val systemPercent = (((procCpu.getSys - last.getSys) / timeDiff.toDouble) * 100).toLong
+
+ processUserCpu.record(userPercent)
+ processSystemCpu.record(systemPercent)
+ processTotalCpu.record(userPercent + systemPercent)
+ }
+ }
+
+ lastProcCpu = Some(procCpu)
+
+ }
+}
+
+object ProcessCpuMetrics extends SigarMetricRecorderCompanion("process-cpu") {
+
+ def apply(instrumentFactory: InstrumentFactory): ProcessCpuMetrics =
+ new ProcessCpuMetrics(instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala
new file mode 100644
index 00000000..8a430427
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala
@@ -0,0 +1,59 @@
+package kamon.system.sigar
+
+import akka.actor.{ Props, Actor }
+import kamon.Kamon
+import kamon.metric.instrument.InstrumentFactory
+import kamon.metric.{ Entity, EntityRecorder, MetricsExtension, Metrics }
+import kamon.system.sigar.SigarMetricsUpdater.UpdateSigarMetrics
+import org.hyperic.sigar.Sigar
+
+import scala.concurrent.duration.FiniteDuration
+
+class SigarMetricsUpdater(refreshInterval: FiniteDuration) extends Actor {
+ val sigar = new Sigar
+ val metricsExtension = Kamon(Metrics)(context.system)
+
+ val sigarMetrics = List(
+ CpuMetrics.register(metricsExtension),
+ FileSystemMetrics.register(metricsExtension),
+ LoadAverageMetrics.register(metricsExtension),
+ MemoryMetrics.register(metricsExtension),
+ NetworkMetrics.register(metricsExtension),
+ ProcessCpuMetrics.register(metricsExtension))
+
+ val refreshSchedule = context.system.scheduler.schedule(refreshInterval, refreshInterval, self, UpdateSigarMetrics)(context.dispatcher)
+
+ def receive = {
+ case UpdateSigarMetrics ⇒ updateMetrics()
+ }
+
+ def updateMetrics(): Unit = {
+ sigarMetrics.foreach(_.update(sigar))
+ }
+
+ override def postStop(): Unit = {
+ refreshSchedule.cancel()
+ super.postStop()
+ }
+}
+
+object SigarMetricsUpdater {
+ def props(refreshInterval: FiniteDuration): Props =
+ Props(new SigarMetricsUpdater((refreshInterval)))
+
+ case object UpdateSigarMetrics
+}
+
+trait SigarMetric extends EntityRecorder {
+ def update(sigar: Sigar): Unit
+}
+
+abstract class SigarMetricRecorderCompanion(metricName: String) {
+ def register(metricsExtension: MetricsExtension): SigarMetric = {
+ val instrumentFactory = metricsExtension.instrumentFactory("system-metric")
+ metricsExtension.register(Entity(metricName, "system-metric"), apply(instrumentFactory)).recorder
+ }
+
+ def apply(instrumentFactory: InstrumentFactory): SigarMetric
+}
+
diff --git a/kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala b/kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala
index c9530160..4d633952 100644
--- a/kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala
+++ b/kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala
@@ -15,406 +15,140 @@
package kamon.metric
-import akka.actor.ActorSystem
-import akka.testkit.{ TestKitBase, TestProbe }
-import com.typesafe.config.ConfigFactory
-import kamon.Kamon
-import kamon.metric.Subscriptions.TickMetricSnapshot
-import kamon.metrics.CPUMetrics.CPUMetricSnapshot
-import kamon.metrics.ClassLoadingMetrics.ClassLoadingMetricSnapshot
-import kamon.metrics.ContextSwitchesMetrics.ContextSwitchesMetricsSnapshot
-import kamon.metrics.DiskMetrics.DiskMetricsSnapshot
-import kamon.metrics.GCMetrics.GCMetricSnapshot
-import kamon.metrics.HeapMetrics.HeapMetricSnapshot
-import kamon.metrics.LoadAverageMetrics.LoadAverageMetricsSnapshot
-import kamon.metrics.MemoryMetrics.MemoryMetricSnapshot
-import kamon.metrics.NetworkMetrics.NetworkMetricSnapshot
-import kamon.metrics.NonHeapMetrics.NonHeapMetricSnapshot
-import kamon.metrics.ProcessCPUMetrics.ProcessCPUMetricsSnapshot
-import kamon.metrics.ThreadMetrics.ThreadMetricSnapshot
-import kamon.metrics._
-import kamon.system.SystemMetricsExtension
-import org.scalatest.{ Matchers, WordSpecLike }
-
-import scala.concurrent.duration._
-
-class SystemMetricsSpec extends TestKitBase with WordSpecLike with Matchers with RedirectLogging {
- implicit lazy val system: ActorSystem = ActorSystem("system-metrics-spec", ConfigFactory.parseString(
- """
- |akka {
- | extensions = ["kamon.system.SystemMetrics"]
- |}
- |
- |kamon.metrics {
- | disable-aspectj-weaver-missing-error = true
- | tick-interval = 1 second
- |}
- """.stripMargin))
-
- "the Kamon CPU Metrics" should {
- "record user, system, wait, idle, stolen metrics" in new CPUMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val CPUMetrics = expectCPUMetrics(metricsListener, 3 seconds)
- CPUMetrics.user.max should be >= 0L
- CPUMetrics.system.max should be >= 0L
- CPUMetrics.cpuWait.max should be >= 0L
- CPUMetrics.idle.max should be >= 0L
- CPUMetrics.stolen.max should be >= 0L
- }
- }
- "the Kamon GC Metrics" should {
- "record count, time metrics" in new GCMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val GCMetrics = expectGCMetrics(metricsListener, 3 seconds)
- GCMetrics.count.max should be >= 0L
- GCMetrics.time.max should be >= 0L
- }
- }
-
- "the Kamon Heap Metrics" should {
- "record used, max, commited metrics" in new HeapMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val HeapMetrics = expectHeapMetrics(metricsListener, 3 seconds)
- HeapMetrics.used.max should be >= 0L
- HeapMetrics.max.max should be >= 0L
- HeapMetrics.committed.max should be >= 0L
- }
- }
-
- "the Kamon Non-Heap Metrics" should {
- "record used, max, commited metrics" in new NonHeapMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val NonHeapMetrics = expectNonHeapMetrics(metricsListener, 3 seconds)
- NonHeapMetrics.used.max should be >= 0L
- NonHeapMetrics.max.max should be >= 0L
- NonHeapMetrics.committed.max should be >= 0L
- }
- }
-
- "the Kamon Thread Metrics" should {
- "record daemon, count, peak metrics" in new ThreadMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val ThreadMetrics = expectThreadMetrics(metricsListener, 3 seconds)
- ThreadMetrics.daemon.max should be >= 0L
- ThreadMetrics.count.max should be >= 0L
- ThreadMetrics.peak.max should be >= 0L
- }
- }
-
- "the Kamon ClassLoading Metrics" should {
- "record loaded, unloaded, current metrics" in new ClassLoadingMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
+import java.lang.management.ManagementFactory
- val ClassLoadingMetrics = expectClassLoadingMetrics(metricsListener, 3 seconds)
- ClassLoadingMetrics.loaded.max should be >= 0L
- ClassLoadingMetrics.unloaded.max should be >= 0L
- ClassLoadingMetrics.current.max should be >= 0L
- }
- }
-
- "the Kamon Disk Metrics" should {
- "record reads, writes, queue, service time metrics" in new DiskMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val DiskMetrics = expectDiskMetrics(metricsListener, 3 seconds)
- DiskMetrics.reads.max should be >= 0L
- DiskMetrics.writes.max should be >= 0L
- DiskMetrics.queue.max should be >= 0L
- DiskMetrics.serviceTime.max should be >= 0L
- }
- }
-
- "the Kamon Load Average Metrics" should {
- "record 1 minute, 5 minutes and 15 minutes metrics" in new LoadAverageMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val LoadAverageMetrics = expectLoadAverageMetrics(metricsListener, 3 seconds)
- LoadAverageMetrics.one.max should be >= 0L
- LoadAverageMetrics.five.max should be >= 0L
- LoadAverageMetrics.fifteen.max should be >= 0L
- }
- }
+import com.typesafe.config.ConfigFactory
+import kamon.system.jmx.GarbageCollectionMetrics
+import kamon.testkit.BaseKamonSpec
+import scala.collection.JavaConverters._
- "the Kamon Memory Metrics" should {
- "record used, free, buffer, cache, swap used, swap free metrics" in new MemoryMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val MemoryMetrics = expectMemoryMetrics(metricsListener, 3 seconds)
- MemoryMetrics.used.max should be >= 0L
- MemoryMetrics.free.max should be >= 0L
- MemoryMetrics.buffer.max should be >= 0L
- MemoryMetrics.cache.max should be >= 0L
- MemoryMetrics.swapUsed.max should be >= 0L
- MemoryMetrics.swapFree.max should be >= 0L
- }
- }
+class SystemMetricsSpec extends BaseKamonSpec("system-metrics-spec") with RedirectLogging {
- "the Kamon Network Metrics" should {
- "record rxBytes, txBytes, rxErrors, txErrors, rxDropped, txDropped metrics" in new NetworkMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
-
- val NetworkMetrics = expectNetworkMetrics(metricsListener, 3 seconds)
- NetworkMetrics.rxBytes.max should be >= 0L
- NetworkMetrics.txBytes.max should be >= 0L
- NetworkMetrics.rxErrors.max should be >= 0L
- NetworkMetrics.txErrors.max should be >= 0L
- NetworkMetrics.rxDropped.max should be >= 0L
- NetworkMetrics.txDropped.max should be >= 0L
- }
- }
-
- "the Kamon Process CPU Metrics" should {
- "record Cpu Percent, Total Process Time metrics" in new ProcessCPUMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
+ override lazy val config =
+ ConfigFactory.parseString(
+ """
+ |kamon.metric {
+ | tick-interval = 1 hour
+ |}
+ |
+ |akka {
+ | extensions = ["kamon.system.SystemMetrics"]
+ |}
+ """.stripMargin)
- val ProcessCPUMetrics = expectProcessCPUMetrics(metricsListener, 3 seconds)
- ProcessCPUMetrics.cpuPercent.max should be >= 0L
- ProcessCPUMetrics.totalProcessTime.max should be >= 0L
- }
- }
+ override protected def beforeAll(): Unit =
+ Thread.sleep(2000) // Give some room to the recorders to store some values.
- "the Kamon ContextSwitches Metrics" should {
- "record Context Switches Global, Voluntary and Non Voluntary metrics" in new ContextSwitchesMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
+ "the Kamon System Metrics module" should {
+ "record user, system, wait, idle and stolen CPU metrics" in {
+ val cpuMetrics = takeSnapshotOf("cpu", "system-metric")
- val ContextSwitchesMetrics = expectContextSwitchesMetrics(metricsListener, 3 seconds)
- ContextSwitchesMetrics.perProcessVoluntary.max should be >= 0L
- ContextSwitchesMetrics.perProcessNonVoluntary.max should be >= 0L
- ContextSwitchesMetrics.global.max should be >= 0L
+ cpuMetrics.histogram("cpu-user").get.numberOfMeasurements should be > 0L
+ cpuMetrics.histogram("cpu-system").get.numberOfMeasurements should be > 0L
+ cpuMetrics.histogram("cpu-wait").get.numberOfMeasurements should be > 0L
+ cpuMetrics.histogram("cpu-idle").get.numberOfMeasurements should be > 0L
+ cpuMetrics.histogram("cpu-stolen").get.numberOfMeasurements should be > 0L
}
- }
- def expectCPUMetrics(listener: TestProbe, waitTime: FiniteDuration): CPUMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
- }
- val cpuMetricsOption = tickSnapshot.metrics.get(CPUMetrics(SystemMetricsExtension.CPU))
- cpuMetricsOption should not be empty
- cpuMetricsOption.get.asInstanceOf[CPUMetricSnapshot]
- }
+ "record count and time garbage collection metrics" in {
+ val availableGarbageCollectors = ManagementFactory.getGarbageCollectorMXBeans.asScala.filter(_.isValid)
- trait CPUMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(CPUMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
- }
- }
+ for (collectorName ← availableGarbageCollectors) {
+ val sanitizedName = GarbageCollectionMetrics.sanitizeCollectorName(collectorName.getName)
+ val collectorMetrics = takeSnapshotOf(s"$sanitizedName-garbage-collector", "system-metric")
- def expectGCMetrics(listener: TestProbe, waitTime: FiniteDuration): GCMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
+ collectorMetrics.gauge("garbage-collection-count").get.numberOfMeasurements should be > 0L
+ collectorMetrics.gauge("garbage-collection-time").get.numberOfMeasurements should be > 0L
+ }
}
- val gcMetricsOption = tickSnapshot.metrics.get(GCMetrics(SystemMetricsExtension.garbageCollectors(0).getName.replaceAll("""[^\w]""", "-")))
- gcMetricsOption should not be empty
- gcMetricsOption.get.asInstanceOf[GCMetricSnapshot]
- }
+ "record used, max and committed heap metrics" in {
+ val heapMetrics = takeSnapshotOf("heap-memory", "system-metric")
- trait GCMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(GCMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
+ heapMetrics.gauge("heap-used").get.numberOfMeasurements should be > 0L
+ heapMetrics.gauge("heap-max").get.numberOfMeasurements should be > 0L
+ heapMetrics.gauge("heap-committed").get.numberOfMeasurements should be > 0L
}
- }
- def expectHeapMetrics(listener: TestProbe, waitTime: FiniteDuration): HeapMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
- }
- val heapMetricsOption = tickSnapshot.metrics.get(HeapMetrics(SystemMetricsExtension.Heap))
- heapMetricsOption should not be empty
- heapMetricsOption.get.asInstanceOf[HeapMetricSnapshot]
- }
+ "record used, max and committed non-heap metrics" in {
+ val nonHeapMetrics = takeSnapshotOf("non-heap-memory", "system-metric")
- trait HeapMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(HeapMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
+ nonHeapMetrics.gauge("non-heap-used").get.numberOfMeasurements should be > 0L
+ nonHeapMetrics.gauge("non-heap-max").get.numberOfMeasurements should be > 0L
+ nonHeapMetrics.gauge("non-heap-committed").get.numberOfMeasurements should be > 0L
}
- }
- trait NonHeapMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(NonHeapMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
- }
- }
+ "record daemon, count and peak jvm threads metrics" in {
+ val threadsMetrics = takeSnapshotOf("threads", "system-metric")
- def expectNonHeapMetrics(listener: TestProbe, waitTime: FiniteDuration): NonHeapMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
+ threadsMetrics.gauge("daemon-thread-count").get.numberOfMeasurements should be > 0L
+ threadsMetrics.gauge("peak-thread-count").get.numberOfMeasurements should be > 0L
+ threadsMetrics.gauge("thread-count").get.numberOfMeasurements should be > 0L
}
- val nonHeapMetricsOption = tickSnapshot.metrics.get(NonHeapMetrics(SystemMetricsExtension.NonHeap))
- nonHeapMetricsOption should not be empty
- nonHeapMetricsOption.get.asInstanceOf[NonHeapMetricSnapshot]
- }
- trait ThreadMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(ThreadMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
- }
- }
+ "record loaded, unloaded and current class loading metrics" in {
+ val classLoadingMetrics = takeSnapshotOf("class-loading", "system-metric")
- def expectThreadMetrics(listener: TestProbe, waitTime: FiniteDuration): ThreadMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
+ classLoadingMetrics.gauge("classes-loaded").get.numberOfMeasurements should be > 0L
+ classLoadingMetrics.gauge("classes-unloaded").get.numberOfMeasurements should be > 0L
+ classLoadingMetrics.gauge("classes-currently-loaded").get.numberOfMeasurements should be > 0L
}
- val threadMetricsOption = tickSnapshot.metrics.get(ThreadMetrics(SystemMetricsExtension.Threads))
- threadMetricsOption should not be empty
- threadMetricsOption.get.asInstanceOf[ThreadMetricSnapshot]
- }
- trait ClassLoadingMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(ClassLoadingMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
- }
- }
+ "record reads, writes, queue time and service time file system metrics" in {
+ val fileSystemMetrics = takeSnapshotOf("file-system", "system-metric")
- def expectClassLoadingMetrics(listener: TestProbe, waitTime: FiniteDuration): ClassLoadingMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
+ fileSystemMetrics.histogram("file-system-reads").get.numberOfMeasurements should be > 0L
+ fileSystemMetrics.histogram("file-system-writes").get.numberOfMeasurements should be > 0L
}
- val classLoadingMetricsOption = tickSnapshot.metrics.get(ClassLoadingMetrics(SystemMetricsExtension.Classes))
- classLoadingMetricsOption should not be empty
- classLoadingMetricsOption.get.asInstanceOf[ClassLoadingMetricSnapshot]
- }
- trait DiskMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(DiskMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
- }
- }
+ "record 1 minute, 5 minutes and 15 minutes metrics load average metrics" in {
+ val loadAverage = takeSnapshotOf("load-average", "system-metric")
- def expectDiskMetrics(listener: TestProbe, waitTime: FiniteDuration): DiskMetricsSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
+ loadAverage.histogram("one-minute").get.numberOfMeasurements should be > 0L
+ loadAverage.histogram("five-minutes").get.numberOfMeasurements should be > 0L
+ loadAverage.histogram("fifteen-minutes").get.numberOfMeasurements should be > 0L
}
- val diskMetricsOption = tickSnapshot.metrics.get(DiskMetrics(SystemMetricsExtension.Disk))
- diskMetricsOption should not be empty
- diskMetricsOption.get.asInstanceOf[DiskMetricsSnapshot]
- }
- trait LoadAverageMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(LoadAverageMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
- }
- }
+ "record used, free, swap used, swap free system memory metrics" in {
+ val memoryMetrics = takeSnapshotOf("memory", "system-metric")
- def expectLoadAverageMetrics(listener: TestProbe, waitTime: FiniteDuration): LoadAverageMetricsSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
+ memoryMetrics.histogram("memory-used").get.numberOfMeasurements should be > 0L
+ memoryMetrics.histogram("memory-free").get.numberOfMeasurements should be > 0L
+ memoryMetrics.histogram("swap-used").get.numberOfMeasurements should be > 0L
+ memoryMetrics.histogram("swap-free").get.numberOfMeasurements should be > 0L
}
- val loadAverageMetricsOption = tickSnapshot.metrics.get(LoadAverageMetrics(SystemMetricsExtension.LoadAverage))
- loadAverageMetricsOption should not be empty
- loadAverageMetricsOption.get.asInstanceOf[LoadAverageMetricsSnapshot]
- }
- def expectMemoryMetrics(listener: TestProbe, waitTime: FiniteDuration): MemoryMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
- }
- val memoryMetricsOption = tickSnapshot.metrics.get(MemoryMetrics(SystemMetricsExtension.Memory))
- memoryMetricsOption should not be empty
- memoryMetricsOption.get.asInstanceOf[MemoryMetricSnapshot]
- }
+ "record rxBytes, txBytes, rxErrors, txErrors, rxDropped, txDropped network metrics" in {
+ val networkMetrics = takeSnapshotOf("network", "system-metric")
- trait MemoryMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(MemoryMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
+ networkMetrics.histogram("tx-bytes").get.numberOfMeasurements should be > 0L
+ networkMetrics.histogram("rx-bytes").get.numberOfMeasurements should be > 0L
+ networkMetrics.histogram("tx-errors").get.numberOfMeasurements should be > 0L
+ networkMetrics.histogram("rx-errors").get.numberOfMeasurements should be > 0L
+ networkMetrics.histogram("tx-dropped").get.numberOfMeasurements should be > 0L
+ networkMetrics.histogram("rx-dropped").get.numberOfMeasurements should be > 0L
}
- }
- def expectNetworkMetrics(listener: TestProbe, waitTime: FiniteDuration): NetworkMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
- }
- val networkMetricsOption = tickSnapshot.metrics.get(NetworkMetrics(SystemMetricsExtension.Network))
- networkMetricsOption should not be empty
- networkMetricsOption.get.asInstanceOf[NetworkMetricSnapshot]
- }
+ "record system and user CPU percentage for the application process" in {
+ val processCpuMetrics = takeSnapshotOf("process-cpu", "system-metric")
- trait NetworkMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(NetworkMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
+ processCpuMetrics.histogram("process-user-cpu").get.numberOfMeasurements should be > 0L
+ processCpuMetrics.histogram("process-system-cpu").get.numberOfMeasurements should be > 0L
+ processCpuMetrics.histogram("process-cpu").get.numberOfMeasurements should be > 0L
}
- }
- def expectProcessCPUMetrics(listener: TestProbe, waitTime: FiniteDuration): ProcessCPUMetricsSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
- }
- val processCPUMetricsOption = tickSnapshot.metrics.get(ProcessCPUMetrics(SystemMetricsExtension.ProcessCPU))
- processCPUMetricsOption should not be empty
- processCPUMetricsOption.get.asInstanceOf[ProcessCPUMetricsSnapshot]
- }
+ "record Context Switches Global, Voluntary and Non Voluntary metrics when running on Linux" in {
+ if (isLinux) {
+ val contextSwitchesMetrics = takeSnapshotOf("context-switches", "system-metric")
- trait ProcessCPUMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(ProcessCPUMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
+ contextSwitchesMetrics.histogram("context-switches-process-voluntary").get.numberOfMeasurements should be > 0L
+ contextSwitchesMetrics.histogram("context-switches-process-non-voluntary").get.numberOfMeasurements should be > 0L
+ contextSwitchesMetrics.histogram("context-switches-global").get.numberOfMeasurements should be > 0L
+ }
}
}
- def expectContextSwitchesMetrics(listener: TestProbe, waitTime: FiniteDuration): ContextSwitchesMetricsSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
- }
- val contextSwitchesMetricsOption = tickSnapshot.metrics.get(ContextSwitchesMetrics(SystemMetricsExtension.ContextSwitches))
- contextSwitchesMetricsOption should not be empty
- contextSwitchesMetricsOption.get.asInstanceOf[ContextSwitchesMetricsSnapshot]
- }
+ def isLinux: Boolean =
+ System.getProperty("os.name").indexOf("Linux") != -1
- trait ContextSwitchesMetricsListenerFixture {
- def subscribeToMetrics(): TestProbe = {
- val metricsListener = TestProbe()
- Kamon(Metrics).subscribe(ContextSwitchesMetrics, "*", metricsListener.ref, permanently = true)
- // Wait for one empty snapshot before proceeding to the test.
- metricsListener.expectMsgType[TickMetricSnapshot]
- metricsListener
- }
- }
}