diff --git a/build.sbt b/build.sbt index a4318bc..504fc39 100644 --- a/build.sbt +++ b/build.sbt @@ -14,7 +14,7 @@ * ========================================================================================= */ -val kamonCore = "io.kamon" %% "kamon-core" % "2.0.0-M5" +val kamonCore = "io.kamon" %% "kamon-core" % "2.0.0-RC1" val logback = "ch.qos.logback" % "logback-classic" % "1.0.13" val oshi = "com.github.oshi" % "oshi-core" % "3.13.2" diff --git a/kamon-host-metrics/src/main/resources/reference.conf b/kamon-host-metrics/src/main/resources/reference.conf deleted file mode 100644 index 59d9a19..0000000 --- a/kamon-host-metrics/src/main/resources/reference.conf +++ /dev/null @@ -1,57 +0,0 @@ -kamon.instrumentation.system { - jvm { - - } - - process { - hiccup-monitor-interval = 1 millisecond - } - - host { - storage { - - # Decides which file system types will be selected for tracking usage and activity metrics. By default we are - # excluding types associated with Docker and Ubuntu Snaps which would usually generate irrelevant metrics. - tracked-mount-types { - includes = [ "**" ] - excludes = ["squashfs", "tmpfs", "aufs"] - } - } - - network { - - # Decides which network interfaces will be selected for tracking network activity metrics. By default we are - # excluding network interface names known to be associated with Docker. - tracked-interfaces { - includes = [ "**" ] - excludes = [ "docker0", "br-*" ] - } - } - } -} - -kamon.modules { - host-metrics { - enabled = yes - name = "Host Metrics" - description = "Periodically collects metrics on CPU, Memory, Swap, Network and Storage usage" - factory = "kamon.instrumentation.system.host.HostMetricsCollector$Factory" - config-path = "kamon.instrumentation.system.host" - } - - process-metrics { - enabled = yes - name = "Process Metrics" - description = "Collects Process CPU and Ulimit metrics from the JVM process" - factory = "kamon.instrumentation.system.process.ProcessMetricsCollector$Factory" - config-path = "kamon.instrumentation.system.process" - } - - jvm-metrics { - enabled = yes - name = "JVM Metrics" - description = "Collects CPU, Garbage Collection, Memory, Class Loading and Threads metrics from the local JVM" - factory = "kamon.instrumentation.system.jvm.JvmMetricsCollector$Factory" - config-path = "kamon.instrumentation.system.jvm" - } -} \ No newline at end of file diff --git a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala b/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala deleted file mode 100644 index e05d879..0000000 --- a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala +++ /dev/null @@ -1,253 +0,0 @@ -package kamon.instrumentation.system.host - -import kamon.Kamon -import kamon.instrumentation.system.host.HostMetrics.StorageDeviceInstruments.DeviceInstruments -import kamon.instrumentation.system.host.HostMetrics.StorageMountInstruments.MountInstruments -import kamon.instrumentation.system.host.HostMetrics.NetworkActivityInstruments.InterfaceInstruments -import kamon.metric.{Counter, Gauge, InstrumentGroup, MeasurementUnit} -import kamon.tag.TagSet - -import scala.collection.mutable - -object HostMetrics { - - val CpuUsage = Kamon.histogram ( - name = "host.cpu.usage", - description = "Samples the CPU usage percentage", - unit = MeasurementUnit.percentage - ) - - val MemoryUsed = Kamon.gauge ( - name = "host.memory.used", - description = "Tracks the used memory Memory percentage", - unit = MeasurementUnit.information.bytes - ) - - val MemoryFree = Kamon.gauge ( - name = "host.memory.free", - description = "Tracks the free Memory percentage", - unit = MeasurementUnit.information.bytes - ) - - val MemoryTotal = Kamon.gauge ( - name = "host.memory.total", - description = "Tracks the total memory available", - unit = MeasurementUnit.information.bytes - ) - - val SwapUsed = Kamon.gauge ( - name = "host.swap.used", - description = "Tracks the used Swap space", - unit = MeasurementUnit.information.bytes - ) - - val SwapFree = Kamon.gauge ( - name = "host.swap.free", - description = "Tracks the free Swap space", - unit = MeasurementUnit.information.bytes - ) - - val SwapTotal = Kamon.gauge ( - name = "host.swap.max", - description = "Tracks the total Swap space", - unit = MeasurementUnit.information.bytes - ) - - val LoadAverage = Kamon.gauge ( - name = "host.load.average", - description = "Tracks the system load average" - ) - - val FileSystemMountSpaceUsed = Kamon.gauge ( - name = "host.storage.mount.space.used", - description = "Tracks the used space on a file system mount/volume", - unit = MeasurementUnit.information.bytes - ) - - val FileSystemMountSpaceFree = Kamon.gauge ( - name = "host.storage.mount.space.free", - description = "Tracks the free space on a file system mount/volume", - unit = MeasurementUnit.information.bytes - ) - - val FileSystemMountSpaceTotal = Kamon.gauge ( - name = "host.storage.mount.space.total", - description = "Tracks the total space on a file system mount/volume", - unit = MeasurementUnit.information.bytes - ) - - val StorageDeviceRead = Kamon.counter ( - name = "host.storage.device.data.read", - description = "Counts the amount of byes that have been read from a storage device", - unit = MeasurementUnit.information.bytes - ) - - val StorageDeviceWrite = Kamon.counter ( - name = "host.storage.device.data.write", - description = "Counts the amount of byes that have been written to a storage device", - unit = MeasurementUnit.information.bytes - ) - - val StorageDeviceReadOps = Kamon.counter ( - name = "host.storage.device.ops.read", - description = "Counts the number of read operations executed on a storage device" - ) - - val StorageDeviceWriteOps = Kamon.counter ( - name = "host.storage.device.ops.write", - description = "Counts the number of write operations executed on a storage device" - ) - - val NetworkPacketsRead = Kamon.counter ( - name = "host.network.packets.read", - description = "Counts how many packets have been read from a network interface" - ) - - val NetworkPacketsWrite = Kamon.counter ( - name = "host.network.packets.write", - description = "Counts how many packets have been written to a network interface" - ) - - val NetworkDataRead = Kamon.counter ( - name = "host.network.data.read", - description = "Counts how many bytes have been read from a network interface", - unit = MeasurementUnit.information.bytes - ) - - val NetworkDataWrite = Kamon.counter ( - name = "host.network.data.write", - description = "Counts how many bytes have been written to a network interface", - unit = MeasurementUnit.information.bytes - ) - - class CpuInstruments(tags: TagSet) extends InstrumentGroup(tags) { - val user = register(CpuUsage, "mode", "user") - val system = register(CpuUsage, "mode", "system") - val iowait = register(CpuUsage, "mode", "wait") - val idle = register(CpuUsage, "mode", "idle") - val stolen = register(CpuUsage, "mode", "stolen") - val combined = register(CpuUsage, "mode", "combined") - } - - class MemoryInstruments(tags: TagSet) extends InstrumentGroup(tags) { - val used = register(MemoryUsed) - val free = register(MemoryFree) - val total = register(MemoryTotal) - } - - class SwapInstruments(tags: TagSet) extends InstrumentGroup(tags) { - val used = register(SwapUsed) - val free = register(SwapFree) - val total = register(SwapTotal) - } - - class LoadAverageInstruments(tags: TagSet) extends InstrumentGroup(tags) { - val oneMinute = register(LoadAverage, "period", "1m") - val fiveMinutes = register(LoadAverage, "period", "5m") - val fifteenMinutes = register(LoadAverage, "period", "15m") - } - - class StorageMountInstruments(tags: TagSet) extends InstrumentGroup(tags) { - // It is ok to use mutable, not-synchronized collections here because they will only be accessed from one Thread - // at a time and that Thread is always the same Thread. - private val _mountsCache = mutable.Map.empty[String, MountInstruments] - - def mountInstruments(mountName: String): MountInstruments = - _mountsCache.getOrElseUpdate(mountName, { - val mount = TagSet.of("mount", mountName) - - MountInstruments ( - register(FileSystemMountSpaceUsed, mount), - register(FileSystemMountSpaceFree, mount), - register(FileSystemMountSpaceTotal, mount) - ) - }) - } - - object StorageMountInstruments { - case class MountInstruments ( - used: Gauge, - free: Gauge, - total: Gauge - ) - } - - class StorageDeviceInstruments(tags: TagSet) extends InstrumentGroup(tags) { - // It is ok to use mutable, not-synchronized collections here because they will only be accessed from one Thread - // at a time and that Thread is always the same Thread. - private val _deviceInstrumentsCache = mutable.Map.empty[String, DeviceInstruments] - - def deviceInstruments(deviceName: String): DeviceInstruments = - _deviceInstrumentsCache.getOrElseUpdate(deviceName, { - val device = TagSet.of("device", deviceName) - - DeviceInstruments ( - DiffCounter(register(StorageDeviceReadOps, device)), - DiffCounter(register(StorageDeviceRead, device)), - DiffCounter(register(StorageDeviceWriteOps, device)), - DiffCounter(register(StorageDeviceWrite, device)) - ) - }) - } - - object StorageDeviceInstruments { - case class DeviceInstruments ( - reads: DiffCounter, - readBytes: DiffCounter, - writes: DiffCounter, - writeBytes: DiffCounter, - ) - } - - class NetworkActivityInstruments(tags: TagSet) extends InstrumentGroup(tags) { - // It is ok to use mutable, not-synchronized collections here because they will only be accessed from one Thread - // at a time and that Thread is always the same Thread. - private val _interfaceCache = mutable.Map.empty[String, InterfaceInstruments] - - def interfaceInstruments(interfaceName: String): InterfaceInstruments = - _interfaceCache.getOrElseUpdate(interfaceName, { - val interface = TagSet.of("interface", interfaceName) - val success = TagSet.of("state", "success") - val error = TagSet.of("state", "error") - - InterfaceInstruments( - DiffCounter(register(NetworkDataRead, interface)), - DiffCounter(register(NetworkPacketsRead, interface.withTags(success))), - DiffCounter(register(NetworkPacketsRead, interface.withTags(error))), - DiffCounter(register(NetworkDataWrite, interface)), - DiffCounter(register(NetworkPacketsWrite, interface.withTags(success))), - DiffCounter(register(NetworkPacketsWrite, interface.withTags(error))) - ) - }) - } - - object NetworkActivityInstruments { - case class InterfaceInstruments ( - receivedBytes: DiffCounter, - receivedPackets: DiffCounter, - receiveErrorPackets: DiffCounter, - sentBytes: DiffCounter, - sentPackets: DiffCounter, - sendErrorPackets: DiffCounter - ) - } - - /** - * A modified Counter that keeps track of a monotonically increasing value and only records the difference between - * the current and previous value on the target counter. - */ - case class DiffCounter(counter: Counter) { - private var _previous = 0L - - def diff(current: Long): Unit = { - if(_previous > 0L) { - val delta = current - _previous - if(delta > 0) - counter.increment(delta) - - } - - _previous = current - } - } -} diff --git a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala b/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala deleted file mode 100644 index 6719a72..0000000 --- a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala +++ /dev/null @@ -1,216 +0,0 @@ -package kamon -package instrumentation -package system -package host - -import java.util.concurrent.TimeUnit - -import com.typesafe.config.Config -import kamon.instrumentation.system.host.HostMetrics._ -import kamon.module.{Module, ModuleFactory} -import kamon.tag.TagSet -import kamon.util.Filter -import oshi.SystemInfo -import oshi.hardware.CentralProcessor.TickType - -import scala.concurrent.{ExecutionContext, Future} - -/** - * Collects CPU, Memory, Swap, Storage and Network metrics. The metrics collection is split into two groups: frequent - * and infrequent collector; the frequent collector records metrics that are highly volatile and do not accumulate over - * time, like the CPU usage, while the infrequent collector focuses on metrics that can be updated less frequently like - * swap and memory usage and cumulative metrics like network and storage usage. - */ -class HostMetricsCollector(ec: ExecutionContext, initialConfig: Config) extends Module { - @volatile private var _settings: HostMetricsCollector.Settings = readSettings(initialConfig) - - private val _frequentCollector = new FrequentCollectionTask - private val _infrequentCollector = new InfrequentCollectionTask - private val _fcSchedule = Kamon.scheduler().scheduleAtFixedRate(scheduleOnModuleEC(_frequentCollector), 1, 1, TimeUnit.SECONDS) - private val _ifcSchedule = Kamon.scheduler().scheduleAtFixedRate(scheduleOnModuleEC(_infrequentCollector), 1, 10, TimeUnit.SECONDS) - - override def stop(): Unit = { - _fcSchedule.cancel(false) - _ifcSchedule.cancel(false) - _frequentCollector.cleanup() - _infrequentCollector.cleanup() - } - - override def reconfigure(newConfig: Config): Unit = - _settings = readSettings(newConfig) - - private def readSettings(config: Config): HostMetricsCollector.Settings = - HostMetricsCollector.Settings( - Filter.from(config.getConfig("network.tracked-interfaces")), - Filter.from(config.getConfig("storage.tracked-mount-types")) - ) - - private def scheduleOnModuleEC(task: CollectionTask): Runnable = new Runnable { - override def run(): Unit = - task.schedule(ec) - } - - trait CollectionTask { - def schedule(ec: ExecutionContext): Unit - def cleanup(): Unit - } - - private class FrequentCollectionTask extends CollectionTask { - private val _defaultTags = TagSet.of("component", "host") - private val _systemInfo = new SystemInfo() - private val _hal = _systemInfo.getHardware() - private val _cpuInstruments = new CpuInstruments(_defaultTags) - private var _prevCpuLoadTicks: Array[Long] = Array.ofDim(0) - - def schedule(ec: ExecutionContext): Unit = { - Future { - recordCpuUsage() - }(ec) - } - - def cleanup(): Unit = { - _cpuInstruments.remove() - } - - private def recordCpuUsage(): Unit = { - if(_prevCpuLoadTicks.length > 0) { - val previousTicks = _prevCpuLoadTicks - val currentTicks = _hal.getProcessor().getSystemCpuLoadTicks() - - val user = ticksDiff(previousTicks, currentTicks, TickType.USER) - val nice = ticksDiff(previousTicks, currentTicks, TickType.NICE) - val system = ticksDiff(previousTicks, currentTicks, TickType.SYSTEM) - val idle = ticksDiff(previousTicks, currentTicks, TickType.IDLE) - val iowait = ticksDiff(previousTicks, currentTicks, TickType.IOWAIT) - val irq = ticksDiff(previousTicks, currentTicks, TickType.IRQ) - val softirq = ticksDiff(previousTicks, currentTicks, TickType.SOFTIRQ) - val steal = ticksDiff(previousTicks, currentTicks, TickType.STEAL) - val total = user + nice + system + idle + iowait +irq + softirq + steal - def toPercent(value: Long): Long = ((100D * value.toDouble) / total.toDouble).toLong - - _cpuInstruments.user.record(toPercent(user)) - _cpuInstruments.system.record(toPercent(system)) - _cpuInstruments.iowait.record(toPercent(iowait)) - _cpuInstruments.idle.record(toPercent(idle)) - _cpuInstruments.stolen.record(toPercent(steal)) - _cpuInstruments.combined.record(toPercent(user + system + nice + iowait)) - _prevCpuLoadTicks = currentTicks - - } else { - _prevCpuLoadTicks = _hal.getProcessor().getSystemCpuLoadTicks() - } - - } - - private def ticksDiff(previous: Array[Long], current: Array[Long], tickType: TickType): Long = - math.max(current(tickType.getIndex) - previous(tickType.getIndex), 0L) - - } - - private class InfrequentCollectionTask extends CollectionTask { - private val _defaultTags = TagSet.of("component", "host") - private val _systemInfo = new SystemInfo() - private val _hal = _systemInfo.getHardware() - private val _os = _systemInfo.getOperatingSystem - - private val _memoryInstruments = new MemoryInstruments(_defaultTags) - private val _swapInstruments = new SwapInstruments(_defaultTags) - private val _loadAverageInstruments = new LoadAverageInstruments(_defaultTags) - private val _fileSystemUsageInstruments = new StorageMountInstruments(_defaultTags) - private val _fileSystemActivityInstruments = new StorageDeviceInstruments(_defaultTags) - private val _networkActivityInstruments = new NetworkActivityInstruments(_defaultTags) - - def schedule(ec: ExecutionContext): Unit = { - Future { - recordMemoryUsage() - recordLoadAverage() - recordStorageUsage() - recordStorageActivity() - recordNetworkActivity() - }(ec) - } - - def cleanup(): Unit = { - _memoryInstruments.remove() - _swapInstruments.remove() - _loadAverageInstruments.remove() - _fileSystemUsageInstruments.remove() - _fileSystemActivityInstruments.remove() - _networkActivityInstruments.remove() - } - - private def recordMemoryUsage(): Unit = { - val memory = _hal.getMemory - _memoryInstruments.total.update(memory.getTotal()) - _memoryInstruments.free.update(memory.getAvailable()) - _memoryInstruments.used.update(memory.getTotal() - memory.getAvailable()) - - _swapInstruments.total.update(memory.getSwapTotal()) - _swapInstruments.free.update(memory.getSwapUsed()) - _swapInstruments.used.update(memory.getSwapTotal() - memory.getSwapUsed()) - } - - private def recordLoadAverage(): Unit = { - val loadAverage = _hal.getProcessor.getSystemLoadAverage(3) - if(loadAverage(0) >= 0D) _loadAverageInstruments.oneMinute.update(loadAverage(0)) - if(loadAverage(1) >= 0D) _loadAverageInstruments.fiveMinutes.update(loadAverage(1)) - if(loadAverage(2) >= 0D) _loadAverageInstruments.fifteenMinutes.update(loadAverage(2)) - } - - private def recordStorageUsage(): Unit = { - val fileStores = _os.getFileSystem().getFileStores - - fileStores.foreach(fs => { - if(_settings.trackedMounts.accept(fs.getType)) { - val mountInstruments = _fileSystemUsageInstruments.mountInstruments(fs.getMount) - mountInstruments.free.update(fs.getUsableSpace) - mountInstruments.total.update(fs.getTotalSpace) - mountInstruments.used.update(fs.getTotalSpace - fs.getUsableSpace) - } - }) - } - - private def recordStorageActivity(): Unit = { - val devices = _hal.getDiskStores - - devices.foreach(device => { - if(device.getPartitions.nonEmpty) { - val deviceInstruments = _fileSystemActivityInstruments.deviceInstruments(device.getName) - deviceInstruments.reads.diff(device.getReads) - deviceInstruments.writes.diff(device.getWrites) - deviceInstruments.readBytes.diff(device.getReadBytes) - deviceInstruments.writeBytes.diff(device.getWriteBytes) - } - }) - } - - private def recordNetworkActivity(): Unit = { - val interfaces = _hal.getNetworkIFs() - - interfaces.foreach(interface => { - if(_settings.trackedInterfaces.accept(interface.getName)) { - val interfaceInstruments = _networkActivityInstruments.interfaceInstruments(interface.getName) - interfaceInstruments.receivedBytes.diff(interface.getBytesRecv) - interfaceInstruments.sentBytes.diff(interface.getBytesSent) - interfaceInstruments.sentPackets.diff(interface.getPacketsSent) - interfaceInstruments.receivedPackets.diff(interface.getPacketsRecv) - interfaceInstruments.sendErrorPackets.diff(interface.getOutErrors) - interfaceInstruments.receiveErrorPackets.diff(interface.getInErrors) - } - }) - } - } -} - -object HostMetricsCollector { - - class Factory extends ModuleFactory { - override def create(settings: ModuleFactory.Settings): Module = - new HostMetricsCollector(settings.executionContext, settings.config) - } - - case class Settings ( - trackedInterfaces: Filter, - trackedMounts: Filter - ) -} diff --git a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala b/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala deleted file mode 100644 index dcad1b2..0000000 --- a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala +++ /dev/null @@ -1,134 +0,0 @@ -package kamon.instrumentation.system.jvm - -import kamon.Kamon -import kamon.instrumentation.system.jvm.JvmMetrics.MemoryUsageInstruments.MemoryRegionInstruments -import kamon.instrumentation.system.jvm.JvmMetricsCollector.{Collector, MemoryPool} -import kamon.metric.{Gauge, Histogram, InstrumentGroup, MeasurementUnit} -import kamon.tag.TagSet - -import scala.collection.mutable - -object JvmMetrics { - - val GC = Kamon.histogram ( - name = "jvm.gc", - description = "Tracks the distribution of GC events duration", - unit = MeasurementUnit.time.milliseconds - ) - - val GcPromotion = Kamon.histogram ( - name = "jvm.gc.promotion", - description = "Tracks the distribution of promoted bytes to the old generation regions after a GC", - unit = MeasurementUnit.information.bytes - ) - - val MemoryUsed = Kamon.histogram ( - name = "jvm.memory.used", - description = "Samples the used space in a memory region", - unit = MeasurementUnit.information.bytes - ) - - val MemoryFree = Kamon.histogram ( - name = "jvm.memory.free", - description = "Samples the free space in a memory region", - unit = MeasurementUnit.information.bytes - ) - - val MemoryCommitted = Kamon.gauge ( - name = "jvm.memory.committed", - description = "Tracks the committed space in a memory region", - unit = MeasurementUnit.information.bytes - ) - - val MemoryMax = Kamon.gauge ( - name = "jvm.memory.max", - description = "Tracks the max space in a memory region", - unit = MeasurementUnit.information.bytes - ) - - val MemoryPoolUsed = Kamon.histogram ( - name = "jvm.memory.pool.used", - description = "Samples the used space in a memory pool", - unit = MeasurementUnit.information.bytes - ) - - val MemoryPoolFree = Kamon.histogram ( - name = "jvm.memory.pool.free", - description = "Samples the free space in a memory pool", - unit = MeasurementUnit.information.bytes - ) - - val MemoryPoolCommitted = Kamon.gauge ( - name = "jvm.memory.pool.committed", - description = "Tracks the committed space in a memory pool", - unit = MeasurementUnit.information.bytes - ) - - val MemoryPoolMax = Kamon.gauge ( - name = "jvm.memory.pool.max", - description = "Tracks the max space in a memory pool", - unit = MeasurementUnit.information.bytes - ) - - val MemoryAllocation = Kamon.counter ( - name = "jvm.memory.allocation", - description = "Tracks the number amount of bytes allocated", - unit = MeasurementUnit.information.bytes - ) - - class GarbageCollectionInstruments(tags: TagSet) extends InstrumentGroup(tags) { - private val _collectorCache = mutable.Map.empty[String, Histogram] - - val allocation = register(MemoryAllocation) - val promotionToOld = register(GcPromotion, "space", "old") - - def garbageCollectionTime(collector: Collector): Histogram = - _collectorCache.getOrElseUpdate(collector.alias, { - val collectorTags = TagSet.builder() - .add("collector", collector.alias) - .add("generation", collector.generation.toString) - .build() - - register(GC, collectorTags) - }) - } - - class MemoryUsageInstruments(tags: TagSet) extends InstrumentGroup(tags) { - private val _memoryRegionsCache = mutable.Map.empty[String, MemoryRegionInstruments] - private val _memoryPoolsCache = mutable.Map.empty[String, MemoryRegionInstruments] - - def regionInstruments(regionName: String): MemoryRegionInstruments = - _memoryRegionsCache.getOrElseUpdate(regionName, { - val region = TagSet.of("region", regionName) - - MemoryRegionInstruments ( - register(MemoryUsed, region), - register(MemoryFree, region), - register(MemoryCommitted, region), - register(MemoryMax, region) - ) - }) - - def poolInstruments(pool: MemoryPool): MemoryRegionInstruments = - _memoryPoolsCache.getOrElseUpdate(pool.alias, { - val region = TagSet.of("pool", pool.alias) - - MemoryRegionInstruments ( - register(MemoryPoolUsed, region), - register(MemoryPoolFree, region), - register(MemoryPoolCommitted, region), - register(MemoryPoolMax, region) - ) - }) - } - - object MemoryUsageInstruments { - - case class MemoryRegionInstruments ( - used: Histogram, - free: Histogram, - committed: Gauge, - max: Gauge - ) - } -} diff --git a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala b/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala deleted file mode 100644 index 8aec3b2..0000000 --- a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala +++ /dev/null @@ -1,224 +0,0 @@ -package kamon.instrumentation.system.jvm - -import java.lang.management.{ManagementFactory, MemoryUsage} -import java.util.concurrent.TimeUnit - -import com.sun.management.GarbageCollectionNotificationInfo -import com.sun.management.GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION -import com.typesafe.config.Config -import javax.management.openmbean.CompositeData -import javax.management.{Notification, NotificationEmitter, NotificationListener} -import kamon.Kamon -import kamon.instrumentation.system.jvm.JvmMetrics.{GarbageCollectionInstruments, MemoryUsageInstruments} -import kamon.instrumentation.system.jvm.JvmMetricsCollector.{Collector, MemoryPool} -import kamon.module.{Module, ModuleFactory} -import kamon.tag.TagSet - -import scala.collection.JavaConverters.{collectionAsScalaIterableConverter, mapAsScalaMapConverter} -import scala.collection.concurrent.TrieMap -import scala.concurrent.ExecutionContext -import scala.util.matching.Regex - -class JvmMetricsCollector(ec: ExecutionContext, initialConfig: Config) extends Module { - private val _defaultTags = TagSet.of("component", "jvm") - private val _gcListener = registerGcListener(_defaultTags) - private val _memoryUsageInstruments = new MemoryUsageInstruments(_defaultTags) - private val _memoryUsageTask = new MemoryUsageCollectorTask(_memoryUsageInstruments) - private val _memoryUsageSchedule = Kamon.scheduler().scheduleAtFixedRate(_memoryUsageTask, 1, 10, TimeUnit.SECONDS) - - override def stop(): Unit = { - _memoryUsageSchedule.cancel(false) - deregisterGcListener() - } - - override def reconfigure(newConfig: Config): Unit = {} - - private def registerGcListener(defaultTags: TagSet): NotificationListener = { - val gcInstruments = new GarbageCollectionInstruments(defaultTags) - val gcListener = new GcNotificationListener(gcInstruments) - - ManagementFactory.getGarbageCollectorMXBeans().asScala.foreach(gcBean => { - if(gcBean.isInstanceOf[NotificationEmitter]) - gcBean.asInstanceOf[NotificationEmitter].addNotificationListener(gcListener, null, null) - }) - - gcListener - } - - private def deregisterGcListener(): Unit = { - ManagementFactory.getGarbageCollectorMXBeans().asScala.foreach(gcBean => { - if(gcBean.isInstanceOf[NotificationEmitter]) { - gcBean.asInstanceOf[NotificationEmitter].removeNotificationListener(_gcListener) - } - }) - } - - - - - class GcNotificationListener(val gcInstruments: GarbageCollectionInstruments) extends NotificationListener { - private val _previousUsageAfterGc = TrieMap.empty[String, MemoryUsage] - - override def handleNotification(notification: Notification, handback: Any): Unit = { - if(notification.getType() == GARBAGE_COLLECTION_NOTIFICATION) { - val compositeData = notification.getUserData.asInstanceOf[CompositeData] - val info = GarbageCollectionNotificationInfo.from(compositeData) - val collector = Collector.find(info.getGcName) - - gcInstruments.garbageCollectionTime(collector).record(info.getGcInfo.getDuration) - - val usageBeforeGc = info.getGcInfo.getMemoryUsageBeforeGc.asScala - val usageAfterGc = info.getGcInfo.getMemoryUsageAfterGc.asScala - - usageBeforeGc.foreach { - case (regionName, regionUsageBeforeGc) => - val region = MemoryPool.find(regionName) - - // We assume that if the old generation grew during this GC event then some data was promoted to it and will - // record it as promotion to the old generation. - // - if(region.usage == MemoryPool.Usage.OldGeneration) { - val regionUsageAfterGc = usageAfterGc(regionName) - val diff = regionUsageAfterGc.getUsed - regionUsageBeforeGc.getUsed - - if(diff > 0) - gcInstruments.promotionToOld.record(diff) - - } - - // We will record the growth of Eden spaces in between GC events as the allocation rate. - if(region.usage == MemoryPool.Usage.Eden) { - _previousUsageAfterGc.get(regionName).fold({ - - // We wont have the previous GC value the first time an Eden region is processed so we can assume - // that all used space before GC was just allocation. - gcInstruments.allocation.increment(regionUsageBeforeGc.getUsed): Unit - - })(previousUsageAfterGc => { - val currentUsageBeforeGc = regionUsageBeforeGc - val allocated = currentUsageBeforeGc.getUsed - previousUsageAfterGc.getUsed - if(allocated > 0) - gcInstruments.allocation.increment(allocated) - }) - - _previousUsageAfterGc.put(regionName, usageAfterGc(regionName)) - } - } - } - } - } - - class MemoryUsageCollectorTask(memoryUsageInstruments: MemoryUsageInstruments) extends Runnable { - private val _heapUsage = memoryUsageInstruments.regionInstruments("heap") - private val _nonHeapUsage = memoryUsageInstruments.regionInstruments("non-heap") - - override def run(): Unit = { - - val currentHeapUsage = ManagementFactory.getMemoryMXBean.getHeapMemoryUsage - val freeHeap = Math.max(0L, currentHeapUsage.getMax - currentHeapUsage.getUsed) - _heapUsage.free.record(freeHeap) - _heapUsage.used.record(currentHeapUsage.getUsed) - _heapUsage.max.update(currentHeapUsage.getMax) - _heapUsage.committed.update(currentHeapUsage.getCommitted) - - val currentNonHeapUsage = ManagementFactory.getMemoryMXBean.getNonHeapMemoryUsage - val freeNonHeap = Math.max(0L, currentNonHeapUsage.getMax - currentNonHeapUsage.getUsed) - _nonHeapUsage.free.record(freeNonHeap) - _nonHeapUsage.used.record(currentNonHeapUsage.getUsed) - _nonHeapUsage.max.update(currentNonHeapUsage.getMax) - _nonHeapUsage.committed.update(currentNonHeapUsage.getCommitted) - - ManagementFactory.getMemoryPoolMXBeans.asScala.foreach(memoryBean => { - val poolInstruments = memoryUsageInstruments.poolInstruments(MemoryPool.find(memoryBean.getName)) - val memoryUsage = memoryBean.getUsage - val freeMemory = Math.max(0L, memoryUsage.getMax - memoryUsage.getUsed) - - poolInstruments.free.record(freeMemory) - poolInstruments.used.record(memoryUsage.getUsed) - poolInstruments.max.update(memoryUsage.getMax) - poolInstruments.committed.update(memoryUsage.getCommitted) - }) - } - } -} - -object JvmMetricsCollector { - - class Factory extends ModuleFactory { - override def create(settings: ModuleFactory.Settings): Module = - new JvmMetricsCollector(settings.executionContext, settings.config) - } - - case class Collector ( - name: String, - alias: String, - generation: Collector.Generation - ) - - object Collector { - - sealed trait Generation - object Generation { - case object Young extends Generation { override def toString: String = "young" } - case object Old extends Generation { override def toString: String = "old" } - case object Unknown extends Generation { override def toString: String = "unknown" } - } - - def find(collectorName: String): Collector = - _collectorMappings.get(collectorName).getOrElse ( - Collector(collectorName, sanitizeCollectorName(collectorName), Collector.Generation.Unknown) - ) - - private val _collectorMappings: Map[String, Collector] = Map ( - "Copy" -> Collector("Copy", "copy", Generation.Young), - "ParNew" -> Collector("ParNew", "par-new", Generation.Young), - "MarkSweepCompact" -> Collector("MarkSweepCompact", "mark-sweep-compact", Generation.Old), - "ConcurrentMarkSweep" -> Collector("ConcurrentMarkSweep", "concurrent-mark-sweep", Generation.Old), - "PS Scavenge" -> Collector("PS Scavenge", "ps-scavenge", Generation.Young), - "PS MarkSweep" -> Collector("PS MarkSweep", "ps-mark-sweep", Generation.Old), - "G1 Young Generation" -> Collector("G1 Young Generation", "g1-young", Generation.Young), - "G1 Old Generation" -> Collector("G1 Old Generation", "g1-old", Generation.Old) - ) - - private def sanitizeCollectorName(name: String): String = - name.replaceAll("""[^\w]""", "-").toLowerCase - } - - case class MemoryPool ( - name: String, - alias: String, - usage: MemoryPool.Usage - ) - - object MemoryPool { - - sealed trait Usage - object Usage { - case object Eden extends Usage - case object YoungGeneration extends Usage - case object OldGeneration extends Usage - case object CodeCache extends Usage - case object Metaspace extends Usage - case object Unknown extends Usage - } - - def find(poolName: String): MemoryPool = - _memoryRegionMappings.get(poolName).getOrElse { - MemoryPool(poolName, sanitize(poolName), if(poolName.endsWith("Eden Space")) Usage.Eden else Usage.Unknown) - } - - private val _memoryRegionMappings: Map[String, MemoryPool] = Map ( - "Metaspace" -> MemoryPool("Metaspace", "metaspace", Usage.Metaspace), - "Code Cache" -> MemoryPool("Code Cache", "code-cache", Usage.CodeCache), - "Compressed Class Space" -> MemoryPool("Compressed Class Space", "compressed-class-space", Usage.CodeCache), - "PS Eden Space" -> MemoryPool("PS Eden Space", "eden", Usage.Eden), - "PS Survivor Space" -> MemoryPool("PS Survivor Space", "survivor", Usage.YoungGeneration), - "PS Old Gen" -> MemoryPool("PS Old Gen", "old", Usage.OldGeneration), - ) - - private val _invalidChars: Regex = """[^a-z0-9]""".r - - def sanitize(name: String): String = - _invalidChars.replaceAllIn(name.toLowerCase, "-") - } -} diff --git a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetrics.scala b/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetrics.scala deleted file mode 100644 index 531c355..0000000 --- a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetrics.scala +++ /dev/null @@ -1,41 +0,0 @@ -package kamon.instrumentation.system.process - -import kamon.Kamon -import kamon.metric.{InstrumentGroup, MeasurementUnit} -import kamon.tag.TagSet - -object ProcessMetrics { - - val ProcessCpu = Kamon.histogram( - name = "process.cpu", - description = "Samples the Process CPU usage", - unit = MeasurementUnit.percentage - ) - - val ULimits = Kamon.gauge ( - name = "process.ulimit", - description = "Tracks the value of resources limits for the process" - ) - - val ULimitsUsed = Kamon.histogram ( - name = "process.ulimit.used", - description = "Samples the current resource utilization" - ) - - val Hiccups = Kamon.timer ( - name = "process.hiccup", - description = "Tracks the process hiccups generated by either garbage collection or OS noise" - ) - - - class ProcessInstruments(tags: TagSet) extends InstrumentGroup(tags) { - val user = register(ProcessCpu, "mode", "user") - val system = register(ProcessCpu, "mode", "system") - val combined = register(ProcessCpu, "mode", "combined") - - val openFilesLimit = register(ULimits, "limit", "file-descriptors") - val openFilesCurrent = register(ULimitsUsed, "limit", "file-descriptors") - - val hiccups = register(Hiccups) - } -} diff --git a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala b/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala deleted file mode 100644 index e4d1964..0000000 --- a/kamon-host-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala +++ /dev/null @@ -1,162 +0,0 @@ -package kamon.instrumentation.system.process - -import java.time.Duration -import java.util.concurrent.{Executors, TimeUnit} - -import com.sun.jna.Platform -import com.typesafe.config.Config -import kamon.instrumentation.system.process.ProcessMetrics.ProcessInstruments -import kamon.metric.Timer -import kamon.module.{Module, ModuleFactory} -import kamon.tag.TagSet -import kamon.Kamon -import oshi.SystemInfo -import oshi.util.{FileUtil, ParseUtil} - -import scala.collection.JavaConverters.iterableAsScalaIterableConverter -import scala.concurrent.{ExecutionContext, Future} -import scala.util.Try - -class ProcessMetricsCollector(ec: ExecutionContext, initialConfig: Config) extends Module { - private val _defaultTags = TagSet.of("component", "process") - private val _processCpuInstruments = new ProcessInstruments(_defaultTags) - private val _collectionTask = new MetricsCollectionTask - private val _collectionSchedule = Kamon.scheduler().scheduleAtFixedRate(scheduleOnModuleEC(_collectionTask), 1, 1, TimeUnit.SECONDS) - private val _hiccupMonitor = startHiccupMonitor() - - override def stop(): Unit = { - _hiccupMonitor.terminate() - _collectionSchedule.cancel(false) - _collectionTask.cleanup() - } - - override def reconfigure(newConfig: Config): Unit = { - _hiccupMonitor.updateInterval(newConfig.getDuration("hiccup-monitor-interval")) - } - - private def scheduleOnModuleEC(task: MetricsCollectionTask): Runnable = new Runnable { - override def run(): Unit = - task.schedule(ec) - } - - private def startHiccupMonitor(): HiccupMonitor = { - val interval = initialConfig.getDuration("hiccup-monitor-interval") - val monitorThread = new HiccupMonitor(_processCpuInstruments.hiccups, interval) - monitorThread.setDaemon(true) - monitorThread.setName("hiccup-monitor") - monitorThread.start() - monitorThread - } - - private class MetricsCollectionTask { - private val _systemInfo = new SystemInfo() - private val _hal = _systemInfo.getHardware() - private val _os = _systemInfo.getOperatingSystem - private val _pid = _os.getProcessId() - private val _processorCount = _hal.getProcessor.getLogicalProcessorCount().toDouble - private var _previousProcessCpuTime: Array[Long] = Array.empty[Long] - - def schedule(ec: ExecutionContext): Unit = { - Future { - recordProcessCpu() - recordProcessULimits() - }(ec) - } - - def cleanup(): Unit = { - _processCpuInstruments.remove() - } - - private def recordProcessCpu(): Unit = { - val process = _os.getProcess(_pid) - val previous = _previousProcessCpuTime - val current = Array ( - process.getKernelTime(), - process.getUserTime(), - process.getUpTime() - ) - - if(previous.nonEmpty) { - val kernelTime = math.max(0L, current(0) - previous(0)) - val userTime = math.max(0L, current(1) - previous(1)) - val totalTime = math.max(0L, current(2) - previous(2)) - def toPercent(value: Long): Long = { - if(totalTime > 0) ((100D * value.toDouble) / totalTime.toDouble / _processorCount).toLong else 0 - } - - _processCpuInstruments.user.record(toPercent(userTime)) - _processCpuInstruments.system.record(toPercent(kernelTime)) - _processCpuInstruments.combined.record(toPercent(userTime + kernelTime)) - } - - _previousProcessCpuTime = current - } - - private def recordProcessULimits(): Unit = { - val process = _os.getProcess(_pid) - _processCpuInstruments.openFilesCurrent.record(process.getOpenFiles()) - - Try { - if (Platform.isLinux()) { - val allLimits = FileUtil.readFile(String.format(s"/proc/${_pid}/limits")) - allLimits.asScala.find(_.toLowerCase().startsWith("max open files")).map { openFilesLimitLine => - val openFilesLimit = ParseUtil.getNthIntValue(openFilesLimitLine, 1) - _processCpuInstruments.openFilesLimit.update(openFilesLimit) - } - } - } - } - } - - final class HiccupMonitor(hiccupTimeMetric: Timer, duration: Duration) extends Thread { - @volatile private var _hiccupNanos = duration.toNanos - @volatile private var _doRun = true - - override def run(): Unit = { - var shortestObservedDelta = Long.MaxValue - - while (_doRun) { - val hiccupTime = hic(_hiccupNanos) - record(hiccupTime, _hiccupNanos) - } - - def hic(resolution: Long): Long = { - val start = System.nanoTime - TimeUnit.NANOSECONDS.sleep(resolution) - val delta = System.nanoTime() - start - if (delta < shortestObservedDelta) shortestObservedDelta = delta - delta - shortestObservedDelta - } - } - - /** - * We'll need fill in missing measurements as delayed - */ - def record(value: Long, expectedIntervalBetweenValueSamples: Long): Unit = { - hiccupTimeMetric.record(value) - - if (expectedIntervalBetweenValueSamples > 0) { - var missingValue = value - expectedIntervalBetweenValueSamples - - while (missingValue >= expectedIntervalBetweenValueSamples) { - hiccupTimeMetric.record(missingValue) - missingValue -= expectedIntervalBetweenValueSamples - } - } - } - - def terminate():Unit = - _doRun = false - - def updateInterval(duration: Duration): Unit = - _hiccupNanos = duration.toNanos - } -} - -object ProcessMetricsCollector { - - class Factory extends ModuleFactory { - override def create(settings: ModuleFactory.Settings): Module = - new ProcessMetricsCollector(settings.executionContext, settings.config) - } -} \ No newline at end of file diff --git a/kamon-host-metrics/src/test/resources/logback.xml b/kamon-host-metrics/src/test/resources/logback.xml deleted file mode 100644 index e15105b..0000000 --- a/kamon-host-metrics/src/test/resources/logback.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - System.out - - %date{ISO8601} %-5level [%thread] %X{traceToken} %X{kamonTraceID} %X{kamonSpanID} %logger %X{} - %msg%n - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/kamon-host-metrics/src/test/scala/kamon/instrumentation/system/host/Test.scala b/kamon-host-metrics/src/test/scala/kamon/instrumentation/system/host/Test.scala deleted file mode 100644 index 67fedb8..0000000 --- a/kamon-host-metrics/src/test/scala/kamon/instrumentation/system/host/Test.scala +++ /dev/null @@ -1,33 +0,0 @@ -package kamon.instrumentation.system.host - -import java.util.UUID -import java.util.concurrent.{Executors, ThreadLocalRandom} - -import kamon.Kamon - -object Test extends App { - Kamon.loadModules() - - - val pool = Executors.newWorkStealingPool(32) - - def executeShit(): Unit = { - pool.submit(new Runnable { - override def run(): Unit = { - while(true) { - ThreadLocalRandom.current().nextBytes(Array.ofDim(32)) - } - } - }) - } - - executeShit() -// executeShit() -// executeShit() -// executeShit() -// executeShit() -// executeShit() -// executeShit() -// executeShit() - -} diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index 59d9a19..9a293a5 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -36,7 +36,6 @@ kamon.modules { name = "Host Metrics" description = "Periodically collects metrics on CPU, Memory, Swap, Network and Storage usage" factory = "kamon.instrumentation.system.host.HostMetricsCollector$Factory" - config-path = "kamon.instrumentation.system.host" } process-metrics { @@ -44,7 +43,6 @@ kamon.modules { name = "Process Metrics" description = "Collects Process CPU and Ulimit metrics from the JVM process" factory = "kamon.instrumentation.system.process.ProcessMetricsCollector$Factory" - config-path = "kamon.instrumentation.system.process" } jvm-metrics { @@ -52,6 +50,5 @@ kamon.modules { name = "JVM Metrics" description = "Collects CPU, Garbage Collection, Memory, Class Loading and Threads metrics from the local JVM" factory = "kamon.instrumentation.system.jvm.JvmMetricsCollector$Factory" - config-path = "kamon.instrumentation.system.jvm" } } \ No newline at end of file diff --git a/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala b/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala index e05d879..756500d 100644 --- a/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala +++ b/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala @@ -195,7 +195,7 @@ object HostMetrics { reads: DiffCounter, readBytes: DiffCounter, writes: DiffCounter, - writeBytes: DiffCounter, + writeBytes: DiffCounter ) } diff --git a/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala b/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala index 6719a72..2e85d88 100644 --- a/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala +++ b/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala @@ -21,8 +21,9 @@ import scala.concurrent.{ExecutionContext, Future} * time, like the CPU usage, while the infrequent collector focuses on metrics that can be updated less frequently like * swap and memory usage and cumulative metrics like network and storage usage. */ -class HostMetricsCollector(ec: ExecutionContext, initialConfig: Config) extends Module { - @volatile private var _settings: HostMetricsCollector.Settings = readSettings(initialConfig) +class HostMetricsCollector(ec: ExecutionContext) extends Module { + private val _configPath = "kamon.instrumentation.system.host" + @volatile private var _settings: HostMetricsCollector.Settings = readSettings(Kamon.config()) private val _frequentCollector = new FrequentCollectionTask private val _infrequentCollector = new InfrequentCollectionTask @@ -39,11 +40,14 @@ class HostMetricsCollector(ec: ExecutionContext, initialConfig: Config) extends override def reconfigure(newConfig: Config): Unit = _settings = readSettings(newConfig) - private def readSettings(config: Config): HostMetricsCollector.Settings = + private def readSettings(config: Config): HostMetricsCollector.Settings = { + val hostConfig = config.getConfig(_configPath) + HostMetricsCollector.Settings( - Filter.from(config.getConfig("network.tracked-interfaces")), - Filter.from(config.getConfig("storage.tracked-mount-types")) + Filter.from(hostConfig.getConfig("network.tracked-interfaces")), + Filter.from(hostConfig.getConfig("storage.tracked-mount-types")) ) + } private def scheduleOnModuleEC(task: CollectionTask): Runnable = new Runnable { override def run(): Unit = @@ -99,7 +103,6 @@ class HostMetricsCollector(ec: ExecutionContext, initialConfig: Config) extends } else { _prevCpuLoadTicks = _hal.getProcessor().getSystemCpuLoadTicks() } - } private def ticksDiff(previous: Array[Long], current: Array[Long], tickType: TickType): Long = @@ -206,7 +209,7 @@ object HostMetricsCollector { class Factory extends ModuleFactory { override def create(settings: ModuleFactory.Settings): Module = - new HostMetricsCollector(settings.executionContext, settings.config) + new HostMetricsCollector(settings.executionContext) } case class Settings ( diff --git a/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala b/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala index 8aec3b2..bebc503 100644 --- a/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala +++ b/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala @@ -19,7 +19,7 @@ import scala.collection.concurrent.TrieMap import scala.concurrent.ExecutionContext import scala.util.matching.Regex -class JvmMetricsCollector(ec: ExecutionContext, initialConfig: Config) extends Module { +class JvmMetricsCollector(ec: ExecutionContext) extends Module { private val _defaultTags = TagSet.of("component", "jvm") private val _gcListener = registerGcListener(_defaultTags) private val _memoryUsageInstruments = new MemoryUsageInstruments(_defaultTags) @@ -146,7 +146,7 @@ object JvmMetricsCollector { class Factory extends ModuleFactory { override def create(settings: ModuleFactory.Settings): Module = - new JvmMetricsCollector(settings.executionContext, settings.config) + new JvmMetricsCollector(settings.executionContext) } case class Collector ( @@ -213,7 +213,7 @@ object JvmMetricsCollector { "Compressed Class Space" -> MemoryPool("Compressed Class Space", "compressed-class-space", Usage.CodeCache), "PS Eden Space" -> MemoryPool("PS Eden Space", "eden", Usage.Eden), "PS Survivor Space" -> MemoryPool("PS Survivor Space", "survivor", Usage.YoungGeneration), - "PS Old Gen" -> MemoryPool("PS Old Gen", "old", Usage.OldGeneration), + "PS Old Gen" -> MemoryPool("PS Old Gen", "old", Usage.OldGeneration) ) private val _invalidChars: Regex = """[^a-z0-9]""".r diff --git a/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala b/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala index e4d1964..a81d7f8 100644 --- a/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala +++ b/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala @@ -17,7 +17,8 @@ import scala.collection.JavaConverters.iterableAsScalaIterableConverter import scala.concurrent.{ExecutionContext, Future} import scala.util.Try -class ProcessMetricsCollector(ec: ExecutionContext, initialConfig: Config) extends Module { +class ProcessMetricsCollector(ec: ExecutionContext) extends Module { + private val _hiccupIntervalPath = "kamon.instrumentation.system.process.hiccup-monitor-interval" private val _defaultTags = TagSet.of("component", "process") private val _processCpuInstruments = new ProcessInstruments(_defaultTags) private val _collectionTask = new MetricsCollectionTask @@ -30,9 +31,9 @@ class ProcessMetricsCollector(ec: ExecutionContext, initialConfig: Config) exten _collectionTask.cleanup() } - override def reconfigure(newConfig: Config): Unit = { - _hiccupMonitor.updateInterval(newConfig.getDuration("hiccup-monitor-interval")) - } + override def reconfigure(newConfig: Config): Unit = + _hiccupMonitor.updateInterval(newConfig.getDuration(_hiccupIntervalPath)) + private def scheduleOnModuleEC(task: MetricsCollectionTask): Runnable = new Runnable { override def run(): Unit = @@ -40,7 +41,7 @@ class ProcessMetricsCollector(ec: ExecutionContext, initialConfig: Config) exten } private def startHiccupMonitor(): HiccupMonitor = { - val interval = initialConfig.getDuration("hiccup-monitor-interval") + val interval = Kamon.config().getDuration(_hiccupIntervalPath) val monitorThread = new HiccupMonitor(_processCpuInstruments.hiccups, interval) monitorThread.setDaemon(true) monitorThread.setName("hiccup-monitor") @@ -94,7 +95,7 @@ class ProcessMetricsCollector(ec: ExecutionContext, initialConfig: Config) exten private def recordProcessULimits(): Unit = { val process = _os.getProcess(_pid) - _processCpuInstruments.openFilesCurrent.record(process.getOpenFiles()) + _processCpuInstruments.openFilesCurrent.record(Math.max(process.getOpenFiles(), 0)) Try { if (Platform.isLinux()) { @@ -157,6 +158,6 @@ object ProcessMetricsCollector { class Factory extends ModuleFactory { override def create(settings: ModuleFactory.Settings): Module = - new ProcessMetricsCollector(settings.executionContext, settings.config) + new ProcessMetricsCollector(settings.executionContext) } } \ No newline at end of file