-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds first pass on metrics. Didn't test CloudWatch
- Loading branch information
Showing
8 changed files
with
275 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package mods.eln.metrics | ||
|
||
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder | ||
import com.amazonaws.services.cloudwatch.model.Dimension | ||
import com.amazonaws.services.cloudwatch.model.MetricDatum | ||
import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest | ||
import mods.eln.Eln | ||
|
||
|
||
object CloudwatchMetricsImpl: IMetricsAbstraction { | ||
val cw = AmazonCloudWatchClientBuilder.defaultClient() | ||
|
||
/** | ||
* Put a metric to CloudWatch. | ||
* | ||
* @param value The value of the metric in question | ||
* @param unit The unit type | ||
* @param metricName The name of the metric (for example, time to complete X) | ||
* @param namespace The part of the code we are in. For example, "MNA" | ||
* @param description The description (unused for CloudWatch) | ||
*/ | ||
override fun putMetric(value: Double, unit: UnitTypes, metricName: String, namespace: String, description: String) { | ||
val dimension = Dimension().withName("Server").withValue(Eln.metricsDimension) | ||
val datum = MetricDatum().withMetricName(metricName).withUnit(unit.symbol).withValue(value).withDimensions(dimension) | ||
val request = PutMetricDataRequest().withNamespace("ELN/$namespace").withMetricData(datum) | ||
cw.putMetricData(request) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package mods.eln.metrics | ||
|
||
interface IMetricsAbstraction { | ||
/** | ||
* Put a metric to a service. | ||
* | ||
* @param value The value of the metric in question (a double) | ||
* @param unit The unit type (seconds, volts, watts, etc.) | ||
* @param metricName The name of the metric (for example, time to complete X) | ||
* @param namespace The part of the code we are in. For example, "MNA" | ||
*/ | ||
fun putMetric(value: Double, unit: UnitTypes, metricName: String, namespace: String, description: String) | ||
} | ||
|
||
enum class UnitTypes(val symbol: String) { | ||
SECONDS("s"), | ||
MINUTES("m"), | ||
HOURS("h"), | ||
MILLISECONDS("ms"), | ||
MICROSECONDS("µs"), | ||
NANOSECONDS("ns"), | ||
TICKS("t"), | ||
VOLTS("V"), | ||
AMPS("A"), | ||
WATTS("W"), | ||
JOULES("J"), | ||
NO_UNITS("") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package mods.eln.metrics | ||
|
||
import mods.eln.Eln | ||
import mods.eln.misc.Utils | ||
import java.util.concurrent.ConcurrentLinkedQueue | ||
|
||
object MetricsSubsystem { | ||
private val metricSinks = mutableListOf<IMetricsAbstraction>() | ||
private val metricThread: Thread | ||
private val metricsIngested = ConcurrentLinkedQueue<MetricData>() | ||
|
||
init { | ||
if (Eln.prometheusEnable) { | ||
metricSinks.add(PrometheusMetricsImpl) | ||
} | ||
if (Eln.cloudwatchEnable) { | ||
metricSinks.add(CloudwatchMetricsImpl) | ||
} | ||
|
||
metricThread = Thread { | ||
// Wait a tick for data. We don't need to be exactly on the tick, but it's not worth going faster really. | ||
Thread.sleep(50) | ||
|
||
while (true) { | ||
val metric = metricsIngested.remove()?: break | ||
metricSinks.forEach { | ||
try { | ||
it.putMetric(metric.value, metric.unit, metric.metricName, metric.namespace, metric.description) | ||
} catch (e: Exception) { | ||
Utils.println("The ${it.javaClass.name} metric subsystem failed. $e") | ||
} | ||
} | ||
} | ||
} | ||
metricThread.start() | ||
} | ||
|
||
/** | ||
* Put a metric to the metrics subsystem (Now with thread safety!) | ||
* | ||
* @param value The value of the metric in question (a double) | ||
* @param unit The unit type (seconds, volts, watts, etc.) | ||
* @param metricName The name of the metric (for example, time to complete X) | ||
* @param namespace The part of the code we are in. For example, "MNA" | ||
*/ | ||
fun putMetric(value: Double, unit: UnitTypes, metricName: String, namespace: String, description: String) { | ||
metricsIngested.add(MetricData(value, unit, metricName, namespace, description)) | ||
} | ||
|
||
/** | ||
* Simple thing to just put data directly in (for use by simplistic abstractions) | ||
*/ | ||
fun putMetric(metricData: MetricData) { | ||
metricsIngested.add(metricData) | ||
} | ||
} | ||
|
||
class SimpleMetric(val metricName: String, val namespace: String, val description: String, val unit: UnitTypes) { | ||
fun putMetric(value: Double) { | ||
MetricsSubsystem.putMetric(MetricData(value, unit, metricName, namespace, description)) | ||
} | ||
} | ||
|
||
data class MetricData(val value: Double, val unit: UnitTypes, val metricName: String, val namespace: String, val description: String) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package mods.eln.metrics | ||
|
||
import io.prometheus.client.Gauge | ||
import io.prometheus.client.exporter.HTTPServer | ||
import mods.eln.Eln | ||
|
||
object PrometheusMetricsImpl: IMetricsAbstraction { | ||
|
||
init { | ||
// I have no idea how this works. I guess saving it to a value is not necessary? | ||
HTTPServer("0.0.0.0", Eln.prometheusPort) | ||
} | ||
|
||
private val metricMap = mutableMapOf<String, Gauge>() | ||
|
||
/** | ||
* Put a metric to Prometheus. | ||
* | ||
* @param value The value of the metric in question | ||
* @param unit The unit type (Unused for Prometheus) | ||
* @param metricName The name of the metric (for example, time to complete X) | ||
* @param namespace The part of the code we are in. For example, "MNA" | ||
* @param description The description (a help text for Prometheus) | ||
*/ | ||
override fun putMetric(value: Double, unit: UnitTypes, metricName: String, namespace: String, description: String) { | ||
createMetric(metricName, namespace, description) | ||
val metric = metricMap[metricName]?: return | ||
metric.set(value) | ||
} | ||
|
||
/** | ||
* You can't have duplicate metric names registered, so we're going to handle that for you. | ||
* | ||
* @param metricName The name of the metrics (for example, time to complete X) | ||
* @param namespace The part of the code we are in. For example, "MNA" | ||
* @param description The description (a help text for Prometheus) | ||
*/ | ||
fun createMetric(metricName: String, namespace: String, description: String) { | ||
if (metricName !in metricMap) { | ||
val metric = Gauge.build().name("${namespace}_$metricName").help(description).register() | ||
metricMap[metricName] = metric | ||
} | ||
} | ||
} |
Oops, something went wrong.