aboutsummaryrefslogtreecommitdiff
path: root/kamon-system-metrics/src
diff options
context:
space:
mode:
authorIvan Topolnjak <ivantopo@gmail.com>2015-02-14 13:50:36 +0100
committerIvan Topolnjak <ivantopo@gmail.com>2015-02-14 13:50:36 +0100
commite931727454fbd97fb39d163255edbcdcd7bcdbc6 (patch)
tree98b4bdcaa1af1dbbf201036ce05021bc096db62f /kamon-system-metrics/src
parent8af0dfb1e2c8892023dd1bc6fbae1dae2ffb16ba (diff)
parent66b35556aa1bf0975cefa35603660991cdfcc526 (diff)
downloadKamon-e931727454fbd97fb39d163255edbcdcd7bcdbc6.tar.gz
Kamon-e931727454fbd97fb39d163255edbcdcd7bcdbc6.tar.bz2
Kamon-e931727454fbd97fb39d163255edbcdcd7bcdbc6.zip
Merge branch 'single-kamon-instance-per-jvm' into release-legacy-akka-2.2
Conflicts: kamon-akka-remote/src/test/scala/kamon/akka/instrumentation/RemotingInstrumentationSpec.scala kamon-core/src/main/scala/kamon/instrumentation/akka/ActorCellInstrumentation.scala kamon-core/src/main/scala/kamon/instrumentation/akka/AskPatternInstrumentation.scala kamon-core/src/main/scala/kamon/metric/MetricsExtension.scala kamon-core/src/main/scala/kamon/metric/Subscriptions.scala kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala kamon-core/src/main/scala/kamon/metric/instrument/MinMaxCounter.scala kamon-core/src/test/scala/kamon/instrumentation/akka/ActorCellInstrumentationSpec.scala kamon-core/src/test/scala/kamon/metric/ActorMetricsSpec.scala kamon-core/src/test/scala/kamon/metric/RouterMetricsSpec.scala kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala kamon-core/src/test/scala/kamon/metric/UserMetricsSpec.scala kamon-core/src/test/scala/kamon/trace/TraceContextManipulationSpec.scala kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala kamon-newrelic/src/main/scala/kamon/newrelic/Agent.scala kamon-newrelic/src/main/scala/kamon/newrelic/MetricReporter.scala kamon-play/src/main/scala/kamon/play/Play.scala kamon-play/src/main/scala/kamon/play/action/KamonTraceActions.scala kamon-play/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala kamon-play/src/main/scala/kamon/play/instrumentation/WSInstrumentation.scala kamon-play/src/test/scala/kamon/play/RequestInstrumentationSpec.scala kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala project/Dependencies.scala version.sbt
Diffstat (limited to 'kamon-system-metrics/src')
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/index21
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-freebsd-6.sobin210641 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-linux.sobin246605 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-solaris.sobin251360 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ia64-hpux-11.slbin577452 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ia64-linux.sobin494929 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-pa-hpux-11.slbin516096 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc-aix-5.sobin400925 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc-linux.sobin258547 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc64-aix-5.sobin425077 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc64-linux.sobin330767 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-s390x-linux.sobin269932 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-sparc-solaris.sobin285004 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-sparc64-solaris.sobin261896 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-universal-macosx.dylibbin377668 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-universal64-macosx.dylibbin397440 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-freebsd-5.sobin179751 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-freebsd-6.sobin179379 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-linux.sobin233385 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-solaris.sobin242880 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/sigar-amd64-winnt.dllbin402432 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/kamon/system/sigar/sigar-x86-winnt.dllbin266240 -> 0 bytes
-rw-r--r--kamon-system-metrics/src/main/resources/reference.conf243
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/CPUMetrics.scala84
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/ContextSwitchesMetrics.scala81
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala78
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/HeapMetrics.scala87
-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.scala83
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/metrics/ProcessCPUMetrics.scala76
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala64
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala176
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsExtension.scala71
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala118
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/ClassLoadingMetrics.scala48
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala54
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/HeapMemoryMetrics.scala49
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala29
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/NonHeapMemoryMetrics.scala53
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/jmx/ThreadsMetrics.scala48
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/CpuMetrics.scala53
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/DiffRecordingHistogram.scala60
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/FileSystemMetrics.scala48
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/LoadAverageMetrics.scala45
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/MemoryMetrics.scala57
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/NetworkMetrics.scala61
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/ProcessCpuMetrics.scala77
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarLoader.scala203
-rw-r--r--kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala75
-rw-r--r--kamon-system-metrics/src/test/scala/kamon/metrics/RedirectLogging.scala34
-rw-r--r--kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala416
51 files changed, 1255 insertions, 1429 deletions
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/index b/kamon-system-metrics/src/main/resources/kamon/system/sigar/index
deleted file mode 100644
index cad1f326..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/index
+++ /dev/null
@@ -1,21 +0,0 @@
-libsigar-amd64-freebsd-6.so
-libsigar-amd64-linux.so
-libsigar-amd64-solaris.so
-libsigar-ia64-hpux-11.sl
-libsigar-ia64-linux.so
-libsigar-pa-hpux-11.sl
-libsigar-ppc64-aix-5.so
-libsigar-ppc64-linux.so
-libsigar-ppc-aix-5.so
-libsigar-ppc-linux.so
-libsigar-s390x-linux.so
-libsigar-sparc64-solaris.so
-libsigar-sparc-solaris.so
-libsigar-universal64-macosx.dylib
-libsigar-universal-macosx.dylib
-libsigar-x86-freebsd-5.so
-libsigar-x86-freebsd-6.so
-libsigar-x86-linux.so
-libsigar-x86-solaris.so
-sigar-amd64-winnt.dll
-sigar-x86-winnt.dll \ No newline at end of file
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-freebsd-6.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-freebsd-6.so
deleted file mode 100644
index 3e94f0d2..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-freebsd-6.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-linux.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-linux.so
deleted file mode 100644
index 5a2e4c24..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-linux.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-solaris.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-solaris.so
deleted file mode 100644
index 6396482a..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-amd64-solaris.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ia64-hpux-11.sl b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ia64-hpux-11.sl
deleted file mode 100644
index d92ea4a9..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ia64-hpux-11.sl
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ia64-linux.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ia64-linux.so
deleted file mode 100644
index 2bd2fc8e..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ia64-linux.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-pa-hpux-11.sl b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-pa-hpux-11.sl
deleted file mode 100644
index 0dfd8a11..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-pa-hpux-11.sl
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc-aix-5.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc-aix-5.so
deleted file mode 100644
index 7d4b5199..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc-aix-5.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc-linux.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc-linux.so
deleted file mode 100644
index 4394b1b0..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc-linux.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc64-aix-5.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc64-aix-5.so
deleted file mode 100644
index 35fd8288..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc64-aix-5.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc64-linux.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc64-linux.so
deleted file mode 100644
index a1ba2529..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-ppc64-linux.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-s390x-linux.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-s390x-linux.so
deleted file mode 100644
index c275f4ac..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-s390x-linux.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-sparc-solaris.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-sparc-solaris.so
deleted file mode 100644
index aa847d2b..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-sparc-solaris.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-sparc64-solaris.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-sparc64-solaris.so
deleted file mode 100644
index 6c4fe809..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-sparc64-solaris.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-universal-macosx.dylib b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-universal-macosx.dylib
deleted file mode 100644
index 27ab1071..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-universal-macosx.dylib
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-universal64-macosx.dylib b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-universal64-macosx.dylib
deleted file mode 100644
index 0c721fec..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-universal64-macosx.dylib
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-freebsd-5.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-freebsd-5.so
deleted file mode 100644
index 8c50c611..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-freebsd-5.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-freebsd-6.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-freebsd-6.so
deleted file mode 100644
index f0800274..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-freebsd-6.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-linux.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-linux.so
deleted file mode 100644
index a0b64edd..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-linux.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-solaris.so b/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-solaris.so
deleted file mode 100644
index c6452e56..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/libsigar-x86-solaris.so
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/sigar-amd64-winnt.dll b/kamon-system-metrics/src/main/resources/kamon/system/sigar/sigar-amd64-winnt.dll
deleted file mode 100644
index 1ec8a035..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/sigar-amd64-winnt.dll
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/kamon/system/sigar/sigar-x86-winnt.dll b/kamon-system-metrics/src/main/resources/kamon/system/sigar/sigar-x86-winnt.dll
deleted file mode 100644
index 6afdc016..00000000
--- a/kamon-system-metrics/src/main/resources/kamon/system/sigar/sigar-x86-winnt.dll
+++ /dev/null
Binary files differ
diff --git a/kamon-system-metrics/src/main/resources/reference.conf b/kamon-system-metrics/src/main/resources/reference.conf
index fbdb3b89..57b34195 100644
--- a/kamon-system-metrics/src/main/resources/reference.conf
+++ b/kamon-system-metrics/src/main/resources/reference.conf
@@ -3,74 +3,187 @@
# ============================================ #
kamon {
- 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
- }
- }
-
- 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}
- }
-
- 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}
- }
+ system-metrics {
+
+ # 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
+ }
+
+ # Dispatcher to be used by the ContextSwitchesUpdater actor.
+ context-switches-dispatcher {
+ executor = "thread-pool-executor"
+ type = PinnedDispatcher
+ }
+ }
+
+ 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
+ }
+
+ 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
}
- jvm {
- heap {
- used = ${kamon.metrics.precision.default-gauge-precision}
- max = ${kamon.metrics.precision.default-gauge-precision}
- committed = ${kamon.metrics.precision.default-gauge-precision}
- }
-
- gc {
- count = ${kamon.metrics.precision.default-gauge-precision}
- time = ${kamon.metrics.precision.default-gauge-precision}
- }
+ 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}
+
+ }
+ }
+
+ modules {
+ kamon-system-metrics {
+ auto-start = yes
+ requires-aspectj = no
+ extension-id = "kamon.system.SystemMetrics"
}
}
} \ 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 ef7f225c..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/CPUMetrics.scala
+++ /dev/null
@@ -1,84 +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 class CPUMetricRecorder(user: Histogram, system: Histogram, cpuWait: Histogram, idle: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- CPUMetricSnapshot(user.collect(context), system.collect(context), cpuWait.collect(context), idle.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class CPUMetricSnapshot(user: Histogram.Snapshot, system: Histogram.Snapshot, cpuWait: Histogram.Snapshot, idle: 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))
- }
-
- lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- User -> user,
- System -> system,
- Wait -> cpuWait,
- Idle -> idle)
- }
-
- 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")
-
- new CPUMetricRecorder(
- Histogram.fromConfig(userConfig),
- Histogram.fromConfig(systemConfig),
- Histogram.fromConfig(cpuWaitConfig),
- Histogram.fromConfig(idleConfig))
- }
-}
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/GCMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala
deleted file mode 100644
index bc5fc724..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.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.metrics
-
-import java.lang.management.GarbageCollectorMXBean
-
-import akka.actor.ActorSystem
-import com.typesafe.config.Config
-import kamon.metric._
-import kamon.metric.instrument.{ Gauge, 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: Gauge, time: Gauge)
- 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(
- Gauge.fromConfig(countConfig, system)(() ⇒ gc.getCollectionCount),
- Gauge.fromConfig(timeConfig, system, Scale.Milli)(() ⇒ gc.getCollectionTime))
- }
-}
-
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 ac033fe2..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-heap" }
- case object Max extends MetricIdentity { val name = "max-heap" }
- case object Committed extends MetricIdentity { val name = "committed-heap" }
-
- 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/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 f348bb0c..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/metrics/NetworkMetrics.scala
+++ /dev/null
@@ -1,83 +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 class NetworkMetricRecorder(rxBytes: Histogram, txBytes: Histogram, rxErrors: Histogram, txErrors: Histogram)
- extends MetricGroupRecorder {
-
- def collect(context: CollectionContext): MetricGroupSnapshot = {
- NetworkMetricSnapshot(rxBytes.collect(context), txBytes.collect(context), rxErrors.collect(context), txErrors.collect(context))
- }
-
- def cleanup: Unit = {}
- }
-
- case class NetworkMetricSnapshot(rxBytes: Histogram.Snapshot, txBytes: Histogram.Snapshot, rxErrors: Histogram.Snapshot, txErrors: 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))
- }
-
- val metrics: Map[MetricIdentity, MetricSnapshot] = Map(
- RxBytes -> rxBytes,
- TxBytes -> txBytes,
- RxErrors -> rxErrors,
- TxErrors -> txErrors)
- }
-
- 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")
-
- new NetworkMetricRecorder(
- Histogram.fromConfig(rxBytesConfig, Scale.Kilo),
- Histogram.fromConfig(txBytesConfig, Scale.Kilo),
- Histogram.fromConfig(rxErrorsConfig),
- Histogram.fromConfig(txErrorsConfig))
- }
-} \ No newline at end of file
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/system/SystemMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala
deleted file mode 100644
index 62ffdb33..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala
+++ /dev/null
@@ -1,64 +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 systemMetricsExtension = Kamon(Metrics)(system)
-
- //JVM Metrics
- systemMetricsExtension.register(HeapMetrics(Heap), HeapMetrics.Factory)
- garbageCollectors.map { gc ⇒ systemMetricsExtension.register(GCMetrics(gc.getName), GCMetrics.Factory(gc)) }
-
- //System Metrics
- system.actorOf(SystemMetricsCollector.props(1 second), "system-metrics-collector")
-}
-
-object SystemMetricsExtension {
- val CPU = "cpu"
- val ProcessCPU = "process-cpu"
- val Network = "network"
- val Memory = "memory"
- val Heap = "heap"
- val ContextSwitches = "context-switches"
-
- def toKB(value: Long): Long = (value / 1024)
- def toMB(value: Long): Long = (value / 1024 / 1024)
- def toLong(value: Double): Long = math round (value * 100L)
-
- val garbageCollectors = ManagementFactory.getGarbageCollectorMXBeans.asScala.filter(_.isValid)
-}
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 f41a76d5..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala
+++ /dev/null
@@ -1,176 +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.IOException
-
-import akka.actor.{ ActorLogging, Actor, Props }
-import kamon.Kamon
-import kamon.metric.Metrics
-import kamon.metrics.CPUMetrics.CPUMetricRecorder
-import kamon.metrics.ContextSwitchesMetrics.ContextSwitchesMetricsRecorder
-import kamon.metrics.MemoryMetrics.MemoryMetricRecorder
-import kamon.metrics.NetworkMetrics.NetworkMetricRecorder
-import kamon.metrics.ProcessCPUMetrics.ProcessCPUMetricsRecorder
-import kamon.metrics._
-import kamon.system.sigar.SigarHolder
-import org.hyperic.sigar.{ Mem, NetInterfaceStat, SigarProxy }
-
-import scala.concurrent.duration.FiniteDuration
-import scala.io.Source
-
-class SystemMetricsCollector(collectInterval: FiniteDuration) extends Actor with ActorLogging with SigarExtensionProvider {
- import kamon.system.SystemMetricsCollector._
- import kamon.system.SystemMetricsExtension._
-
- val collectSchedule = context.system.scheduler.schedule(collectInterval, collectInterval, self, Collect)(context.dispatcher)
-
- val systemMetricsExtension = Kamon(Metrics)(context.system)
-
- val cpuRecorder = systemMetricsExtension.register(CPUMetrics(CPU), CPUMetrics.Factory)
- val processCpuRecorder = systemMetricsExtension.register(ProcessCPUMetrics(ProcessCPU), ProcessCPUMetrics.Factory)
- val memoryRecorder = systemMetricsExtension.register(MemoryMetrics(Memory), MemoryMetrics.Factory)
- val networkRecorder = systemMetricsExtension.register(NetworkMetrics(Network), NetworkMetrics.Factory)
- val contextSwitchesRecorder = systemMetricsExtension.register(ContextSwitchesMetrics(ContextSwitches), ContextSwitchesMetrics.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)
-
- 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))
- }
-
- 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) = {
- nr.rxBytes.record(collect(sigar, interfaces)(net ⇒ toKB(net.getRxBytes)))
- nr.txBytes.record(collect(sigar, interfaces)(net ⇒ toKB(net.getTxBytes)))
- nr.rxErrors.record(collect(sigar, interfaces)(net ⇒ net.getRxErrors))
- nr.txErrors.record(collect(sigar, interfaces)(net ⇒ net.getTxErrors))
-
- def collect(sigar: SigarProxy, interfaces: Set[String])(block: NetInterfaceStat ⇒ Long): Long = {
- interfaces.foldLeft(0L) { (totalBytes, interface) ⇒
- {
- val net = sigar.getNetInterfaceStat(interface)
- totalBytes + block(net)
- }
- }
- }
- }
-
- private def recordContextSwitches(ctxt: 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("ctxt")) {
- contextSwitches = line.substring(line.indexOf(" ") + 1).toLong
- }
- }
- } catch {
- case ex: IOException ⇒ {
- log.error("Error trying to read [{}]", filename)
- }
- }
- contextSwitches
- }
-
- val (perProcessVoluntary, perProcessNonVoluntary) = contextSwitchesByProcess(pid)
- ctxt.perProcessVoluntary.record(perProcessVoluntary)
- ctxt.perProcessNonVoluntary.record(perProcessNonVoluntary)
- ctxt.global.record(contextSwitches)
- }
-}
-
-object SystemMetricsCollector {
- case object Collect
-
- object OsUtils {
- def isLinux: Boolean = System.getProperty("os.name").indexOf("Linux") != -1;
- }
-
- def props(collectInterval: FiniteDuration): Props = Props[SystemMetricsCollector](new SystemMetricsCollector(collectInterval))
-}
-
-trait SigarExtensionProvider {
- lazy val sigar = SigarHolder.instance()
-
- def pid = sigar.getPid
-
- val interfaces: Set[String] = sigar.getNetInterfaceList.toSet
-}
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..ebdaf01f
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsExtension.scala
@@ -0,0 +1,71 @@
+/*
+ * =========================================================================================
+ * 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.supervisor.ModuleSupervisor
+import kamon.system.custom.{ ContextSwitchesUpdater, ContextSwitchesMetrics }
+import kamon.system.jmx._
+import kamon.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
+
+ // 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..384c89f1
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala
@@ -0,0 +1,118 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.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
+
+/**
+ * Context Switches metrics:
+ * - process-voluntary: Total number of voluntary context switches related to the current process (one thread explicitly yield the CPU to another).
+ * - process-non-voluntary: Total number of involuntary context switches related to the current process (the system scheduler suspends and active thread, and switches control to a different thread).
+ * - global: Total number of context switches across all CPUs.
+ */
+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("ctxt")) {
+ 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
+ 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..568f1b71
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/ClassLoadingMetrics.scala
@@ -0,0 +1,48 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.jmx
+
+import java.lang.management.ManagementFactory
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+
+/**
+ * Class Loading metrics, as reported by JMX:
+ * - @see [[http://docs.oracle.com/javase/7/docs/api/java/lang/management/ClassLoadingMXBean.html "ClassLoadingMXBean"]]
+ */
+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..a9ab4b62
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala
@@ -0,0 +1,54 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.jmx
+
+import java.lang.management.{ GarbageCollectorMXBean, ManagementFactory }
+
+import kamon.metric.{ Entity, MetricsExtension, GenericEntityRecorder }
+import kamon.metric.instrument.{ DifferentialValueCollector, Time, InstrumentFactory }
+import scala.collection.JavaConverters._
+
+/**
+ * Garbage Collection metrics, as reported by JMX:
+ * - @see [[http://docs.oracle.com/javase/7/docs/api/java/lang/management/GarbageCollectorMXBean.html "GarbageCollectorMXBean"]]
+ */
+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..cd2e3e8e
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/HeapMemoryMetrics.scala
@@ -0,0 +1,49 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.jmx
+
+import java.lang.management.ManagementFactory
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+
+/**
+ * Heap Memory metrics, as reported by JMX:
+ * - @see [[http://docs.oracle.com/javase/7/docs/api/java/lang/management/MemoryMXBean.html "MemoryMXBean"]]
+ */
+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..be0ee08c
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala
@@ -0,0 +1,29 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.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..7425972b
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/NonHeapMemoryMetrics.scala
@@ -0,0 +1,53 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.jmx
+
+import java.lang.management.ManagementFactory
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+
+/**
+ * Non Heap Memory metrics, as reported by JMX:
+ * - @see [[http://docs.oracle.com/javase/7/docs/api/java/lang/management/MemoryMXBean.html "MemoryMXBean"]]
+ */
+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..b9bf9622
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/ThreadsMetrics.scala
@@ -0,0 +1,48 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.jmx
+
+import java.lang.management.ManagementFactory
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.InstrumentFactory
+
+/**
+ * Threads metrics, as reported by JMX:
+ * - @see [[http://docs.oracle.com/javase/7/docs/api/java/lang/management/ThreadMXBean.html "ThreadMXBean"]]
+ */
+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..0e9a5b53
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/CpuMetrics.scala
@@ -0,0 +1,53 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.InstrumentFactory
+import org.hyperic.sigar.Sigar
+
+/**
+ * Cpu usage metrics, as reported by Sigar:
+ * - user: Total percentage of system cpu user time.
+ * - system: Total percentage of system cpu kernel time.
+ * - wait: Total percentage of system cpu io wait time.
+ * - idle: Total percentage of system cpu idle time
+ * - stolen: Total percentage of system cpu involuntary wait time. @see [[https://www.datadoghq.com/2013/08/understanding-aws-stolen-cpu-and-how-it-affects-your-apps/ "Understanding Stolen Cpu"]]
+ */
+class CpuMetrics(sigar: Sigar, 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(): 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(sigar: Sigar, instrumentFactory: InstrumentFactory): CpuMetrics =
+ new CpuMetrics(sigar, 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..06e3e37d
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/DiffRecordingHistogram.scala
@@ -0,0 +1,60 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.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) {
+ val diff = value - _lastObservedValue.getAndSet(value)
+ val current = if (diff >= 0) diff else 0L
+
+ wrappedHistogram.record(current, 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..d3bfefbe
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/FileSystemMetrics.scala
@@ -0,0 +1,48 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.{ Memory, InstrumentFactory }
+import org.hyperic.sigar.{ DiskUsage, FileSystem, Sigar }
+import scala.util.Try
+
+/**
+ * Disk usage metrics, as reported by Sigar:
+ * - readBytes: Total number of physical disk reads.
+ * - writesBytes: Total number of physical disk writes.
+ */
+class FileSystemMetrics(sigar: Sigar, 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))
+
+ val fileSystems = sigar.getFileSystemList.filter(_.getType == FileSystem.TYPE_LOCAL_DISK).map(_.getDevName).toSet
+
+ def sumOfAllFileSystems(sigar: Sigar, thunk: DiskUsage ⇒ Long): Long = Try {
+ fileSystems.map(i ⇒ thunk(sigar.getDiskUsage(i))).fold(0L)(_ + _)
+ } getOrElse 0L
+
+ def update(): Unit = {
+ reads.record(sumOfAllFileSystems(sigar, _.getReadBytes))
+ writes.record(sumOfAllFileSystems(sigar, _.getWriteBytes))
+ }
+}
+
+object FileSystemMetrics extends SigarMetricRecorderCompanion("file-system") {
+ def apply(sigar: Sigar, instrumentFactory: InstrumentFactory): FileSystemMetrics =
+ new FileSystemMetrics(sigar, 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..8d7bd808
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/LoadAverageMetrics.scala
@@ -0,0 +1,45 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.InstrumentFactory
+import org.hyperic.sigar.Sigar
+
+/**
+ * Load Average metrics, as reported by Sigar:
+ * - The system load averages for the past 1, 5, and 15 minutes.
+ */
+class LoadAverageMetrics(sigar: Sigar, instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val oneMinute = histogram("one-minute")
+ val fiveMinutes = histogram("five-minutes")
+ val fifteenMinutes = histogram("fifteen-minutes")
+
+ def update(): 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(sigar: Sigar, instrumentFactory: InstrumentFactory): LoadAverageMetrics =
+ new LoadAverageMetrics(sigar, 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..787c9f2f
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/MemoryMetrics.scala
@@ -0,0 +1,57 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.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(sigar: Sigar, instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val used = histogram("memory-used", Memory.Bytes)
+ val cached = histogram("memory-cache-and-buffer", Memory.Bytes)
+ val free = histogram("memory-free", Memory.Bytes)
+ val total = histogram("memory-total", Memory.Bytes)
+ val swapUsed = histogram("swap-used", Memory.Bytes)
+ val swapFree = histogram("swap-free", Memory.Bytes)
+
+ def update(): Unit = {
+ val mem = sigar.getMem
+ val swap = sigar.getSwap
+ val cachedMemory = if (mem.getActualFree > mem.getFree) mem.getActualFree - mem.getFree else 0L
+
+ used.record(mem.getActualUsed)
+ free.record(mem.getActualFree)
+ cached.record(cachedMemory)
+ total.record(mem.getTotal)
+ swapUsed.record(swap.getUsed)
+ swapFree.record(swap.getFree)
+ }
+}
+
+object MemoryMetrics extends SigarMetricRecorderCompanion("memory") {
+
+ def apply(sigar: Sigar, instrumentFactory: InstrumentFactory): MemoryMetrics =
+ new MemoryMetrics(sigar, 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..30575508
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/NetworkMetrics.scala
@@ -0,0 +1,61 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument._
+import org.hyperic.sigar.{ NetInterfaceStat, Sigar }
+import scala.util.Try
+
+/**
+ * Network metrics, as reported by Sigar:
+ * - rxBytes: Total number of received packets in bytes.
+ * - txBytes: Total number of transmitted packets in bytes.
+ * - rxErrors: Total number of packets received with errors. This includes too-long-frames errors, ring-buffer overflow errors, etc.
+ * - txErrors: Total number of errors encountered while transmitting packets. This list includes errors due to the transmission being aborted, errors due to the carrier, etc.
+ * - rxDropped: Total number of incoming packets dropped.
+ * - txDropped: Total number of outgoing packets dropped.
+ */
+class NetworkMetrics(sigar: Sigar, 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"))
+
+ val interfaces = sigar.getNetInterfaceList.toList.filter(_ != "lo")
+
+ def sumOfAllInterfaces(sigar: Sigar, thunk: NetInterfaceStat ⇒ Long): Long = Try {
+ interfaces.map(i ⇒ thunk(sigar.getNetInterfaceStat(i))).fold(0L)(_ + _)
+
+ } getOrElse 0L
+
+ def update(): 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(sigar: Sigar, instrumentFactory: InstrumentFactory): NetworkMetrics =
+ new NetworkMetrics(sigar, 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..4432e6cd
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/ProcessCpuMetrics.scala
@@ -0,0 +1,77 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.sigar
+
+import kamon.metric.GenericEntityRecorder
+import kamon.metric.instrument.InstrumentFactory
+import org.hyperic.sigar.{ ProcCpu, Sigar }
+
+/**
+ * Process Cpu usage metrics, as reported by Sigar:
+ * - user: Process cpu user time.
+ * - total: Process cpu time (sum of User and Sys).
+ * - system: Process cpu kernel time.
+ */
+class ProcessCpuMetrics(sigar: Sigar, instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SigarMetric {
+ val processUserCpu = histogram("process-user-cpu")
+ val processSystemCpu = histogram("process-system-cpu")
+ val processTotalCpu = histogram("process-cpu")
+
+ val pid = sigar.getPid
+ val totalCores = sigar.getCpuInfoList.headOption.map(_.getTotalCores.toLong).getOrElse(1L)
+
+ var lastProcCpu: ProcCpu = sigar.getProcCpu(pid)
+ var currentLoad: Long = 0
+
+ /**
+ * While CPU usage time updates not very often, We have introduced a simple heuristic, that supposes that the load is the same as previous,
+ * while CPU usage time doesn't update. But supposing that it could be zero load for a process for some time,
+ * We used an arbitrary duration of 2000 milliseconds, after which the same CPU usage time value become legal, and it is supposed that the load is really zero.
+ *
+ * @see [[http://stackoverflow.com/questions/19323364/using-sigar-api-to-get-jvm-cpu-usage "StackOverflow: Using Sigar API to get JVM Cpu usage"]]
+ */
+ def update(): Unit = {
+ val currentProcCpu = sigar.getProcCpu(pid)
+ val totalDiff = currentProcCpu.getTotal - lastProcCpu.getTotal
+ val userDiff = currentProcCpu.getUser - lastProcCpu.getUser
+ val systemDiff = currentProcCpu.getSys - lastProcCpu.getSys
+ val timeDiff = currentProcCpu.getLastTime - lastProcCpu.getLastTime
+
+ def percentUsage(delta: Long): Long = 100 * delta / timeDiff / totalCores
+
+ if (totalDiff == 0) {
+ if (timeDiff > 2000) currentLoad = 0
+ if (currentLoad == 0) lastProcCpu = currentProcCpu
+ } else {
+ val totalPercent = percentUsage(totalDiff)
+ val userPercent = percentUsage(userDiff)
+ val systemPercent = percentUsage(systemDiff)
+
+ processUserCpu.record(userPercent)
+ processSystemCpu.record(systemPercent)
+ processTotalCpu.record(userPercent + systemPercent)
+
+ currentLoad = totalPercent
+ lastProcCpu = currentProcCpu
+ }
+ }
+}
+
+object ProcessCpuMetrics extends SigarMetricRecorderCompanion("process-cpu") {
+ def apply(sigar: Sigar, instrumentFactory: InstrumentFactory): ProcessCpuMetrics =
+ new ProcessCpuMetrics(sigar, instrumentFactory)
+}
diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarLoader.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarLoader.scala
deleted file mode 100644
index 607ebe13..00000000
--- a/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarLoader.scala
+++ /dev/null
@@ -1,203 +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.sigar
-
-import java.io._
-import java.text.SimpleDateFormat
-import java.util
-import java.util.logging.Logger
-import java.util.{ ArrayList, Date, List }
-
-import org.hyperic.sigar._
-
-import scala.annotation.tailrec
-import scala.collection.JavaConversions._
-import scala.io.Source
-
-object SigarHolder {
- private lazy val sigarProxy = SigarLoader.sigarProxy
- def instance() = sigarProxy
-}
-
-object SigarLoader {
-
- val Version = "1.6.4"
- val JavaLibraryPath = "java.library.path"
- val TmpDir = "java.io.tmpdir"
- val IndexFile = "/kamon/system/sigar/index"
- val UsrPathField = "usr_paths"
-
- private val log = Logger.getLogger("SigarLoader")
-
- def sigarProxy = init(new File(System.getProperty(TmpDir)))
-
- private[sigar] def init(baseTmp: File): SigarProxy = {
- val tmpDir = createTmpDir(baseTmp)
- for (lib ← loadIndex) copy(lib, tmpDir)
-
- attachToLibraryPath(tmpDir)
-
- try {
- val sigar = new Sigar()
- printBanner(sigar)
- sigar
- } catch {
- case t: Throwable ⇒ {
- log.severe("Failed to load sigar")
- throw new RuntimeException(t)
- }
- }
- }
-
- private[sigar] val usrPathField = {
- val usrPathField = classOf[ClassLoader].getDeclaredField(UsrPathField)
- usrPathField.setAccessible(true)
- usrPathField
- }
-
- private[sigar] def attachToLibraryPath(dir: File): Unit = {
- val dirAbsolute = dir.getAbsolutePath
- System.setProperty(JavaLibraryPath, newLibraryPath(dirAbsolute))
- var paths = usrPathField.get(null).asInstanceOf[Array[String]]
- if (paths == null) paths = new Array[String](0)
- for (path ← paths) if (path == dirAbsolute) return
- val newPaths = util.Arrays.copyOf(paths, paths.length + 1)
- newPaths(newPaths.length - 1) = dirAbsolute
- usrPathField.set(null, newPaths)
- }
-
- private[sigar] def newLibraryPath(dirAbsolutePath: String): String = {
- Option(System.getProperty(JavaLibraryPath)).fold(dirAbsolutePath)(oldValue ⇒ s"$dirAbsolutePath${File.pathSeparator}$oldValue")
- }
-
- private[sigar] def copy(lib: String, tmpDir: File) {
- val target = new File(tmpDir, lib)
- if (target.exists()) return
- write(classOf[Loader].getResourceAsStream(lib), target)
- }
-
- private[sigar] def createTmpDir(baseTmp: File): File = {
- val tmpDir = new File(baseTmp, s"sigar-$Version")
- if (!tmpDir.exists()) {
- if (!tmpDir.mkdirs()) throw new RuntimeException(s"Could not create temp sigar directory: ${tmpDir.getAbsolutePath}")
- }
- if (!tmpDir.isDirectory) throw new RuntimeException(s"sigar temp directory path is not a directory: ${tmpDir.getAbsolutePath}")
- if (!tmpDir.canWrite()) throw new RuntimeException(s"sigar temp directory not writeable: ${tmpDir.getAbsolutePath}")
- tmpDir
- }
-
- private[sigar] def loadIndex(): List[String] = {
- val libs = new ArrayList[String]()
- val is = classOf[Loader].getResourceAsStream(IndexFile)
-
- for (line ← Source.fromInputStream(is).getLines()) {
- val currentLine = line.trim()
- libs add currentLine
- }
- libs
- }
-
- private[sigar] def write(input: InputStream, to: File) {
- val out = new FileOutputStream(to)
- try {
- transfer(input, out)
- } finally {
- out.close()
- }
- }
-
- private[sigar] def transfer(input: InputStream, out: OutputStream) {
- val buffer = new Array[Byte](8192)
-
- @tailrec def transfer() {
- val read = input.read(buffer)
- if (read >= 0) {
- out.write(buffer, 0, read)
- transfer()
- }
- }
- transfer()
- }
-
- private[sigar] 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 Loader private[sigar]
-}
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..e68b0ede
--- /dev/null
+++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala
@@ -0,0 +1,75 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 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.sigar
+
+import akka.actor.{ Props, Actor }
+import kamon.Kamon
+import kamon.metric.instrument.InstrumentFactory
+import kamon.metric.{ Entity, EntityRecorder, MetricsExtension }
+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
+
+ val sigarMetrics = List(
+ CpuMetrics.register(sigar, metricsExtension),
+ FileSystemMetrics.register(sigar, metricsExtension),
+ LoadAverageMetrics.register(sigar, metricsExtension),
+ MemoryMetrics.register(sigar, metricsExtension),
+ NetworkMetrics.register(sigar, metricsExtension),
+ ProcessCpuMetrics.register(sigar, metricsExtension))
+
+ val refreshSchedule = context.system.scheduler.schedule(refreshInterval, refreshInterval, self, UpdateSigarMetrics)(context.dispatcher)
+
+ def receive = {
+ case UpdateSigarMetrics ⇒ updateMetrics()
+ }
+
+ def updateMetrics(): Unit = {
+ sigarMetrics.foreach(_.update())
+ }
+
+ 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(): Unit
+}
+
+abstract class SigarMetricRecorderCompanion(metricName: String) {
+ def register(sigar: Sigar, metricsExtension: MetricsExtension): SigarMetric = {
+ val instrumentFactory = metricsExtension.instrumentFactory("system-metric")
+ metricsExtension.register(Entity(metricName, "system-metric"), apply(sigar, instrumentFactory)).recorder
+ }
+
+ def apply(sigar: Sigar, instrumentFactory: InstrumentFactory): SigarMetric
+}
+
diff --git a/kamon-system-metrics/src/test/scala/kamon/metrics/RedirectLogging.scala b/kamon-system-metrics/src/test/scala/kamon/metrics/RedirectLogging.scala
new file mode 100644
index 00000000..fbf42cf0
--- /dev/null
+++ b/kamon-system-metrics/src/test/scala/kamon/metrics/RedirectLogging.scala
@@ -0,0 +1,34 @@
+/* =========================================================================================
+ * 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.metric
+
+import java.util.logging.LogManager
+import org.slf4j.bridge.SLF4JBridgeHandler
+
+/**
+ * Redirect different logging sources to SLF4J.
+ */
+trait RedirectLogging {
+
+ def redirectLogging(): Unit = {
+ // Redirect JUL to SLF4J.
+ LogManager.getLogManager().reset();
+ SLF4JBridgeHandler.install();
+ }
+
+ redirectLogging()
+
+}
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 4f7867ed..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,362 +15,140 @@
package kamon.metric
-import akka.actor.ActorSystem
-import akka.testkit.{ TestKitBase, TestProbe }
+import java.lang.management.ManagementFactory
+
import com.typesafe.config.ConfigFactory
-import kamon.Kamon
-import kamon.metric.Subscriptions.TickMetricSnapshot
-import kamon.metrics.CPUMetrics.CPUMetricSnapshot
-import kamon.metrics.ContextSwitchesMetrics.ContextSwitchesMetricsSnapshot
-import kamon.metrics.GCMetrics.GCMetricSnapshot
-import kamon.metrics.HeapMetrics.HeapMetricSnapshot
-import kamon.metrics.MemoryMetrics.MemoryMetricSnapshot
-import kamon.metrics.NetworkMetrics.NetworkMetricSnapshot
-import kamon.metrics.ProcessCPUMetrics.ProcessCPUMetricsSnapshot
-import kamon.metrics._
-import kamon.system.SystemMetricsExtension
-import org.scalatest.{ Matchers, WordSpecLike }
-
-import scala.concurrent.duration._
-
-class SystemMetricsSpec extends TestKitBase with WordSpecLike with Matchers {
- 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
- |
- | system {
- | cpu {
- | user {
- | highest-trackable-value = 999999999
- | significant-value-digits = 2
- | }
- | system {
- | highest-trackable-value = 999999999
- | significant-value-digits = 2
- | }
- | wait {
- | highest-trackable-value = 999999999
- | significant-value-digits = 2
- | }
- | idle {
- | highest-trackable-value = 999999999
- | significant-value-digits = 2
- | }
- | }
- | process-cpu {
- | user {
- | highest-trackable-value = 999999999
- | significant-value-digits = 2
- | }
- | system {
- | highest-trackable-value = 999999999
- | significant-value-digits = 2
- | }
- | }
- | memory {
- | used {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | free {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | buffer {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | cache {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | swap-used {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | swap-free {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | }
- | context-switches {
- | per-process-voluntary {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | per-process-non-voluntary {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | global {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | }
- | network {
- | rx-bytes {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | tx-bytes {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | rx-errors {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | tx-errors {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | }
- | heap {
- | used {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | max {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | committed {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | }
- | gc {
- | count {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | time {
- | highest-trackable-value = 3600000000000
- | significant-value-digits = 2
- | }
- | }
- | }
- |}
- """.stripMargin))
-
- "the Kamon CPU Metrics" should {
- "record user, system, wait, idle 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
- }
- }
- "the Kamon GC Metrics" should {
- "record count, time metrics" in new GCMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
+import kamon.system.jmx.GarbageCollectionMetrics
+import kamon.testkit.BaseKamonSpec
+import scala.collection.JavaConverters._
- val GCMetrics = expectGCMetrics(metricsListener, 3 seconds)
- GCMetrics.count.max should be > 0L
- GCMetrics.time.max should be > 0L
- }
- }
+class SystemMetricsSpec extends BaseKamonSpec("system-metrics-spec") with RedirectLogging {
- "the Kamon Heap Metrics" should {
- "record used, max, commited metrics" in new HeapMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
+ override lazy val config =
+ ConfigFactory.parseString(
+ """
+ |kamon.metric {
+ | tick-interval = 1 hour
+ |}
+ |
+ |akka {
+ | extensions = ["kamon.system.SystemMetrics"]
+ |}
+ """.stripMargin)
- val HeapMetrics = expectHeapMetrics(metricsListener, 3 seconds)
- HeapMetrics.used.max should be >= 0L
- HeapMetrics.max.max should be >= 0L
- HeapMetrics.committed.max should be >= 0L
- }
- }
+ override protected def beforeAll(): Unit =
+ Thread.sleep(2000) // Give some room to the recorders to store some values.
- "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
+ "the Kamon System Metrics module" should {
+ "record user, system, wait, idle and stolen CPU metrics" in {
+ val cpuMetrics = takeSnapshotOf("cpu", "system-metric")
+
+ 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
}
- }
- "the Kamon Network Metrics" should {
- "record rxBytes, txBytes, rxErrors, txErrors metrics" in new NetworkMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
+ "record count and time garbage collection metrics" in {
+ val availableGarbageCollectors = ManagementFactory.getGarbageCollectorMXBeans.asScala.filter(_.isValid)
- 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
+ for (collectorName ← availableGarbageCollectors) {
+ val sanitizedName = GarbageCollectionMetrics.sanitizeCollectorName(collectorName.getName)
+ val collectorMetrics = takeSnapshotOf(s"$sanitizedName-garbage-collector", "system-metric")
+
+ collectorMetrics.gauge("garbage-collection-count").get.numberOfMeasurements should be > 0L
+ collectorMetrics.gauge("garbage-collection-time").get.numberOfMeasurements should be > 0L
+ }
}
- }
- "the Kamon Process CPU Metrics" should {
- "record Cpu Percent, Total Process Time metrics" in new ProcessCPUMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
+ "record used, max and committed heap metrics" in {
+ val heapMetrics = takeSnapshotOf("heap-memory", "system-metric")
- val ProcessCPUMetrics = expectProcessCPUMetrics(metricsListener, 3 seconds)
- ProcessCPUMetrics.cpuPercent.max should be > 0L
- ProcessCPUMetrics.totalProcessTime.max should be > 0L
+ 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
}
- }
- "the Kamon ContextSwitches Metrics" should {
- "record Context Switches Global, Voluntary and Non Voluntary metrics" in new ContextSwitchesMetricsListenerFixture {
- val metricsListener = subscribeToMetrics()
+ "record used, max and committed non-heap metrics" in {
+ val nonHeapMetrics = takeSnapshotOf("non-heap-memory", "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
+ 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
}
- }
- 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 daemon, count and peak jvm threads metrics" in {
+ val threadsMetrics = takeSnapshotOf("threads", "system-metric")
- 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
+ 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
}
- }
- def expectGCMetrics(listener: TestProbe, waitTime: FiniteDuration): GCMetricSnapshot = {
- val tickSnapshot = within(waitTime) {
- listener.expectMsgType[TickMetricSnapshot]
+ "record loaded, unloaded and current class loading metrics" in {
+ val classLoadingMetrics = takeSnapshotOf("class-loading", "system-metric")
+
+ 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 gcMetricsOption = tickSnapshot.metrics.get(GCMetrics(SystemMetricsExtension.garbageCollectors(0).getName))
- gcMetricsOption should not be empty
- gcMetricsOption.get.asInstanceOf[GCMetricSnapshot]
- }
+ "record reads, writes, queue time and service time file system metrics" in {
+ val fileSystemMetrics = takeSnapshotOf("file-system", "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
+ fileSystemMetrics.histogram("file-system-reads").get.numberOfMeasurements should be > 0L
+ fileSystemMetrics.histogram("file-system-writes").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 1 minute, 5 minutes and 15 minutes metrics load average metrics" in {
+ val loadAverage = takeSnapshotOf("load-average", "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
+ 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
}
- }
- 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 used, free, swap used, swap free system memory metrics" in {
+ val memoryMetrics = takeSnapshotOf("memory", "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
+ 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
}
- }
- 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 rxBytes, txBytes, rxErrors, txErrors, rxDropped, txDropped network metrics" in {
+ val networkMetrics = takeSnapshotOf("network", "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
+ 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 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 system and user CPU percentage for the application process" in {
+ val processCpuMetrics = takeSnapshotOf("process-cpu", "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
+ 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 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]
- }
+ "record Context Switches Global, Voluntary and Non Voluntary metrics when running on Linux" in {
+ if (isLinux) {
+ val contextSwitchesMetrics = takeSnapshotOf("context-switches", "system-metric")
- 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
+ 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 isLinux: Boolean =
+ System.getProperty("os.name").indexOf("Linux") != -1
+
}