From 29068fc70a3e5a17a630c2c7fff951572bb5fa21 Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Thu, 3 Jul 2014 14:36:42 -0300 Subject: ! all: refactor the core metric recording instruments and accomodate UserMetrics This PR is including several changes to the kamon-core, most notably: - Formalize the interface for Histograms, Counters and MinMaxCounters. Making sure that the interfaces are as clean as possible. - Move away from the all Vector[Measurement] based Histogram snapshot to a new approach in which we use a single long to store both the index in the counts array and the frequency on that bucket. The leftmost 2 bytes of each long are used for storing the counts array index and the remaining 6 bytes are used for the actual count, and everything is put into a simple long array. This way only the buckets that actually have values will be included in the snapshot with the smallest possible memory footprint. - Introduce Gauges. - Reorganize the instrumentation for Akka and Scala and rewrite most of the tests of this components to avoid going through the subscription protocol to test. - Introduce trace tests and fixes on various tests. - Necessary changes on new relic, datadog and statsd modules to compile with the new codebase. Pending: - Finish the upgrade of the new relic to the current model. - Introduce proper limit checks for histograms to ensure that we never pass the 2/6 bytes limits. - More testing, more testing, more testing. - Create the KamonStandalone module. --- kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'kamon-playground') diff --git a/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala b/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala index 664bd4f9..84621927 100644 --- a/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala +++ b/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala @@ -26,9 +26,9 @@ import scala.util.Random import akka.routing.RoundRobinPool import kamon.trace.TraceRecorder import kamon.Kamon -import kamon.metrics._ +import kamon.metric._ import spray.http.{ StatusCodes, Uri } -import kamon.metrics.Subscriptions.TickMetricSnapshot +import kamon.metric.Subscriptions.TickMetricSnapshot object SimpleRequestProcessor extends App with SimpleRoutingApp with RequestBuilding with KamonTraceDirectives { import scala.concurrent.duration._ @@ -55,8 +55,6 @@ object SimpleRequestProcessor extends App with SimpleRoutingApp with RequestBuil val replier = system.actorOf(Props[Replier].withRouter(RoundRobinPool(nrOfInstances = 2)), "replier") val random = new Random() - val requestCountRecorder = Kamon(Metrics).register(CustomMetric("GetCount"), CustomMetric.histogram(10, 3, Scale.Unit)) - startServer(interface = "localhost", port = 9090) { get { path("test") { @@ -87,7 +85,6 @@ object SimpleRequestProcessor extends App with SimpleRoutingApp with RequestBuil path("ok") { traceName("OK") { complete { - requestCountRecorder.map(_.record(1)) "ok" } } -- cgit v1.2.3 From 5c141733ad39cf2730cf34dc8f3f4a82f0c1b516 Mon Sep 17 00:00:00 2001 From: Diego Date: Tue, 24 Jun 2014 23:35:14 -0300 Subject: ! kamon-system-metrics: introducing System and JVM metrics module --- .../main/scala/kamon/metric/instrument/Gauge.scala | 8 +- .../src/main/resources/application.conf | 1 + .../src/main/resources/reference.conf | 76 +++++ .../src/main/scala/kamon/metrics/CPUMetrics.scala | 84 ++++++ .../src/main/scala/kamon/metrics/GCMetrics.scala | 75 +++++ .../src/main/scala/kamon/metrics/HeapMetrics.scala | 82 +++++ .../main/scala/kamon/metrics/MemoryMetrics.scala | 96 ++++++ .../main/scala/kamon/metrics/NetworkMetrics.scala | 94 ++++++ .../scala/kamon/metrics/ProcessCPUMetrics.scala | 76 +++++ .../main/scala/kamon/system/SystemMetrics.scala | 64 ++++ .../scala/kamon/system/native/SigarLoader.scala | 131 ++++++++ .../src/main/scala/kamon/system/native/index | 22 ++ .../system/native/libsigar-amd64-freebsd-6.so | Bin 0 -> 210641 bytes .../kamon/system/native/libsigar-amd64-linux.so | Bin 0 -> 246605 bytes .../kamon/system/native/libsigar-amd64-solaris.so | Bin 0 -> 251360 bytes .../kamon/system/native/libsigar-ia64-hpux-11.sl | Bin 0 -> 577452 bytes .../kamon/system/native/libsigar-ia64-linux.so | Bin 0 -> 494929 bytes .../kamon/system/native/libsigar-pa-hpux-11.sl | Bin 0 -> 516096 bytes .../kamon/system/native/libsigar-ppc-aix-5.so | Bin 0 -> 400925 bytes .../kamon/system/native/libsigar-ppc-linux.so | Bin 0 -> 258547 bytes .../kamon/system/native/libsigar-ppc64-aix-5.so | Bin 0 -> 425077 bytes .../kamon/system/native/libsigar-ppc64-linux.so | Bin 0 -> 330767 bytes .../kamon/system/native/libsigar-s390x-linux.so | Bin 0 -> 269932 bytes .../kamon/system/native/libsigar-sparc-solaris.so | Bin 0 -> 285004 bytes .../system/native/libsigar-sparc64-solaris.so | Bin 0 -> 261896 bytes .../system/native/libsigar-universal-macosx.dylib | Bin 0 -> 377668 bytes .../native/libsigar-universal64-macosx.dylib | Bin 0 -> 397440 bytes .../kamon/system/native/libsigar-x86-freebsd-5.so | Bin 0 -> 179751 bytes .../kamon/system/native/libsigar-x86-freebsd-6.so | Bin 0 -> 179379 bytes .../kamon/system/native/libsigar-x86-linux.so | Bin 0 -> 233385 bytes .../kamon/system/native/libsigar-x86-solaris.so | Bin 0 -> 242880 bytes .../kamon/system/native/sigar-amd64-winnt.dll | Bin 0 -> 402432 bytes .../scala/kamon/system/native/sigar-x86-winnt.dll | Bin 0 -> 266240 bytes .../scala/kamon/metrics/SystemMetricsSpec.scala | 331 +++++++++++++++++++++ kamon-system/src/main/resources/reference.conf | 28 -- .../scala/kamon/metrics/CpuMetricsCollector.scala | 74 ----- .../src/main/scala/kamon/metrics/JvmMetrics.scala | 71 ----- .../main/scala/kamon/metrics/SystemMetrics.scala | 71 ----- .../src/main/scala/kamon/system/System.scala | 36 --- .../scala/kamon/system/native/SigarLoader.scala | 82 ----- .../src/main/scala/kamon/system/native/index | 22 -- .../system/native/libsigar-amd64-freebsd-6.so | Bin 210641 -> 0 bytes .../kamon/system/native/libsigar-amd64-linux.so | Bin 246605 -> 0 bytes .../kamon/system/native/libsigar-amd64-solaris.so | Bin 251360 -> 0 bytes .../kamon/system/native/libsigar-ia64-hpux-11.sl | Bin 577452 -> 0 bytes .../kamon/system/native/libsigar-ia64-linux.so | Bin 494929 -> 0 bytes .../kamon/system/native/libsigar-pa-hpux-11.sl | Bin 516096 -> 0 bytes .../kamon/system/native/libsigar-ppc-aix-5.so | Bin 400925 -> 0 bytes .../kamon/system/native/libsigar-ppc-linux.so | Bin 258547 -> 0 bytes .../kamon/system/native/libsigar-ppc64-aix-5.so | Bin 425077 -> 0 bytes .../kamon/system/native/libsigar-ppc64-linux.so | Bin 330767 -> 0 bytes .../kamon/system/native/libsigar-s390x-linux.so | Bin 269932 -> 0 bytes .../kamon/system/native/libsigar-sparc-solaris.so | Bin 285004 -> 0 bytes .../system/native/libsigar-sparc64-solaris.so | Bin 261896 -> 0 bytes .../system/native/libsigar-universal-macosx.dylib | Bin 377668 -> 0 bytes .../native/libsigar-universal64-macosx.dylib | Bin 397440 -> 0 bytes .../kamon/system/native/libsigar-x86-freebsd-5.so | Bin 179751 -> 0 bytes .../kamon/system/native/libsigar-x86-freebsd-6.so | Bin 179379 -> 0 bytes .../kamon/system/native/libsigar-x86-linux.so | Bin 233385 -> 0 bytes .../kamon/system/native/libsigar-x86-solaris.so | Bin 242880 -> 0 bytes .../kamon/system/native/sigar-amd64-winnt.dll | Bin 402432 -> 0 bytes .../scala/kamon/system/native/sigar-x86-winnt.dll | Bin 266240 -> 0 bytes project/Dependencies.scala | 2 - project/Projects.scala | 14 +- 64 files changed, 1149 insertions(+), 391 deletions(-) create mode 100644 kamon-system-metrics/src/main/resources/reference.conf create mode 100644 kamon-system-metrics/src/main/scala/kamon/metrics/CPUMetrics.scala create mode 100644 kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala create mode 100644 kamon-system-metrics/src/main/scala/kamon/metrics/HeapMetrics.scala create mode 100644 kamon-system-metrics/src/main/scala/kamon/metrics/MemoryMetrics.scala create mode 100644 kamon-system-metrics/src/main/scala/kamon/metrics/NetworkMetrics.scala create mode 100644 kamon-system-metrics/src/main/scala/kamon/metrics/ProcessCPUMetrics.scala create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/SigarLoader.scala create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/index create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-freebsd-6.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-linux.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-solaris.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ia64-hpux-11.sl create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ia64-linux.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-pa-hpux-11.sl create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc-aix-5.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc-linux.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc64-aix-5.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc64-linux.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-s390x-linux.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-sparc-solaris.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-sparc64-solaris.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-universal-macosx.dylib create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-universal64-macosx.dylib create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-freebsd-5.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-freebsd-6.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-linux.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-solaris.so create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/sigar-amd64-winnt.dll create mode 100644 kamon-system-metrics/src/main/scala/kamon/system/native/sigar-x86-winnt.dll create mode 100644 kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala delete mode 100644 kamon-system/src/main/resources/reference.conf delete mode 100644 kamon-system/src/main/scala/kamon/metrics/CpuMetricsCollector.scala delete mode 100644 kamon-system/src/main/scala/kamon/metrics/JvmMetrics.scala delete mode 100644 kamon-system/src/main/scala/kamon/metrics/SystemMetrics.scala delete mode 100644 kamon-system/src/main/scala/kamon/system/System.scala delete mode 100644 kamon-system/src/main/scala/kamon/system/native/SigarLoader.scala delete mode 100644 kamon-system/src/main/scala/kamon/system/native/index delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-freebsd-6.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-linux.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-solaris.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-ia64-hpux-11.sl delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-ia64-linux.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-pa-hpux-11.sl delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-ppc-aix-5.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-ppc-linux.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-ppc64-aix-5.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-ppc64-linux.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-s390x-linux.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-sparc-solaris.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-sparc64-solaris.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-universal-macosx.dylib delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-universal64-macosx.dylib delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-x86-freebsd-5.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-x86-freebsd-6.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-x86-linux.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/libsigar-x86-solaris.so delete mode 100644 kamon-system/src/main/scala/kamon/system/native/sigar-amd64-winnt.dll delete mode 100644 kamon-system/src/main/scala/kamon/system/native/sigar-x86-winnt.dll (limited to 'kamon-playground') diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala b/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala index 1efff2bc..efd7d78f 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala @@ -44,14 +44,18 @@ object Gauge { fromConfig(config, system)(currentValueCollector) } - def fromConfig(config: Config, system: ActorSystem)(currentValueCollector: CurrentValueCollector): Gauge = { + def fromConfig(config: Config, system: ActorSystem, scale: Scale)(currentValueCollector: CurrentValueCollector): Gauge = { import scala.concurrent.duration._ val highest = config.getLong("highest-trackable-value") val significantDigits = config.getInt("significant-value-digits") val refreshInterval = config.getDuration("refresh-interval", TimeUnit.MILLISECONDS) - Gauge(Histogram.Precision(significantDigits), highest, Scale.Unit, refreshInterval.millis, system)(currentValueCollector) + Gauge(Histogram.Precision(significantDigits), highest, scale, refreshInterval.millis, system)(currentValueCollector) + } + + def fromConfig(config: Config, system: ActorSystem)(currentValueCollector: CurrentValueCollector): Gauge = { + fromConfig(config, system, Scale.Unit)(currentValueCollector) } implicit def functionZeroAsCurrentValueCollector(f: () ⇒ Long): CurrentValueCollector = new CurrentValueCollector { diff --git a/kamon-playground/src/main/resources/application.conf b/kamon-playground/src/main/resources/application.conf index 3d57141a..af85207f 100644 --- a/kamon-playground/src/main/resources/application.conf +++ b/kamon-playground/src/main/resources/application.conf @@ -1,6 +1,7 @@ akka { loglevel = INFO + extensions = ["kamon.system.SystemMetrics"] actor { debug { diff --git a/kamon-system-metrics/src/main/resources/reference.conf b/kamon-system-metrics/src/main/resources/reference.conf new file mode 100644 index 00000000..d6eb0576 --- /dev/null +++ b/kamon-system-metrics/src/main/resources/reference.conf @@ -0,0 +1,76 @@ +# ============================================ # +# Kamon-System-Metrics Reference Configuration # +# ============================================ # + +kamon { + metrics { + precision { + system { + process-cpu { + user = { + refresh-interval = 100 milliseconds + highest-trackable-value = 999999999 + significant-value-digits = 2 + } + system = { + refresh-interval = 100 milliseconds + highest-trackable-value = 999999999 + significant-value-digits = 2 + } + } + + cpu { + user = { + refresh-interval = 100 milliseconds + highest-trackable-value = 999999999 + significant-value-digits = 2 + } + system = { + refresh-interval = 100 milliseconds + highest-trackable-value = 999999999 + significant-value-digits = 2 + } + wait = { + refresh-interval = 100 milliseconds + highest-trackable-value = 999999999 + significant-value-digits = 2 + } + idle ={ + refresh-interval = 100 milliseconds + highest-trackable-value = 999999999 + significant-value-digits = 2 + } + } + + network { + rx-bytes = ${kamon.metrics.precision.default-gauge-precision} + tx-bytes = ${kamon.metrics.precision.default-gauge-precision} + rx-errors = ${kamon.metrics.precision.default-gauge-precision} + tx-errors = ${kamon.metrics.precision.default-gauge-precision} + } + + memory { + used = ${kamon.metrics.precision.default-gauge-precision} + free = ${kamon.metrics.precision.default-gauge-precision} + buffer = ${kamon.metrics.precision.default-gauge-precision} + cache = ${kamon.metrics.precision.default-gauge-precision} + swap-used = ${kamon.metrics.precision.default-gauge-precision} + swap-free = ${kamon.metrics.precision.default-gauge-precision} + } + } + + 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} + } + } + } + } +} \ 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 new file mode 100644 index 00000000..c098d1e5 --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/metrics/CPUMetrics.scala @@ -0,0 +1,84 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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.instrument.{ Gauge, Histogram } +import kamon.metric._ +import kamon.system.SigarExtensionProvider +import org.hyperic.sigar.SigarProxy + +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: Gauge, system: Gauge, cpuWait: Gauge, idle: Gauge) + 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 = new MetricGroupFactory with SigarExtensionProvider { + def cpu = sigar.getCpu + + 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( + Gauge.fromConfig(userConfig, system)(() ⇒ cpu.getUser), + Gauge.fromConfig(systemConfig, system)(() ⇒ cpu.getSys), + Gauge.fromConfig(cpuWaitConfig, system)(() ⇒ cpu.getWait), + Gauge.fromConfig(idleConfig, system)(() ⇒ cpu.getIdle)) + } + } +} + diff --git a/kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala new file mode 100644 index 00000000..b5da600e --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/metrics/GCMetrics.scala @@ -0,0 +1,75 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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) = new MetricGroupFactory { + + 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 new file mode 100644 index 00000000..09174f47 --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/metrics/HeapMetrics.scala @@ -0,0 +1,82 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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 = new MetricGroupFactory { + + val memory = ManagementFactory.getMemoryMXBean + def heap = memory.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)(() ⇒ heap.getUsed), + Gauge.fromConfig(maxHeapConfig, system)(() ⇒ heap.getMax), + Gauge.fromConfig(committedHeapConfig, system)(() ⇒ 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 new file mode 100644 index 00000000..4f6cb1cd --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/metrics/MemoryMetrics.scala @@ -0,0 +1,96 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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.Gauge.CurrentValueCollector +import kamon.metric.instrument.{ Gauge, Histogram } +import kamon.system.SigarExtensionProvider +import org.hyperic.sigar.Mem + +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: Gauge, free: Gauge, buffer: Gauge, cache: Gauge, swapUsed: Gauge, swapFree: Gauge) + 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 = new MetricGroupFactory with SigarExtensionProvider { + def mem = sigar.getMem + def swap = sigar.getSwap + + 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( + Gauge.fromConfig(usedConfig, system)(() ⇒ mem.getUsed), + Gauge.fromConfig(freeConfig, system)(() ⇒ mem.getFree), + Gauge.fromConfig(bufferConfig, system)(() ⇒ swap.getUsed), + Gauge.fromConfig(cacheConfig, system)(() ⇒ swap.getFree), + Gauge.fromConfig(swapUsedConfig, system)(collectBuffer(mem)), + Gauge.fromConfig(swapFreeConfig, system)(collectCache(mem))) + } + + private def collectBuffer(mem: Mem) = () ⇒ if (mem.getUsed() != mem.getActualUsed()) mem.getActualUsed() else 0L + private def collectCache(mem: Mem) = () ⇒ if (mem.getFree() != mem.getActualFree()) mem.getActualFree() else 0L + } +} \ 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 new file mode 100644 index 00000000..62fc3fcd --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/metrics/NetworkMetrics.scala @@ -0,0 +1,94 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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.Gauge.CurrentValueCollector +import kamon.metric.instrument.{ Gauge, Histogram } +import kamon.system.SigarExtensionProvider +import org.hyperic.sigar.{ NetInterfaceStat, SigarProxy } + +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: Gauge, txBytes: Gauge, rxErrors: Gauge, txErrors: Gauge) + 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 = new MetricGroupFactory with SigarExtensionProvider { + + val interfaces: Set[String] = sigar.getNetInterfaceList.toSet + + 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( + Gauge.fromConfig(rxBytesConfig, system)(collect(sigar, interfaces)(net ⇒ net.getRxBytes)), + Gauge.fromConfig(txBytesConfig, system)(collect(sigar, interfaces)(net ⇒ net.getTxBytes)), + Gauge.fromConfig(rxErrorsConfig, system)(collect(sigar, interfaces)(net ⇒ net.getRxErrors)), + Gauge.fromConfig(txErrorsConfig, system)(collect(sigar, interfaces)(net ⇒ net.getTxErrors))) + } + + private def collect(sigar: SigarProxy, interfaces: Set[String])(block: NetInterfaceStat ⇒ Long) = () ⇒ { + interfaces.foldLeft(0L) { (totalBytes, interface) ⇒ + { + val net = sigar.getNetInterfaceStat(interface) + totalBytes + block(net) + } + } + } + } +} \ 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 new file mode 100644 index 00000000..356504b7 --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/metrics/ProcessCPUMetrics.scala @@ -0,0 +1,76 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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.instrument.{ Gauge, Histogram } +import kamon.metric._ +import kamon.system.SigarExtensionProvider + +case class ProcessCPUMetrics(name: String) extends MetricGroupIdentity { + val category = ProcessCPUMetrics +} + +object ProcessCPUMetrics extends MetricGroupCategory { + val name = "proc-cpu" + + case object User extends MetricIdentity { val name = "user" } + case object System extends MetricIdentity { val name = "system" } + + case class ProcessCPUMetricsRecorder(user: Gauge, system: Gauge) + extends MetricGroupRecorder { + + def collect(context: CollectionContext): MetricGroupSnapshot = { + ProcessCPUMetricsSnapshot(user.collect(context), system.collect(context)) + } + + def cleanup: Unit = {} + } + + case class ProcessCPUMetricsSnapshot(user: Histogram.Snapshot, system: Histogram.Snapshot) + extends MetricGroupSnapshot { + + type GroupSnapshotType = ProcessCPUMetricsSnapshot + + def merge(that: ProcessCPUMetricsSnapshot, context: CollectionContext): GroupSnapshotType = { + ProcessCPUMetricsSnapshot(user.merge(that.user, context), system.merge(that.system, context)) + } + + lazy val metrics: Map[MetricIdentity, MetricSnapshot] = Map( + User -> user, + System -> system) + } + + val Factory = new MetricGroupFactory with SigarExtensionProvider { + def pid = sigar.getPid + def cpu = sigar.getProcCpu(pid) + + type GroupRecorder = ProcessCPUMetricsRecorder + + def create(config: Config, system: ActorSystem): GroupRecorder = { + val settings = config.getConfig("precision.system.process-cpu") + + val userConfig = settings.getConfig("user") + val systemConfig = settings.getConfig("system") + + new ProcessCPUMetricsRecorder( + Gauge.fromConfig(userConfig, system)(() ⇒ cpu.getUser), + Gauge.fromConfig(systemConfig, system)(() ⇒ cpu.getSys)) + } + } +} + diff --git a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala new file mode 100644 index 00000000..e46fca24 --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetrics.scala @@ -0,0 +1,64 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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 kamon.system.native.SigarLoader +import scala.collection.JavaConverters._ + +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) + + systemMetricsExtension.register(CPUMetrics(CPU), CPUMetrics.Factory) + systemMetricsExtension.register(ProcessCPUMetrics(ProcessCPU), ProcessCPUMetrics.Factory) + systemMetricsExtension.register(NetworkMetrics(Network), NetworkMetrics.Factory) + systemMetricsExtension.register(MemoryMetrics(Memory), MemoryMetrics.Factory) + systemMetricsExtension.register(HeapMetrics(Heap), HeapMetrics.Factory) + + garbageCollectors.map { gc ⇒ systemMetricsExtension.register(GCMetrics(gc.getName), GCMetrics.Factory(gc)) } +} + +object SystemMetricsExtension { + val CPU = "cpu" + val ProcessCPU = "process-cpu" + val Network = "network" + val Memory = "memory" + val Heap = "heap" + + val garbageCollectors = ManagementFactory.getGarbageCollectorMXBeans.asScala.filter(_.isValid) +} + +trait SigarExtensionProvider { + lazy val sigar = SigarLoader.sigarProxy +} diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/SigarLoader.scala b/kamon-system-metrics/src/main/scala/kamon/system/native/SigarLoader.scala new file mode 100644 index 00000000..6af0a6d2 --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/system/native/SigarLoader.scala @@ -0,0 +1,131 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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.native + +import java.io._ +import java.util +import java.util.logging.Logger +import java.util.{ ArrayList, List } + +import org.hyperic.sigar.{ SigarProxy, SigarProxyCache } + +import scala.annotation.tailrec +import scala.collection.JavaConversions._ +import scala.io.Source + +object SigarLoader { + + val Version = "1.6.4" + val JavaLibraryPath = "java.library.path" + val TmpDir = "java.io.tmpdir" + val IndexFile = "/kamon/system/native/index" + val UsrPathField = "usr_paths" + + private val log = Logger.getLogger("SigarLoader") + + def sigarProxy = init(new File(System.getProperty(TmpDir))) + + private[native] def init(baseTmp: File): SigarProxy = { + val tmpDir = createTmpDir(baseTmp) + for (lib ← loadIndex) copy(lib, tmpDir) + + attachToLibraryPath(tmpDir) + + try { + val sigar = SigarProxyCache.newInstance() + sigar.getPid + sigar + } catch { + case t: Throwable ⇒ { + log.severe("Failed to load sigar") + throw new RuntimeException(t) + } + } + } + + private[native] val usrPathField = { + val usrPathField = classOf[ClassLoader].getDeclaredField(UsrPathField) + usrPathField.setAccessible(true) + usrPathField + } + + private[native] 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[native] def newLibraryPath(dirAbsolutePath: String): String = { + Option(System.getProperty(JavaLibraryPath)).fold(dirAbsolutePath)(oldValue ⇒ s"$dirAbsolutePath${File.pathSeparator}$oldValue") + } + + private[native] def copy(lib: String, tmpDir: File) { + val target = new File(tmpDir, lib) + if (target.exists()) return + write(classOf[Loader].getResourceAsStream(lib), target) + } + + private[native] 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[native] 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[native] def write(input: InputStream, to: File) { + val out = new FileOutputStream(to) + try { + transfer(input, out) + } finally { + out.close() + } + } + + private[native] 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() + } + + class Loader private[native] +} diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/index b/kamon-system-metrics/src/main/scala/kamon/system/native/index new file mode 100644 index 00000000..ebc7f952 --- /dev/null +++ b/kamon-system-metrics/src/main/scala/kamon/system/native/index @@ -0,0 +1,22 @@ +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 + diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-freebsd-6.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-freebsd-6.so new file mode 100644 index 00000000..3e94f0d2 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-freebsd-6.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-linux.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-linux.so new file mode 100644 index 00000000..5a2e4c24 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-linux.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-solaris.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-solaris.so new file mode 100644 index 00000000..6396482a Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-amd64-solaris.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ia64-hpux-11.sl b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ia64-hpux-11.sl new file mode 100644 index 00000000..d92ea4a9 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ia64-hpux-11.sl differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ia64-linux.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ia64-linux.so new file mode 100644 index 00000000..2bd2fc8e Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ia64-linux.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-pa-hpux-11.sl b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-pa-hpux-11.sl new file mode 100644 index 00000000..0dfd8a11 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-pa-hpux-11.sl differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc-aix-5.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc-aix-5.so new file mode 100644 index 00000000..7d4b5199 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc-aix-5.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc-linux.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc-linux.so new file mode 100644 index 00000000..4394b1b0 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc-linux.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc64-aix-5.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc64-aix-5.so new file mode 100644 index 00000000..35fd8288 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc64-aix-5.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc64-linux.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc64-linux.so new file mode 100644 index 00000000..a1ba2529 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-ppc64-linux.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-s390x-linux.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-s390x-linux.so new file mode 100644 index 00000000..c275f4ac Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-s390x-linux.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-sparc-solaris.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-sparc-solaris.so new file mode 100644 index 00000000..aa847d2b Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-sparc-solaris.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-sparc64-solaris.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-sparc64-solaris.so new file mode 100644 index 00000000..6c4fe809 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-sparc64-solaris.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-universal-macosx.dylib b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-universal-macosx.dylib new file mode 100644 index 00000000..27ab1071 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-universal-macosx.dylib differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-universal64-macosx.dylib b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-universal64-macosx.dylib new file mode 100644 index 00000000..0c721fec Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-universal64-macosx.dylib differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-freebsd-5.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-freebsd-5.so new file mode 100644 index 00000000..8c50c611 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-freebsd-5.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-freebsd-6.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-freebsd-6.so new file mode 100644 index 00000000..f0800274 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-freebsd-6.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-linux.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-linux.so new file mode 100644 index 00000000..a0b64edd Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-linux.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-solaris.so b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-solaris.so new file mode 100644 index 00000000..c6452e56 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/libsigar-x86-solaris.so differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/sigar-amd64-winnt.dll b/kamon-system-metrics/src/main/scala/kamon/system/native/sigar-amd64-winnt.dll new file mode 100644 index 00000000..1ec8a035 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/sigar-amd64-winnt.dll differ diff --git a/kamon-system-metrics/src/main/scala/kamon/system/native/sigar-x86-winnt.dll b/kamon-system-metrics/src/main/scala/kamon/system/native/sigar-x86-winnt.dll new file mode 100644 index 00000000..6afdc016 Binary files /dev/null and b/kamon-system-metrics/src/main/scala/kamon/system/native/sigar-x86-winnt.dll differ diff --git a/kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala b/kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala new file mode 100644 index 00000000..ed10903f --- /dev/null +++ b/kamon-system-metrics/src/test/scala/kamon/metrics/SystemMetricsSpec.scala @@ -0,0 +1,331 @@ +/* ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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 akka.actor.ActorSystem +import akka.testkit.{ TestKitBase, TestProbe } +import com.typesafe.config.ConfigFactory +import kamon.Kamon +import kamon.metric.Subscriptions.TickMetricSnapshot +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.metrics.CPUMetrics.CPUMetricSnapshot +import kamon.metrics.GCMetrics.GCMetricSnapshot +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 + | } + | } + | 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() + + val GCMetrics = expectGCMetrics(metricsListener, 3 seconds) + GCMetrics.count.max should be > 0L + GCMetrics.time.max should be > 0L + } + } + + "the Kamon Heap Metrics" should { + "record used, max, commited metrics" in new HeapMetricsListenerFixture { + val metricsListener = subscribeToMetrics() + + val HeapMetrics = expectHeapMetrics(metricsListener, 3 seconds) + HeapMetrics.used.max should be >= 0L + HeapMetrics.max.max should be >= 0L + HeapMetrics.committed.max should be >= 0L + } + } + + "the Kamon 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 Network Metrics" should { + "record rxBytes, txBytes, rxErrors, txErrors metrics" in new NetworkMetricsListenerFixture { + val metricsListener = subscribeToMetrics() + + val NetworkMetrics = expectNetworkMetrics(metricsListener, 3 seconds) + NetworkMetrics.rxBytes.max should be >= 0L + NetworkMetrics.txBytes.max should be >= 0L + NetworkMetrics.rxErrors.max should be >= 0L + NetworkMetrics.txErrors.max should be >= 0L + } + } + + "the Kamon Process CPU Metrics" should { + "record user, system metrics" in new ProcessCPUMetricsListenerFixture { + val metricsListener = subscribeToMetrics() + + val ProcessCPUMetrics = expectProcessCPUMetrics(metricsListener, 3 seconds) + ProcessCPUMetrics.user.max should be > 0L + ProcessCPUMetrics.system.max 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] + } + + 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 + } + } + + def expectGCMetrics(listener: TestProbe, waitTime: FiniteDuration): GCMetricSnapshot = { + val tickSnapshot = within(waitTime) { + listener.expectMsgType[TickMetricSnapshot] + } + + val gcMetricsOption = tickSnapshot.metrics.get(GCMetrics(SystemMetricsExtension.garbageCollectors(0).getName)) + gcMetricsOption should not be empty + gcMetricsOption.get.asInstanceOf[GCMetricSnapshot] + } + + 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 + } + } + + 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] + } + + 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 + } + } + + 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] + } + + 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 + } + } + + 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] + } + + 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 + } + } + + 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] + } + + 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 + } + } +} diff --git a/kamon-system/src/main/resources/reference.conf b/kamon-system/src/main/resources/reference.conf deleted file mode 100644 index 94d28106..00000000 --- a/kamon-system/src/main/resources/reference.conf +++ /dev/null @@ -1,28 +0,0 @@ -# ==================================== # -# Kamon-System Reference Configuration # -# ==================================== # - -kamon { - precision { - system { - processing-time { - highest-trackable-value = 3600000000000 - significant-value-digits = 2 - } - time-in-mailbox { - highest-trackable-value = 3600000000000 - significant-value-digits = 2 - } - mailbox-size { - highest-trackable-value = 999999999 - significant-value-digits = 2 - } - } - jvm { - processing-time { - highest-trackable-value = 3600000000000 - significant-value-digits = 2 - } - } - } -} \ No newline at end of file diff --git a/kamon-system/src/main/scala/kamon/metrics/CpuMetricsCollector.scala b/kamon-system/src/main/scala/kamon/metrics/CpuMetricsCollector.scala deleted file mode 100644 index 17f6fb08..00000000 --- a/kamon-system/src/main/scala/kamon/metrics/CpuMetricsCollector.scala +++ /dev/null @@ -1,74 +0,0 @@ -package kamon.metrics - -import kamon.system.native.SigarLoader -import org.hyperic.sigar.{NetInterfaceStat, Swap} - -trait SigarExtensionProvider { - self: MetricsCollector => - - lazy val sigar = SigarLoader.init -} - -trait MetricsCollector extends SigarExtensionProvider { - def collect: MetricsMeasurement -} - -sealed trait MetricsMeasurement -case class MemoryMetricsMeasurement(memUsage: Long, memSwapPageIn: Long, memSwapPageOut: Long) extends MetricsMeasurement -case class NetworkMetricsMeasurement(tcpCurrEstab: Long, - tcpEstabResets: Long, - netRxBytesRate: Long, - netTxBytesRate: Long, - netRxErrors: Long, - netTxErrors: Long) extends MetricsMeasurement - -case class CpuMetricsMeasurement(cpuUser: Long, cpuSys: Long, cpuCombined: Long, - loadAverage1min: Long, - loadAverage5min: Long, - loadAverage15min: Long) extends MetricsMeasurement - - - -class CpuMetricsCollector extends MetricsCollector { - val loadAverage = sigar.getLoadAverage - val cpuPerc = sigar.getCpuPerc - - - def collect(): CpuMetricsMeasurement = { - println(s"ProcCPU->${sigar.getProcCpu(sigar.getPid)}") - val loadAverage1min = loadAverage(0).toLong - val loadAverage5min = loadAverage(1).toLong - val loadAverage15min = loadAverage(2).toLong - - CpuMetricsMeasurement(cpuPerc.getUser.toLong, cpuPerc.getSys.toLong, cpuPerc.getCombined.toLong, loadAverage1min, loadAverage5min, loadAverage15min) - } -} - -class MemoryMetricsCollector extends MetricsCollector { - val swap: Swap = sigar.getSwap - - def collect(): MetricsMeasurement = MemoryMetricsMeasurement(sigar.getMem.getUsedPercent.toLong, swap.getPageIn, swap.getPageOut) -} - -class NetWorkMetricsCollector extends MetricsCollector { - val interfaces = sigar.getNetInterfaceList.toSet - val tcp = sigar.getTcp - - var netRxBytes = 0L - var netTxBytes = 0L - var netRxErrors = 0L - var netTxErrors = 0L - - def collect(): MetricsMeasurement = { - for{ - interface <- interfaces - net:NetInterfaceStat <- sigar.getNetInterfaceStat(interface) - }{ - netRxBytes += net.getRxBytes - netTxBytes += net.getTxBytes - netRxErrors += net.getRxErrors - netTxErrors += net.getTxErrors - } - NetworkMetricsMeasurement(tcp.getCurrEstab, tcp.getEstabResets,netRxBytes, netTxBytes, netRxErrors, netTxErrors) - } -} \ No newline at end of file diff --git a/kamon-system/src/main/scala/kamon/metrics/JvmMetrics.scala b/kamon-system/src/main/scala/kamon/metrics/JvmMetrics.scala deleted file mode 100644 index fb3bfeb8..00000000 --- a/kamon-system/src/main/scala/kamon/metrics/JvmMetrics.scala +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ========================================================================================= - * Copyright © 2013-2014 the kamon project - * - * 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 com.typesafe.config.Config -import org.HdrHistogram.HdrRecorder - -case class JvmMetrics(name: String) extends MetricGroupIdentity { - val category = JvmMetrics -} - -object JvmMetrics extends MetricGroupCategory { - val name = "system" - - case object MaximumPoolSize extends MetricIdentity { val name, tag = "maximum-pool-size" } - case object RunningThreadCount extends MetricIdentity { val name, tag = "running-thread-count" } - case object QueueTaskCount extends MetricIdentity { val name, tag = "queued-task-count" } - case object PoolSize extends MetricIdentity { val name, tag = "pool-size" } - - case class JvmMetricRecorder(maximumPoolSize: MetricRecorder, runningThreadCount: MetricRecorder, queueTaskCount: MetricRecorder, poolSize: MetricRecorder) - extends MetricGroupRecorder { - - def collect: MetricGroupSnapshot = { - JvmMetricSnapshot(maximumPoolSize.collect(), runningThreadCount.collect(), queueTaskCount.collect(), poolSize.collect()) - } - } - - case class JvmMetricSnapshot(maximumPoolSize: MetricSnapshotLike, runningThreadCount: MetricSnapshotLike, queueTaskCount: MetricSnapshotLike, poolSize: MetricSnapshotLike) - extends MetricGroupSnapshot { - - val metrics: Map[MetricIdentity, MetricSnapshotLike] = Map( - (MaximumPoolSize -> maximumPoolSize), - (RunningThreadCount -> runningThreadCount), - (QueueTaskCount -> queueTaskCount), - (PoolSize -> poolSize)) - } - - val Factory = new MetricGroupFactory { - type GroupRecorder = JvmMetricRecorder - - def create(config: Config): JvmMetricRecorder = { - val settings = config.getConfig("precision.jvm") - - val threadCountConfig = extractPrecisionConfig(settings.getConfig("maximum-pool-size")) - val RunningThreadCountConfig = extractPrecisionConfig(settings.getConfig("running-thread-count")) - val QueueTaskCountConfig = extractPrecisionConfig(settings.getConfig("queued-task-count")) - val PoolSizeConfig = extractPrecisionConfig(settings.getConfig("pool-size")) - - new JvmMetricRecorder( - HdrRecorder(threadCountConfig.highestTrackableValue, threadCountConfig.significantValueDigits, Scale.Unit), - HdrRecorder(RunningThreadCountConfig.highestTrackableValue, RunningThreadCountConfig.significantValueDigits, Scale.Unit), - HdrRecorder(QueueTaskCountConfig.highestTrackableValue, QueueTaskCountConfig.significantValueDigits, Scale.Unit), - HdrRecorder(PoolSizeConfig.highestTrackableValue, PoolSizeConfig.significantValueDigits, Scale.Unit)) - } - } -} - diff --git a/kamon-system/src/main/scala/kamon/metrics/SystemMetrics.scala b/kamon-system/src/main/scala/kamon/metrics/SystemMetrics.scala deleted file mode 100644 index 9bcd8917..00000000 --- a/kamon-system/src/main/scala/kamon/metrics/SystemMetrics.scala +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ========================================================================================= - * Copyright © 2013-2014 the kamon project - * - * 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 com.typesafe.config.Config -import org.HdrHistogram.HdrRecorder - -case class SystemMetrics(name: String) extends MetricGroupIdentity { - val category = JvmMetrics -} - -object SystemMetrics extends MetricGroupCategory { - val name = "system" - - case object MaximumPoolSize extends MetricIdentity { val name, tag = "maximum-pool-size" } - case object RunningThreadCount extends MetricIdentity { val name, tag = "running-thread-count" } - case object QueueTaskCount extends MetricIdentity { val name, tag = "queued-task-count" } - case object PoolSize extends MetricIdentity { val name, tag = "pool-size" } - - case class SystemMetricRecorder(maximumPoolSize: MetricRecorder, runningThreadCount: MetricRecorder, queueTaskCount: MetricRecorder, poolSize: MetricRecorder) - extends MetricGroupRecorder { - - def collect: MetricGroupSnapshot = { - SystemMetricSnapshot(maximumPoolSize.collect(), runningThreadCount.collect(), queueTaskCount.collect(), poolSize.collect()) - } - } - - case class SystemMetricSnapshot(maximumPoolSize: MetricSnapshotLike, runningThreadCount: MetricSnapshotLike, queueTaskCount: MetricSnapshotLike, poolSize: MetricSnapshotLike) - extends MetricGroupSnapshot { - - val metrics: Map[MetricIdentity, MetricSnapshotLike] = Map( - (MaximumPoolSize -> maximumPoolSize), - (RunningThreadCount -> runningThreadCount), - (QueueTaskCount -> queueTaskCount), - (PoolSize -> poolSize)) - } - - val Factory = new MetricGroupFactory { - type GroupRecorder = SystemMetricRecorder - - def create(config: Config): SystemMetricRecorder = { - val settings = config.getConfig("precision.system") - - val threadCountConfig = extractPrecisionConfig(settings.getConfig("maximum-pool-size")) - val RunningThreadCountConfig = extractPrecisionConfig(settings.getConfig("running-thread-count")) - val QueueTaskCountConfig = extractPrecisionConfig(settings.getConfig("queued-task-count")) - val PoolSizeConfig = extractPrecisionConfig(settings.getConfig("pool-size")) - - new SystemMetricRecorder( - HdrRecorder(threadCountConfig.highestTrackableValue, threadCountConfig.significantValueDigits, Scale.Unit), - HdrRecorder(RunningThreadCountConfig.highestTrackableValue, RunningThreadCountConfig.significantValueDigits, Scale.Unit), - HdrRecorder(QueueTaskCountConfig.highestTrackableValue, QueueTaskCountConfig.significantValueDigits, Scale.Unit), - HdrRecorder(PoolSizeConfig.highestTrackableValue, PoolSizeConfig.significantValueDigits, Scale.Unit)) - } - } -} - diff --git a/kamon-system/src/main/scala/kamon/system/System.scala b/kamon-system/src/main/scala/kamon/system/System.scala deleted file mode 100644 index a6c468ef..00000000 --- a/kamon-system/src/main/scala/kamon/system/System.scala +++ /dev/null @@ -1,36 +0,0 @@ -/* - * ========================================================================================= - * Copyright © 2013-2014 the kamon project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - * ========================================================================================= - */ - -package kamon.system - -import akka.actor.{ ExtendedActorSystem, Extension, ExtensionIdProvider, ExtensionId } -import kamon.Kamon -import akka.event.Logging - -object System extends ExtensionId[SystemExtension] with ExtensionIdProvider { - override def lookup(): ExtensionId[_ <: Extension] = System - override def createExtension(system: ExtendedActorSystem): SystemExtension = new SystemExtension(system) -} - -class SystemExtension(private val system: ExtendedActorSystem) extends Kamon.Extension { - val log = Logging(system, classOf[SystemExtension]) - log.info("Starting the Kamon(System) extension") - - private val config = system.settings.config.getConfig("kamon.system") - - val defaultDispatcher = system.dispatchers.lookup(config.getString("dispatcher")) -} - diff --git a/kamon-system/src/main/scala/kamon/system/native/SigarLoader.scala b/kamon-system/src/main/scala/kamon/system/native/SigarLoader.scala deleted file mode 100644 index 511a8ffc..00000000 --- a/kamon-system/src/main/scala/kamon/system/native/SigarLoader.scala +++ /dev/null @@ -1,82 +0,0 @@ -package kamon.system.native - -import org.hyperic.sigar.Sigar -import org.hyperic.sigar.SigarProxy -import java.io._ -import scalax.io.JavaConverters._ -import scalax.io._ - -import Resource._ - -import scalax.file.Path -import java.util -import scala.collection.JavaConversions._ - -object SigarLoader { - val Version = "1.6.4" - val JavaLibraryPath = "java.library.path" - val TmpDir = "java.io.tmpdir" - val IndexFile = "/kamon/system/native/index" - val UsrPathField = "usr_paths" - - def init: SigarProxy = init(new File(System.getProperty(TmpDir))) - - private def init(baseTmp: File): SigarProxy = { - val tmpDir = createTmpDir(baseTmp) - for (lib ← loadIndex) copy(lib, tmpDir) - - attachToLibraryPath(tmpDir) - - try { - val sigar = new Sigar - sigar.getPid - sigar - } catch { - case t: Throwable ⇒ - throw new RuntimeException("Failed to load sigar", t) - } - } - - private val usrPathField = { - val usrPathField = classOf[ClassLoader].getDeclaredField(UsrPathField) - usrPathField.setAccessible(true) - usrPathField - } - - private 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 def newLibraryPath(dirAbsolutePath: String): String = { - Option(System.getProperty(JavaLibraryPath)).fold(dirAbsolutePath)(oldValue ⇒ s"$dirAbsolutePath${File.pathSeparator}$oldValue") - } - - private def copy(lib: String, tmpDir: File) { - val dest: Path = Path(new File(tmpDir, lib)) - if (dest.exists) return - val currentFile = Resource.fromInputStream(classOf[Loader].getResourceAsStream("" + lib)) - currentFile.acquireFor(current ⇒ dest.doCopyFrom(current.asInput)) - } - - private def createTmpDir(baseTmp: File): File = { - val path = Path(new File(baseTmp, s"sigar-$Version")) - path.createDirectory(failIfExists = false) - path.jfile - } - - private def loadIndex: util.List[String] = { - val libs = new util.ArrayList[String] - val input = fromInputStream(classOf[Loader].getResourceAsStream(IndexFile)) - input.lines().foreach(libs.add) - libs - } -} - -class Loader \ No newline at end of file diff --git a/kamon-system/src/main/scala/kamon/system/native/index b/kamon-system/src/main/scala/kamon/system/native/index deleted file mode 100644 index ebc7f952..00000000 --- a/kamon-system/src/main/scala/kamon/system/native/index +++ /dev/null @@ -1,22 +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 - diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-freebsd-6.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-freebsd-6.so deleted file mode 100644 index 3e94f0d2..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-freebsd-6.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-linux.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-linux.so deleted file mode 100644 index 5a2e4c24..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-linux.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-solaris.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-solaris.so deleted file mode 100644 index 6396482a..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-amd64-solaris.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-ia64-hpux-11.sl b/kamon-system/src/main/scala/kamon/system/native/libsigar-ia64-hpux-11.sl deleted file mode 100644 index d92ea4a9..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-ia64-hpux-11.sl and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-ia64-linux.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-ia64-linux.so deleted file mode 100644 index 2bd2fc8e..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-ia64-linux.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-pa-hpux-11.sl b/kamon-system/src/main/scala/kamon/system/native/libsigar-pa-hpux-11.sl deleted file mode 100644 index 0dfd8a11..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-pa-hpux-11.sl and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc-aix-5.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc-aix-5.so deleted file mode 100644 index 7d4b5199..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc-aix-5.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc-linux.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc-linux.so deleted file mode 100644 index 4394b1b0..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc-linux.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc64-aix-5.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc64-aix-5.so deleted file mode 100644 index 35fd8288..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc64-aix-5.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc64-linux.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc64-linux.so deleted file mode 100644 index a1ba2529..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-ppc64-linux.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-s390x-linux.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-s390x-linux.so deleted file mode 100644 index c275f4ac..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-s390x-linux.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-sparc-solaris.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-sparc-solaris.so deleted file mode 100644 index aa847d2b..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-sparc-solaris.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-sparc64-solaris.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-sparc64-solaris.so deleted file mode 100644 index 6c4fe809..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-sparc64-solaris.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-universal-macosx.dylib b/kamon-system/src/main/scala/kamon/system/native/libsigar-universal-macosx.dylib deleted file mode 100644 index 27ab1071..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-universal-macosx.dylib and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-universal64-macosx.dylib b/kamon-system/src/main/scala/kamon/system/native/libsigar-universal64-macosx.dylib deleted file mode 100644 index 0c721fec..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-universal64-macosx.dylib and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-freebsd-5.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-freebsd-5.so deleted file mode 100644 index 8c50c611..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-freebsd-5.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-freebsd-6.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-freebsd-6.so deleted file mode 100644 index f0800274..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-freebsd-6.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-linux.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-linux.so deleted file mode 100644 index a0b64edd..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-linux.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-solaris.so b/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-solaris.so deleted file mode 100644 index c6452e56..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/libsigar-x86-solaris.so and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/sigar-amd64-winnt.dll b/kamon-system/src/main/scala/kamon/system/native/sigar-amd64-winnt.dll deleted file mode 100644 index 1ec8a035..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/sigar-amd64-winnt.dll and /dev/null differ diff --git a/kamon-system/src/main/scala/kamon/system/native/sigar-x86-winnt.dll b/kamon-system/src/main/scala/kamon/system/native/sigar-x86-winnt.dll deleted file mode 100644 index 6afdc016..00000000 Binary files a/kamon-system/src/main/scala/kamon/system/native/sigar-x86-winnt.dll and /dev/null differ diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 78240abe..1b67d214 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -37,8 +37,6 @@ object Dependencies { val jsr166 = "io.gatling" % "jsr166e" % "1.0" val scalaCompiler = "org.scala-lang" % "scala-compiler" % Settings.ScalaVersion val sigar = "org.fusesource" % "sigar" % "1.6.4" - val ioCore = "com.github.scala-incubator.io" %% "scala-io-core" % "0.4.3" - val ioFile = "com.github.scala-incubator.io" %% "scala-io-file" % "0.4.3" def compile (deps: ModuleID*): Seq[ModuleID] = deps map (_ % "compile") def provided (deps: ModuleID*): Seq[ModuleID] = deps map (_ % "provided") diff --git a/project/Projects.scala b/project/Projects.scala index 768ac6d8..dd44f6bc 100644 --- a/project/Projects.scala +++ b/project/Projects.scala @@ -7,7 +7,7 @@ object Projects extends Build { import Dependencies._ lazy val root = Project("root", file(".")) - .aggregate(kamonCore, kamonSpray, kamonNewrelic, kamonPlayground, kamonDashboard, kamonTestkit, kamonPlay, kamonStatsD, kamonDatadog) + .aggregate(kamonCore, kamonSpray, kamonNewrelic, kamonPlayground, kamonDashboard, kamonTestkit, kamonPlay, kamonStatsD, kamonDatadog, kamonSystemMetrics) .settings(basicSettings: _*) .settings(formatSettings: _*) .settings(noPublishing: _*) @@ -57,7 +57,7 @@ object Projects extends Build { .settings( libraryDependencies ++= compile(akkaActor, akkaSlf4j, sprayCan, sprayClient, sprayRouting, logback)) - .dependsOn(kamonSpray, kamonNewrelic, kamonStatsD, kamonDatadog) + .dependsOn(kamonSpray, kamonNewrelic, kamonStatsD, kamonDatadog, kamonSystemMetrics) lazy val kamonDashboard = Project("kamon-dashboard", file("kamon-dashboard")) @@ -85,12 +85,14 @@ object Projects extends Build { .settings(formatSettings: _*) .settings(libraryDependencies ++= compile(akkaActor) ++ test(scalatest, akkaTestKit, slf4Api, slf4nop)) .dependsOn(kamonCore) + .dependsOn(kamonSystemMetrics % "provided") lazy val kamonDatadog = Project("kamon-datadog", file("kamon-datadog")) .settings(basicSettings: _*) .settings(formatSettings: _*) - .settings(libraryDependencies ++= compile(akkaActor) ++ test(scalatest, akkaTestKit, slf4Api, slf4nop)) + .settings(libraryDependencies ++= compile(akkaActor) ++ test(scalatest, akkaTestKit, slf4Api, slf4nop)) .dependsOn(kamonCore) + .dependsOn(kamonSystemMetrics % "provided") lazy val kamonMacros = Project("kamon-macros", file("kamon-macros")) .settings(basicSettings: _*) @@ -98,5 +100,11 @@ object Projects extends Build { .settings(noPublishing: _*) .settings(libraryDependencies ++= compile(scalaCompiler)) + lazy val kamonSystemMetrics = Project("kamon-system-metrics", file("kamon-system-metrics")) + .settings(basicSettings: _*) + .settings(formatSettings: _*) + .settings(libraryDependencies ++= compile(sigar) ++ test(scalatest, akkaTestKit, slf4Api, slf4nop)) + .dependsOn(kamonCore) + val noPublishing = Seq(publish := (), publishLocal := (), publishArtifact := false) } -- cgit v1.2.3 From dfef9dce52782fb4939556adb926d7ff531d72b3 Mon Sep 17 00:00:00 2001 From: Diego Date: Sun, 27 Jul 2014 19:02:23 -0300 Subject: kamon-system-metrics: add system metrics to datadog and statsd modules --- kamon-datadog/src/main/resources/reference.conf | 4 +++ .../src/main/scala/kamon/datadog/Datadog.scala | 19 ++++++++++--- .../src/main/resources/application.conf | 2 +- kamon-statsd/src/main/resources/reference.conf | 4 +++ .../src/main/scala/kamon/statsd/StatsD.scala | 9 ++++++ .../src/main/java/kamon/system/SigarHolder.java | 29 ------------------- .../kamon/system/SystemMetricsCollector.scala | 9 +++--- .../scala/kamon/system/sigar/SigarLoader.scala | 33 +++++++++++++--------- 8 files changed, 58 insertions(+), 51 deletions(-) delete mode 100644 kamon-system-metrics/src/main/java/kamon/system/SigarHolder.java (limited to 'kamon-playground') diff --git a/kamon-datadog/src/main/resources/reference.conf b/kamon-datadog/src/main/resources/reference.conf index 231eaf7d..4de24526 100644 --- a/kamon-datadog/src/main/resources/reference.conf +++ b/kamon-datadog/src/main/resources/reference.conf @@ -24,6 +24,10 @@ kamon { dispatcher = [ "*" ] } + # Enable system metrics + # In order to not get a ClassNotFoundException, we must register the kamon-sytem-metrics module + report-system-metrics = false + # Application prefix for all metrics pushed to Datadog. The default namespacing scheme for metrics follows # this pattern: # application.entity-name.metric-name diff --git a/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala b/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala index 1803b833..6498f851 100644 --- a/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala +++ b/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala @@ -16,14 +16,17 @@ package kamon.datadog +import java.net.InetSocketAddress +import java.util.concurrent.TimeUnit.MILLISECONDS + import akka.actor._ +import akka.event.Logging import kamon.Kamon import kamon.metric._ -import scala.concurrent.duration._ +import kamon.metrics._ + import scala.collection.JavaConverters._ -import akka.event.Logging -import java.net.InetSocketAddress -import java.util.concurrent.TimeUnit.MILLISECONDS +import scala.concurrent.duration._ object Datadog extends ExtensionId[DatadogExtension] with ExtensionIdProvider { override def lookup(): ExtensionId[_ <: Extension] = Datadog @@ -65,6 +68,14 @@ class DatadogExtension(system: ExtendedActorSystem) extends Kamon.Extension { Kamon(Metrics)(system).subscribe(DispatcherMetrics, dispatcherPathPattern, datadogMetricsListener, permanently = true) } + // Subscribe to SystemMetrics + val includeSystemMetrics = datadogConfig.getBoolean("report-system-metrics") + if (includeSystemMetrics) { + List(CPUMetrics, ProcessCPUMetrics, MemoryMetrics, NetworkMetrics, GCMetrics, HeapMetrics) foreach { metric ⇒ + Kamon(Metrics)(system).subscribe(metric, "*", datadogMetricsListener, permanently = true) + } + } + def buildMetricsListener(tickInterval: Long, flushInterval: Long): ActorRef = { assert(flushInterval >= tickInterval, "Datadog flush-interval needs to be equal or greater to the tick-interval") diff --git a/kamon-playground/src/main/resources/application.conf b/kamon-playground/src/main/resources/application.conf index af85207f..d827731a 100644 --- a/kamon-playground/src/main/resources/application.conf +++ b/kamon-playground/src/main/resources/application.conf @@ -1,7 +1,7 @@ akka { loglevel = INFO - extensions = ["kamon.system.SystemMetrics"] + extensions = ["kamon.statsd.StatsD", "kamon.system.SystemMetrics"] actor { debug { diff --git a/kamon-statsd/src/main/resources/reference.conf b/kamon-statsd/src/main/resources/reference.conf index fd6293d9..eac5eade 100644 --- a/kamon-statsd/src/main/resources/reference.conf +++ b/kamon-statsd/src/main/resources/reference.conf @@ -24,6 +24,10 @@ kamon { dispatcher = [ "*" ] } + # Enable system metrics + # In order to not get a ClassNotFoundException, we must register the kamon-sytem-metrics module + report-system-metrics = false + simple-metric-key-generator { # Application prefix for all metrics pushed to StatsD. The default namespacing scheme for metrics follows # this pattern: diff --git a/kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala b/kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala index 299b1acc..e9350fae 100644 --- a/kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala +++ b/kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala @@ -19,6 +19,7 @@ package kamon.statsd import akka.actor._ import kamon.Kamon import kamon.metric._ +import kamon.metrics._ import scala.concurrent.duration._ import scala.collection.JavaConverters._ import com.typesafe.config.Config @@ -69,6 +70,14 @@ class StatsDExtension(system: ExtendedActorSystem) extends Kamon.Extension { Kamon(Metrics)(system).subscribe(DispatcherMetrics, dispatcherPathPattern, statsDMetricsListener, permanently = true) } + // Subscribe to SystemMetrics + val includeSystemMetrics = statsDConfig.getBoolean("report-system-metrics") + if (includeSystemMetrics) { + List(CPUMetrics, ProcessCPUMetrics, MemoryMetrics, NetworkMetrics, GCMetrics, HeapMetrics) foreach { metric ⇒ + Kamon(Metrics)(system).subscribe(metric, "*", statsDMetricsListener, permanently = true) + } + } + def buildMetricsListener(tickInterval: Long, flushInterval: Long): ActorRef = { assert(flushInterval >= tickInterval, "StatsD flush-interval needs to be equal or greater to the tick-interval") val defaultMetricKeyGenerator = new SimpleMetricKeyGenerator(system.settings.config) diff --git a/kamon-system-metrics/src/main/java/kamon/system/SigarHolder.java b/kamon-system-metrics/src/main/java/kamon/system/SigarHolder.java deleted file mode 100644 index 7c8cd695..00000000 --- a/kamon-system-metrics/src/main/java/kamon/system/SigarHolder.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * ========================================================================================= - * Copyright © 2013-2014 the kamon project - * - * 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 kamon.system.sigar.SigarLoader; -import org.hyperic.sigar.SigarProxy; - -public class SigarHolder { - private static class LazySigarHolder { - static final SigarProxy instance = SigarLoader.sigarProxy(); - } - - public static SigarProxy instance() { - return LazySigarHolder.instance; - } -} diff --git a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala index fde9820a..a5a2f411 100644 --- a/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala +++ b/kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala @@ -15,20 +15,21 @@ */ package kamon.system -import akka.actor.{ Props, Actor } +import akka.actor.{ Actor, Props } import kamon.Kamon import kamon.metric.Metrics import kamon.metrics.CPUMetrics.CPUMetricRecorder import kamon.metrics.MemoryMetrics.MemoryMetricRecorder import kamon.metrics.NetworkMetrics.NetworkMetricRecorder import kamon.metrics.ProcessCPUMetrics.ProcessCPUMetricsRecorder -import kamon.metrics.{ NetworkMetrics, MemoryMetrics, ProcessCPUMetrics, CPUMetrics } -import org.hyperic.sigar.{ NetInterfaceStat, SigarProxy, Mem } +import kamon.metrics.{ CPUMetrics, MemoryMetrics, NetworkMetrics, ProcessCPUMetrics } +import kamon.system.sigar.SigarHolder +import org.hyperic.sigar.{ Mem, NetInterfaceStat, SigarProxy } import scala.concurrent.duration.FiniteDuration class SystemMetricsCollector(collectInterval: FiniteDuration) extends Actor with SigarExtensionProvider { - import SystemMetricsCollector._ + import kamon.system.SystemMetricsCollector._ import kamon.system.SystemMetricsExtension._ val collectSchedule = context.system.scheduler.schedule(collectInterval, collectInterval, self, Collect)(context.dispatcher) 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 index 0d6c2410..d138ec8f 100644 --- a/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarLoader.scala +++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarLoader.scala @@ -19,14 +19,19 @@ package kamon.system.sigar import java.io._ import java.util import java.util.logging.Logger -import java.util.{ Date, ArrayList, List } +import java.util.{ ArrayList, Date, List } -import org.hyperic.sigar.{ OperatingSystem, CpuPerc, Sigar, SigarProxy } +import org.hyperic.sigar.{ OperatingSystem, Sigar, SigarProxy } 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" @@ -138,6 +143,7 @@ object SigarLoader { val now = System.currentTimeMillis() new Date(now - (uptime.getUptime() * 1000).toLong) } + def osInfo() = { val NewLine = "\n" val os = OperatingSystem.getInstance @@ -149,17 +155,18 @@ object SigarLoader { .toString() } - val message = """ - | - | _____ _ __ __ _ _ _ _ _ - | / ____| | | | \/ | | | (_) | | | | | | - || (___ _ _ ___| |_ ___ _ __ ___ | \ / | ___| |_ _ __ _ ___ ___| | ___ __ _ __| | ___ __| | - | \___ \| | | / __| __/ _ \ '_ ` _ \| |\/| |/ _ \ __| '__| |/ __/ __| | / _ \ / _` |/ _` |/ _ \/ _` | - | ____) | |_| \__ \ || __/ | | | | | | | | __/ |_| | | | (__\__ \ |___| (_) | (_| | (_| | __/ (_| | - ||_____/ \__, |___/\__\___|_| |_| |_|_| |_|\___|\__|_| |_|\___|___/______\___/ \__,_|\__,_|\___|\__,_| - | __/ | - | |___/ - """.stripMargin + s"\nBoot Time: ${uptime(sigar)} \nLoad Average: ${loadAverage(sigar)} \n${osInfo()}" + val message = + """ + | + | _____ _ __ __ _ _ _ _ _ + | / ____| | | | \/ | | | (_) | | | | | | + || (___ _ _ ___| |_ ___ _ __ ___ | \ / | ___| |_ _ __ _ ___ ___| | ___ __ _ __| | ___ __| | + | \___ \| | | / __| __/ _ \ '_ ` _ \| |\/| |/ _ \ __| '__| |/ __/ __| | / _ \ / _` |/ _` |/ _ \/ _` | + | ____) | |_| \__ \ || __/ | | | | | | | | __/ |_| | | | (__\__ \ |___| (_) | (_| | (_| | __/ (_| | + ||_____/ \__, |___/\__\___|_| |_| |_|_| |_|\___|\__|_| |_|\___|___/______\___/ \__,_|\__,_|\___|\__,_| + | __/ | + | |___/ + """.stripMargin + s"\nBoot Time: ${uptime(sigar)} \nLoad Average: ${loadAverage(sigar)} \n${osInfo()}" log.info(message) } class Loader private[sigar] -- cgit v1.2.3 From 33390af40b39ca22b83e3bced83c9496f6c556ab Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Sun, 27 Jul 2014 20:33:38 -0300 Subject: = newrelic: upgrade to the latest metrics scheme, closes #54 --- .../src/main/scala/kamon/metric/TraceMetrics.scala | 4 ++-- .../scala/kamon/metric/instrument/Histogram.scala | 11 +++++++++++ kamon-newrelic/src/main/resources/reference.conf | 2 +- .../src/main/scala/kamon/newrelic/NewRelic.scala | 4 ++-- .../kamon/newrelic/WebTransactionMetrics.scala | 21 +++++++++++---------- .../src/main/resources/application.conf | 4 ++-- 6 files changed, 29 insertions(+), 17 deletions(-) (limited to 'kamon-playground') diff --git a/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala b/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala index 187eb07d..c506fe81 100644 --- a/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala +++ b/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala @@ -69,8 +69,8 @@ object TraceMetrics extends MetricGroupCategory { val segmentConfig = settings.getConfig("segment") new TraceMetricRecorder( - Histogram.fromConfig(elapsedTimeConfig), - () ⇒ Histogram.fromConfig(segmentConfig)) + Histogram.fromConfig(elapsedTimeConfig, Scale.Nano), + () ⇒ Histogram.fromConfig(segmentConfig, Scale.Nano)) } } diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/Histogram.scala b/kamon-core/src/main/scala/kamon/metric/instrument/Histogram.scala index 9ce11f49..7d8022f7 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/Histogram.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/Histogram.scala @@ -78,6 +78,17 @@ object Histogram { def recordsIterator: Iterator[Record] def merge(that: Histogram.Snapshot, context: CollectionContext): Histogram.Snapshot } + + object Snapshot { + def empty(targetScale: Scale) = new Snapshot { + override def min: Long = 0L + override def max: Long = 0L + override def recordsIterator: Iterator[Record] = Iterator.empty + override def merge(that: Snapshot, context: CollectionContext): Snapshot = that + override def scale: Scale = targetScale + override def numberOfMeasurements: Long = 0L + } + } } /** diff --git a/kamon-newrelic/src/main/resources/reference.conf b/kamon-newrelic/src/main/resources/reference.conf index 24522d63..13aaca2f 100644 --- a/kamon-newrelic/src/main/resources/reference.conf +++ b/kamon-newrelic/src/main/resources/reference.conf @@ -7,7 +7,7 @@ kamon { apdexT = 1 second app-name = "Kamon[Development]" - license-key = 2e24765acb032cb9e7207013b5ba3e2ab7d2d75c + license-key = e7d350b14228f3d28f35bc3140df2c3e565ea5d5 } } diff --git a/kamon-newrelic/src/main/scala/kamon/newrelic/NewRelic.scala b/kamon-newrelic/src/main/scala/kamon/newrelic/NewRelic.scala index 85861454..d83e0335 100644 --- a/kamon-newrelic/src/main/scala/kamon/newrelic/NewRelic.scala +++ b/kamon-newrelic/src/main/scala/kamon/newrelic/NewRelic.scala @@ -26,11 +26,12 @@ import java.util.concurrent.TimeUnit.MILLISECONDS class NewRelicExtension(system: ExtendedActorSystem) extends Kamon.Extension { val config = system.settings.config.getConfig("kamon.newrelic") + val collectionContext = Kamon(Metrics)(system).buildDefaultCollectionContext val metricsListener = system.actorOf(Props[NewRelicMetricsListener], "kamon-newrelic") val apdexT: Double = config.getDuration("apdexT", MILLISECONDS) / 1E3 // scale to seconds. Kamon(Metrics)(system).subscribe(TraceMetrics, "*", metricsListener, permanently = true) - //Kamon(Metrics)(system).subscribe(UserMetrics, "*", metricsListener, permanently = true) + Kamon(Metrics)(system).subscribe(UserMetrics.category, "*", metricsListener, permanently = true) } class NewRelicMetricsListener extends Actor with ActorLogging { @@ -61,6 +62,5 @@ object NewRelic extends ExtensionId[NewRelicExtension] with ExtensionIdProvider math.max(max, that.max), sumOfSquares + that.sumOfSquares) } - } } \ No newline at end of file diff --git a/kamon-newrelic/src/main/scala/kamon/newrelic/WebTransactionMetrics.scala b/kamon-newrelic/src/main/scala/kamon/newrelic/WebTransactionMetrics.scala index 38517e10..a8c54684 100644 --- a/kamon-newrelic/src/main/scala/kamon/newrelic/WebTransactionMetrics.scala +++ b/kamon-newrelic/src/main/scala/kamon/newrelic/WebTransactionMetrics.scala @@ -20,25 +20,28 @@ import kamon.metric._ import kamon.metric.TraceMetrics.ElapsedTime import akka.actor.Actor import kamon.Kamon +import kamon.metric.instrument.Histogram trait WebTransactionMetrics { self: Actor ⇒ def collectWebTransactionMetrics(metrics: Map[MetricGroupIdentity, MetricGroupSnapshot]): Seq[NewRelic.Metric] = { - val apdexBuilder = new ApdexBuilder("Apdex", None, Kamon(NewRelic)(context.system).apdexT) + val newRelicExtension = Kamon(NewRelic)(context.system) + val apdexBuilder = new ApdexBuilder("Apdex", None, newRelicExtension.apdexT) + val collectionContext = newRelicExtension.collectionContext - /* // Trace metrics are recorded in nanoseconds. - var accumulatedHttpDispatcher: MetricSnapshotLike = MetricSnapshot(InstrumentTypes.Histogram, 0, Scale.Nano, Vector.empty) + var accumulatedHttpDispatcher: Histogram.Snapshot = Histogram.Snapshot.empty(Scale.Nano) val webTransactionMetrics = metrics.collect { case (TraceMetrics(name), groupSnapshot) ⇒ groupSnapshot.metrics collect { - case (ElapsedTime, snapshot) ⇒ - accumulatedHttpDispatcher = accumulatedHttpDispatcher.merge(snapshot) - snapshot.measurements.foreach(level ⇒ - apdexBuilder.record(Scale.convert(snapshot.scale, Scale.Unit, level.value), level.count)) + case (ElapsedTime, snapshot: Histogram.Snapshot) ⇒ + accumulatedHttpDispatcher = accumulatedHttpDispatcher.merge(snapshot, collectionContext) + snapshot.recordsIterator.foreach { record ⇒ + apdexBuilder.record(Scale.convert(snapshot.scale, Scale.Unit, record.level), record.count) + } toNewRelicMetric(Scale.Unit)(s"WebTransaction/Custom/$name", None, snapshot) } @@ -47,9 +50,7 @@ trait WebTransactionMetrics { val httpDispatcher = toNewRelicMetric(Scale.Unit)("HttpDispatcher", None, accumulatedHttpDispatcher) val webTransaction = toNewRelicMetric(Scale.Unit)("WebTransaction", None, accumulatedHttpDispatcher) - Seq(httpDispatcher, webTransaction, apdexBuilder.build) ++ webTransactionMetrics.flatten.toSeq */ - - ??? + Seq(httpDispatcher, webTransaction, apdexBuilder.build) ++ webTransactionMetrics.flatten.toSeq } } diff --git a/kamon-playground/src/main/resources/application.conf b/kamon-playground/src/main/resources/application.conf index d827731a..e9f73954 100644 --- a/kamon-playground/src/main/resources/application.conf +++ b/kamon-playground/src/main/resources/application.conf @@ -1,7 +1,7 @@ akka { loglevel = INFO - extensions = ["kamon.statsd.StatsD", "kamon.system.SystemMetrics"] + extensions = ["kamon.newrelic.NewRelic"] actor { debug { @@ -19,7 +19,7 @@ spray.can { kamon { newrelic { app-name = "SimpleRequestProcessor" - license-key = 2e24765acb032cb9e7207013b5ba3e2ab7d2d75c + license-key = e7d350b14228f3d28f35bc3140df2c3e565ea5d5 } } -- cgit v1.2.3 From e83babb5f88e91661bec2f1013fcb6b03612bea9 Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Tue, 29 Jul 2014 00:25:26 -0300 Subject: + logreporter: new log reporter for trace, actor and user metrics, closes #57 The new kamon-log-reporter module subscribes itselfs for trace, actor and user metrics and prints the values using ActorLogging in a pretty ascii table format. --- .../main/scala/kamon/logreporter/LogReporter.scala | 227 +++++++++++++++++++++ .../src/main/resources/application.conf | 4 +- .../main/scala/test/SimpleRequestProcessor.scala | 14 ++ project/Projects.scala | 12 +- 4 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 kamon-log-reporter/src/main/scala/kamon/logreporter/LogReporter.scala (limited to 'kamon-playground') diff --git a/kamon-log-reporter/src/main/scala/kamon/logreporter/LogReporter.scala b/kamon-log-reporter/src/main/scala/kamon/logreporter/LogReporter.scala new file mode 100644 index 00000000..b0cc2551 --- /dev/null +++ b/kamon-log-reporter/src/main/scala/kamon/logreporter/LogReporter.scala @@ -0,0 +1,227 @@ +/* + * ========================================================================================= + * Copyright © 2013-2014 the kamon project + * + * 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.logreporter + +import akka.actor._ +import kamon.Kamon +import kamon.metric.ActorMetrics.ActorMetricSnapshot +import kamon.metric.Subscriptions.TickMetricSnapshot +import kamon.metric.TraceMetrics.TraceMetricsSnapshot +import kamon.metric.UserMetrics.{ UserCounter, UserMetricsSnapshot } +import kamon.metric.instrument.{ Counter, Histogram } +import kamon.metric._ + +object LogReporter extends ExtensionId[LogReporterExtension] with ExtensionIdProvider { + override def lookup(): ExtensionId[_ <: Extension] = LogReporter + override def createExtension(system: ExtendedActorSystem): LogReporterExtension = new LogReporterExtension(system) + + trait MetricKeyGenerator { + def localhostName: String + def normalizedLocalhostName: String + def generateKey(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity): String + } +} + +class LogReporterExtension(system: ExtendedActorSystem) extends Kamon.Extension { + val subscriber = system.actorOf(Props[LogReporterSubscriber], "kamon-log-reporter") + Kamon(Metrics)(system).subscribe(TraceMetrics, "*", subscriber, permanently = true) + Kamon(Metrics)(system).subscribe(ActorMetrics, "*", subscriber, permanently = true) + Kamon(Metrics)(system).subscribe(UserMetrics.category, "*", subscriber, permanently = true) + +} + +class LogReporterSubscriber extends Actor with ActorLogging { + import LogReporterSubscriber.RichHistogramSnapshot + + def receive = { + case tick: TickMetricSnapshot ⇒ printMetricSnapshot(tick) + } + + def printMetricSnapshot(tick: TickMetricSnapshot): Unit = tick.metrics foreach { + case (identity, ams: ActorMetricSnapshot) ⇒ logActorMetrics(identity.name, ams) + case (identity, tms: TraceMetricsSnapshot) ⇒ logTraceMetrics(identity.name, tms) + case (_, ums: UserMetricsSnapshot) ⇒ logUserMetrics(ums) + } + + def logActorMetrics(name: String, ams: ActorMetricSnapshot): Unit = { + log.info( + """ + |+--------------------------------------------------------------------------------------------------+ + || | + || Actor: %-83s | + || | + || Processing Time (nanoseconds) Time in Mailbox (nanoseconds) Mailbox Size | + || Msg Count: %-12s Msg Count: %-12s Min: %-8s | + || Min: %-12s Min: %-12s Avg.: %-8s | + || 50th Perc: %-12s 50th Perc: %-12s Max: %-8s | + || 90th Perc: %-12s 90th Perc: %-12s | + || 95th Perc: %-12s 95th Perc: %-12s | + || 99th Perc: %-12s 99th Perc: %-12s Error Count: %-6s | + || 99.9th Perc: %-12s 99.9th Perc: %-12s | + || Max: %-12s Max: %-12s | + || | + |+--------------------------------------------------------------------------------------------------+""" + .stripMargin.format( + name, + ams.processingTime.numberOfMeasurements, ams.timeInMailbox.numberOfMeasurements, ams.mailboxSize.min, + ams.processingTime.min, ams.timeInMailbox.min, ams.mailboxSize.average, + ams.processingTime.percentile(0.50F), ams.timeInMailbox.percentile(0.50F), ams.mailboxSize.max, + ams.processingTime.percentile(0.90F), ams.timeInMailbox.percentile(0.90F), + ams.processingTime.percentile(0.95F), ams.timeInMailbox.percentile(0.95F), + ams.processingTime.percentile(0.99F), ams.timeInMailbox.percentile(0.99F), ams.errors.count, + ams.processingTime.percentile(0.999F), ams.timeInMailbox.percentile(0.999F), + ams.processingTime.max, ams.timeInMailbox.max)) + } + + def logTraceMetrics(name: String, tms: TraceMetricsSnapshot): Unit = { + val traceMetricsData = StringBuilder.newBuilder + + traceMetricsData.append( + """ + |+--------------------------------------------------------------------------------------------------+ + || | + || Trace: %-83s | + || Count: %-8s | + || | + || Elapsed Time (nanoseconds): | + |""" + .stripMargin.format( + name, tms.elapsedTime.numberOfMeasurements)) + + traceMetricsData.append(compactHistogramView(tms.elapsedTime)) + traceMetricsData.append( + """ + || | + |+--------------------------------------------------------------------------------------------------+""" + .stripMargin) + + log.info(traceMetricsData.toString()) + } + + def logUserMetrics(ums: UserMetricsSnapshot): Unit = { + val userMetricsData = StringBuilder.newBuilder + + userMetricsData.append( + """ + |+--------------------------------------------------------------------------------------------------+ + || | + || User Counters | + || ------------- | + |""".stripMargin) + + ums.counters.toList.sortBy(_._1.name.toLowerCase).foreach { + case (counter, snapshot) ⇒ userMetricsData.append(userCounterString(counter, snapshot)) + } + + userMetricsData.append( + """|| | + || | + || User Histograms | + || --------------- | + |""".stripMargin) + + ums.histograms.foreach { + case (histogram, snapshot) ⇒ + userMetricsData.append("| %-40s |\n".format(histogram.name)) + userMetricsData.append(compactHistogramView(snapshot)) + userMetricsData.append("\n| |\n") + } + + userMetricsData.append( + """|| | + || User MinMaxCounters | + || ------------------- | + |""".stripMargin) + + ums.minMaxCounters.foreach { + case (minMaxCounter, snapshot) ⇒ + userMetricsData.append("| %-40s |\n".format(minMaxCounter.name)) + userMetricsData.append(simpleHistogramView(snapshot)) + userMetricsData.append("\n| |\n") + } + + userMetricsData.append( + """|| | + || User Gauges | + || ----------- | + |""" + .stripMargin) + + ums.gauges.foreach { + case (gauge, snapshot) ⇒ + userMetricsData.append("| %-40s |\n".format(gauge.name)) + userMetricsData.append(simpleHistogramView(snapshot)) + userMetricsData.append("\n| |\n") + } + + userMetricsData.append( + """|| | + |+--------------------------------------------------------------------------------------------------+""" + .stripMargin) + + log.info(userMetricsData.toString()) + } + + def userCounterString(counter: UserCounter, snapshot: Counter.Snapshot): String = { + "| %30s => %-12s |\n" + .format(counter.name, snapshot.count) + } + + def compactHistogramView(histogram: Histogram.Snapshot): String = { + val sb = StringBuilder.newBuilder + + sb.append("| Min: %-11s 50th Perc: %-12s 90th Perc: %-12s 95th Perc: %-12s |\n".format( + histogram.min, histogram.percentile(0.50F), histogram.percentile(0.90F), histogram.percentile(0.95F))) + sb.append("| 99th Perc: %-12s 99.9th Perc: %-12s Max: %-12s |".format( + histogram.percentile(0.99F), histogram.percentile(0.999F), histogram.max)) + + sb.toString() + } + + def simpleHistogramView(histogram: Histogram.Snapshot): String = + "| Min: %-12s Average: %-12s Max: %-12s |" + .format(histogram.min, histogram.average, histogram.max) +} + +object LogReporterSubscriber { + + implicit class RichHistogramSnapshot(histogram: Histogram.Snapshot) { + def percentile(q: Float): Long = { + val records = histogram.recordsIterator + val qThreshold = histogram.numberOfMeasurements * q + var countToCurrentLevel = 0L + var qLevel = 0L + + while (countToCurrentLevel < qThreshold && records.hasNext) { + val record = records.next() + countToCurrentLevel += record.count + qLevel = record.level + } + + qLevel + } + + def average: Double = { + var acc = 0L + for (record ← histogram.recordsIterator) { + acc += record.count * record.level + } + + return acc / histogram.numberOfMeasurements + } + } +} \ No newline at end of file diff --git a/kamon-playground/src/main/resources/application.conf b/kamon-playground/src/main/resources/application.conf index e9f73954..bac3c97e 100644 --- a/kamon-playground/src/main/resources/application.conf +++ b/kamon-playground/src/main/resources/application.conf @@ -1,7 +1,7 @@ akka { loglevel = INFO - extensions = ["kamon.newrelic.NewRelic"] + extensions = ["kamon.logreporter.LogReporter"] actor { debug { @@ -25,7 +25,7 @@ kamon { kamon { metrics { - tick-interval = 1 second + tick-interval = 10 second filters = [ { diff --git a/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala b/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala index 84621927..301a9bbd 100644 --- a/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala +++ b/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala @@ -51,6 +51,19 @@ object SimpleRequestProcessor extends App with SimpleRoutingApp with RequestBuil implicit val timeout = Timeout(30 seconds) + val counter = Kamon(UserMetrics).registerCounter("requests") + Kamon(UserMetrics).registerCounter("requests-2") + Kamon(UserMetrics).registerCounter("requests-3") + + Kamon(UserMetrics).registerHistogram("histogram-1") + Kamon(UserMetrics).registerHistogram("histogram-2") + + Kamon(UserMetrics).registerMinMaxCounter("min-max-counter-1") + Kamon(UserMetrics).registerMinMaxCounter("min-max-counter-2") + Kamon(UserMetrics).registerMinMaxCounter("min-max-counter-3") + + //Kamon(UserMetrics).registerGauge("test-gauge")(() => 10L) + val pipeline = sendReceive val replier = system.actorOf(Props[Replier].withRouter(RoundRobinPool(nrOfInstances = 2)), "replier") val random = new Random() @@ -92,6 +105,7 @@ object SimpleRequestProcessor extends App with SimpleRoutingApp with RequestBuil path("future") { traceName("OK-Future") { dynamic { + counter.increment() complete(Future { "OK" }) } } diff --git a/project/Projects.scala b/project/Projects.scala index 94e8bfa2..8259f2aa 100644 --- a/project/Projects.scala +++ b/project/Projects.scala @@ -7,7 +7,8 @@ object Projects extends Build { import Dependencies._ lazy val root = Project("root", file(".")) - .aggregate(kamonCore, kamonSpray, kamonNewrelic, kamonPlayground, kamonDashboard, kamonTestkit, kamonPlay, kamonStatsD, kamonDatadog, kamonSystemMetrics) + .aggregate(kamonCore, kamonSpray, kamonNewrelic, kamonPlayground, kamonDashboard, kamonTestkit, kamonPlay, kamonStatsD, + kamonDatadog, kamonSystemMetrics, kamonLogReporter) .settings(basicSettings: _*) .settings(formatSettings: _*) .settings(noPublishing: _*) @@ -57,7 +58,7 @@ object Projects extends Build { .settings( libraryDependencies ++= compile(akkaActor, akkaSlf4j, sprayCan, sprayClient, sprayRouting, logback)) - .dependsOn(kamonSpray, kamonNewrelic, kamonStatsD, kamonDatadog, kamonSystemMetrics) + .dependsOn(kamonSpray, kamonNewrelic, kamonStatsD, kamonDatadog, kamonLogReporter, kamonSystemMetrics) lazy val kamonDashboard = Project("kamon-dashboard", file("kamon-dashboard")) @@ -94,6 +95,13 @@ object Projects extends Build { .dependsOn(kamonCore) .dependsOn(kamonSystemMetrics % "provided") + lazy val kamonLogReporter = Project("kamon-log-reporter", file("kamon-log-reporter")) + .settings(basicSettings: _*) + .settings(formatSettings: _*) + .settings(libraryDependencies ++= compile(akkaActor) ++ test(scalatest, akkaTestKit, slf4Api, slf4nop)) + .dependsOn(kamonCore) + .dependsOn(kamonSystemMetrics % "provided") + lazy val kamonMacros = Project("kamon-macros", file("kamon-macros")) .settings(basicSettings: _*) .settings(formatSettings: _*) -- cgit v1.2.3