Skip to content

Commit

Permalink
feat: added micrometer plugin to default build set
Browse files Browse the repository at this point in the history
  • Loading branch information
QuadStingray committed Feb 13, 2024
1 parent fe22fd4 commit 99675cb
Show file tree
Hide file tree
Showing 23 changed files with 792 additions and 4 deletions.
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import common.mongoCampProject
import dev.quadstingray.sbt.json.JsonFile

lazy val root = Project(id = "mc-server-parent", base = file(".")).aggregate(mcCli, mcLibrary, mcServer, mcTest, mcPluginRequestLogging)
lazy val root = Project(id = "mc-server-parent", base = file(".")).aggregate(mcCli, mcLibrary, mcServer, mcTest, mcPluginRequestLogging, mcPluginMicrometer)

ThisBuild / scalaVersion := "2.13.12"

Expand All @@ -20,3 +20,5 @@ lazy val mcCli = mongoCampProject("cli").dependsOn(mcLibrary).enablePlugins(Buil
lazy val mcServer = mongoCampProject("server").enablePlugins(BuildInfoPlugin).dependsOn(mcLibrary, mcTest % Test)

lazy val mcPluginRequestLogging = mongoCampProject("plugin-requestlogging").dependsOn(mcServer, mcTest % Test).enablePlugins(BuildInfoPlugin)

lazy val mcPluginMicrometer = mongoCampProject("plugin-micrometer").dependsOn(mcServer, mcTest % Test).enablePlugins(BuildInfoPlugin)
6 changes: 3 additions & 3 deletions docs/plugins/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ title: List of Plugins
# {{ $frontmatter.title }}

## Monitoring
| Name | Description |
|:----------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------:|
| [Micrometer](https://github.com/MongoCamp/mongocamp-micrometer-plugin) | Adds Functionality to use MicroMeter in other Plugins to your MongoCamp Instance and allow logging of Mircometer Registries to your Database |
| Name | Description |
|:---------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------:|
| [Micrometer](./mongocamp/micrometer.md) | Adds Functionality to use MicroMeter in other Plugins to your MongoCamp Instance and allow logging of Mircometer Registries to your Database |

## Logging
| Name | Description |
Expand Down
39 changes: 39 additions & 0 deletions docs/plugins/mongocamp/micrometer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# MongoDB Micrometer Statistics

This is Plugin adds Micrometer Functionality to a [MongoCamp Server](../../index.md). So other Plugins can use Micrometer or you can get your Micrometer Statistics to Database or call them by HTTP.


## Configuration

### Dependency Setup
Add this to your [Plugin Modules](../../config/properties/plugins-module.md) to download the plugin from Maven Central.


<DependencyGroup organization="dev.mongocamp" name="mongocamp-plugin-micrometer" version="$$MC_VERSION$$" />

### MongoCamp Configuration Settings
#### Persistence Plugin

| Configuration | Description | Default | Type |
|--------------------------------|---------------------------------------------|:-------:|:--------:|
| LOGGING_METRICS_MONGODB_STEP | Duration between persist Metrics to MongoDB | 60m | Duration |
| LOGGING_METRICS_MONGODB_JVM | Should persist JVM Metrics to MongoDB | false | Boolean |
| LOGGING_METRICS_MONGODB_SYSTEM | Should persist SYSTEM Metrics to MongoDB | false | Boolean |
| LOGGING_METRICS_MONGODB_MONGO | Should persist MONGO Metrics to MongoDB | false | Boolean |
| LOGGING_METRICS_MONGODB_EVENT | Should persist EVENT Metrics to MongoDB | false | Boolean |

#### MongoDB Metrics Plugin

Plugin to monitor your MongoDB with your Application

| Configuration | Description | Default | Type |
|--------------------------------|-------------------------------------------------|:-------:|:--------:|
| METRICS_MONGODB_DATABASE | Should monitor all collections in Database | false | Boolean |
| METRICS_MONGODB_COLLECTIONS | Should monitor explicit collections in Database | [] | [String] |
| METRICS_MONGODB_CONNECTIONS | Should monitor CONNECTIONS of your MongoDB | false | Boolean |
| METRICS_MONGODB_NETWORK | Should monitor NETWORK of your MongoDB | false | Boolean |
| METRICS_MONGODB_OPERATION | Should monitor OPERATION of your MongoDB | false | Boolean |
| METRICS_MONGODB_SERVER | Should monitor SERVER of your MongoDB | false | Boolean |
| METRICS_MONGODB_COMMAND | Should monitor COMMAND of your MongoDB | false | Boolean |
| METRICS_MONGODB_CONNECTIONPOOL | Should monitor CONNECTIONPOOL of your MongoDB | false | Boolean |

9 changes: 9 additions & 0 deletions mongocamp-plugin-micrometer/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name := "mongocamp-plugin-micrometer"

enablePlugins(BuildInfoPlugin)

buildInfoPackage := "dev.mongocamp.server.plugin.micrometer"

buildInfoOptions += BuildInfoOption.BuildTime

libraryDependencies += "dev.mongocamp" %% "micrometer-mongodb" % "0.6.1"
18 changes: 18 additions & 0 deletions mongocamp-plugin-micrometer/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
logging.metrics.mongodb {
jvm = false
system = false
mongo = false
event = false
step = 60m
}

metrics.mongodb {
database = false
collections = []
connections = false
network = false
operation = false
command = false
connectionpool = false
server = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package dev.mongocamp.server.plugins.monitoring

import io.micrometer.core.instrument.binder.MeterBinder
import io.micrometer.core.instrument.binder.jvm._
import io.micrometer.core.instrument.binder.system.{ DiskSpaceMetrics, FileDescriptorMetrics, ProcessorMetrics, UptimeMetrics }
import io.micrometer.core.instrument.{ MeterRegistry, Metrics }

import java.io.File
import scala.collection.mutable.ArrayBuffer

object MetricsConfiguration {

private lazy val jvmMetricsRegistries: ArrayBuffer[MeterRegistry] = ArrayBuffer()
private lazy val systemMetricsRegistries: ArrayBuffer[MeterRegistry] = ArrayBuffer()
private lazy val mongoDbMetricsRegistries: ArrayBuffer[MeterRegistry] = ArrayBuffer()
private lazy val eventMetricsRegistries: ArrayBuffer[MeterRegistry] = ArrayBuffer()

private lazy val jvmMeterBinder: ArrayBuffer[MeterBinder] = ArrayBuffer(
new ClassLoaderMetrics(),
new JvmMemoryMetrics(),
new JvmGcMetrics(),
new JvmHeapPressureMetrics(),
new JvmThreadMetrics(),
new JvmInfoMetrics(),
new JvmCompilationMetrics()
)
private lazy val systemMeterBinder: ArrayBuffer[MeterBinder] = ArrayBuffer(
new DiskSpaceMetrics(new File("/")),
new FileDescriptorMetrics(),
new ProcessorMetrics(),
new UptimeMetrics()
)

private lazy val mongoDbMeterBinder: ArrayBuffer[MeterBinder] = ArrayBuffer()
private lazy val eventMeterBinder: ArrayBuffer[MeterBinder] = ArrayBuffer()

def addJvmRegistry(registry: MeterRegistry): Unit = {
jvmMetricsRegistries += registry
Metrics.globalRegistry.add(registry)
}

def addSystemRegistry(registry: MeterRegistry): Unit = {
systemMetricsRegistries += registry
Metrics.globalRegistry.add(registry)
}

def addMongoRegistry(registry: MeterRegistry): Unit = {
mongoDbMetricsRegistries += registry
Metrics.globalRegistry.add(registry)
}

def addEventRegistry(registry: MeterRegistry): Unit = {
eventMetricsRegistries += registry
Metrics.globalRegistry.add(registry)
}

def getJvmMetricsRegistries = jvmMetricsRegistries.toList

def getSystemMetricsRegistries = systemMetricsRegistries.toList

def getMongoDbMetricsRegistries = mongoDbMetricsRegistries.toList

def getEventMetricsRegistries = eventMetricsRegistries.toList

def addJvmMeterBinder(meterBinder: MeterBinder): Unit = jvmMeterBinder += meterBinder

def addSystemMeterBinder(meterBinder: MeterBinder): Unit = systemMeterBinder += meterBinder

def addMongoDbBinder(meterBinder: MeterBinder): Unit = mongoDbMeterBinder += meterBinder

def addEventMeterBinder(meterBinder: MeterBinder): Unit = eventMeterBinder += meterBinder

def bindAll(): Unit = {
getJvmMetricsRegistries.foreach(r => jvmMeterBinder.foreach(_.bindTo(r)))
getSystemMetricsRegistries.foreach(r => systemMeterBinder.foreach(_.bindTo(r)))
getMongoDbMetricsRegistries.foreach(r => mongoDbMeterBinder.foreach(_.bindTo(r)))
getEventMetricsRegistries.foreach(r => eventMeterBinder.foreach(_.bindTo(r)))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package dev.mongocamp.server.plugins.monitoring.metrics

import com.typesafe.scalalogging.LazyLogging
import dev.mongocamp.server.event.{Event, EventSystem}
import dev.mongocamp.server.plugin.ServerPlugin
import dev.mongocamp.server.plugins.monitoring.MetricsConfiguration
import io.micrometer.core.instrument.simple.SimpleMeterRegistry
import org.apache.pekko.actor.Props

object DefaultMetricsPlugin extends ServerPlugin with LazyLogging {
override def activate(): Unit = {
MetricsConfiguration.addJvmRegistry(new SimpleMeterRegistry())
MetricsConfiguration.addSystemRegistry(new SimpleMeterRegistry())
MetricsConfiguration.addMongoRegistry(new SimpleMeterRegistry())
MetricsConfiguration.addEventRegistry(new SimpleMeterRegistry())

val metricsLoggingActor = EventSystem.eventBusActorSystem.actorOf(Props(classOf[MetricsLoggingActor]), "metricsLoggingActor")
EventSystem.eventStream.subscribe(metricsLoggingActor, classOf[Event])
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dev.mongocamp.server.plugins.monitoring.metrics

import com.typesafe.scalalogging.LazyLogging
import dev.mongocamp.server.event.Event
import dev.mongocamp.server.event.http.HttpRequestCompletedEvent
import dev.mongocamp.server.plugins.monitoring.MetricsConfiguration
import org.apache.pekko.actor.Actor

import java.time.Duration

class MetricsLoggingActor extends Actor with LazyLogging {
def receive: Receive = {

case "info" =>
logger.info(this.getClass.getSimpleName)

case e: HttpRequestCompletedEvent =>
val eventNameArray = e.getClass.getName.split('.')
val indexOfEvent = eventNameArray.indexOf("event")
val pathArray = eventNameArray.slice(indexOfEvent, eventNameArray.length)
val regex = "([a-z])([A-Z]+)"
val replacement = "$1.$2"
val metricsName = s"${pathArray.mkString(".")}".replaceAll("Event", "").replaceAll(regex, replacement).toLowerCase()
MetricsConfiguration.getEventMetricsRegistries.foreach(_.timer(metricsName).record(Duration.ofMillis(e.duration.getMillis)))
MetricsConfiguration.getEventMetricsRegistries.foreach(
_.timer(s"$metricsName.${e.controller.toLowerCase()}.${e.controllerMethod.toLowerCase()}").record(Duration.ofMillis(e.duration.getMillis))
)

case e: Event =>
val eventNameArray = e.getClass.getName.split('.')
val indexOfEvent = eventNameArray.indexOf("event")
val pathArray = eventNameArray.slice(indexOfEvent, eventNameArray.length)
val regex = "([a-z])([A-Z]+)"
val replacement = "$1.$2"
val metricsName = s"${pathArray.mkString(".")}".replaceAll("Event", "").replaceAll(regex, replacement).toLowerCase()
MetricsConfiguration.getEventMetricsRegistries.foreach(_.summary(metricsName).record(1))

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package dev.mongocamp.server.plugins.monitoring.model

case class Measurement(statisticType: String, value: Double)
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package dev.mongocamp.server.plugins.monitoring.model

import com.typesafe.scalalogging.LazyLogging
import io.micrometer.core.instrument.Meter

import scala.jdk.CollectionConverters._

case class Metric(name: String, metricsType: String, description: String, baseUnit: String, measurements: List[Measurement])

object Metric extends LazyLogging {
def apply(meter: Meter): Metric = {
Metric(
validStringValue(meter.getId.getName),
validStringValue(meter.getId.getType.name()),
validStringValue(meter.getId.getDescription),
validStringValue(meter.getId.getBaseUnit),
meter
.measure()
.asScala
.toList
.map(v => Measurement(validStringValue(v.getStatistic.name()), validDoubleValue(v.getValue)))
)
}

private def validStringValue(value: String): String = {
if (value == null) {
""
}
else {
value
}
}

private def validDoubleValue(value: Double): Double = {
if (value == null) {
0.0
}
else {
value
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dev.mongocamp.server.plugins.monitoring.mongodb

import com.typesafe.scalalogging.LazyLogging
import dev.mongocamp.micrometer.mongodb.registry.MongoStepMeterRegistry
import dev.mongocamp.server.database.MongoDatabase
import dev.mongocamp.server.model.MongoCampConfiguration
import dev.mongocamp.server.plugin.ServerPlugin
import dev.mongocamp.server.plugins.monitoring.MetricsConfiguration
import dev.mongocamp.server.service.ConfigurationService

import scala.concurrent.duration.Duration

object MetricsMongoDBPersistenceLoggingPlugin extends ServerPlugin with LazyLogging {
private val ConfKeyMicrometerStep = "LOGGING_METRICS_MONGODB_STEP"
private val ConfKeyLoggingJvmToMongoDb = "LOGGING_METRICS_MONGODB_JVM"
private val ConfKeyLoggingSystemToMongoDb = "LOGGING_METRICS_MONGODB_SYSTEM"
private val ConfKeyLoggingMongoToMongoDb = "LOGGING_METRICS_MONGODB_MONGO"
private val ConfKeyLoggingEventToMongoDb = "LOGGING_METRICS_MONGODB_EVENT"

override def activate(): Unit = {

ConfigurationService.registerConfig(ConfKeyMicrometerStep, MongoCampConfiguration.confTypeDuration)
ConfigurationService.registerConfig(ConfKeyLoggingJvmToMongoDb, MongoCampConfiguration.confTypeBoolean)
ConfigurationService.registerConfig(ConfKeyLoggingSystemToMongoDb, MongoCampConfiguration.confTypeBoolean)
ConfigurationService.registerConfig(ConfKeyLoggingMongoToMongoDb, MongoCampConfiguration.confTypeBoolean)
ConfigurationService.registerConfig(ConfKeyLoggingEventToMongoDb, MongoCampConfiguration.confTypeBoolean)

val stepDuration = ConfigurationService.getConfigValue[Duration](ConfKeyMicrometerStep)
val configMap = Map("step" -> s"${stepDuration.toMillis}ms")
if (ConfigurationService.getConfigValue[Boolean](ConfKeyLoggingJvmToMongoDb)) {
MetricsConfiguration.addJvmRegistry(MongoStepMeterRegistry(MongoDatabase.databaseProvider.dao("monitoring_jvm"), configMap))
}
if (ConfigurationService.getConfigValue[Boolean](ConfKeyLoggingSystemToMongoDb)) {
MetricsConfiguration.addSystemRegistry(MongoStepMeterRegistry(MongoDatabase.databaseProvider.dao("monitoring_system"), configMap))
}
if (ConfigurationService.getConfigValue[Boolean](ConfKeyLoggingMongoToMongoDb)) {
MetricsConfiguration.addMongoRegistry(MongoStepMeterRegistry(MongoDatabase.databaseProvider.dao("monitoring_mongo_db"), configMap))
}
if (ConfigurationService.getConfigValue[Boolean](ConfKeyLoggingEventToMongoDb)) {
MetricsConfiguration.addEventRegistry(MongoStepMeterRegistry(MongoDatabase.databaseProvider.dao("monitoring_event"), configMap))
}
}

}
Loading

0 comments on commit 99675cb

Please sign in to comment.