diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml
index a13fd050..6805edcb 100644
--- a/.github/workflows/preview.yml
+++ b/.github/workflows/preview.yml
@@ -11,7 +11,7 @@ jobs:
- name: Configure GPG Key
run: echo "${{secrets.SIGNING_KEY}}" | base64 --decode > /tmp/keyring.gpg
- name: Set up JDK 17
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 17
distribution: zulu
@@ -39,7 +39,7 @@ jobs:
- name: Configure GPG Key
run: echo "${{secrets.SIGNING_KEY}}" | base64 --decode > /tmp/keyring.gpg
- name: Set up JDK 17
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 17
distribution: zulu
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1bffd253..49fd4ade 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,7 +11,7 @@ jobs:
- name: Configure GPG Key
run: echo "${{secrets.SIGNING_KEY}}" | base64 --decode > /tmp/keyring.gpg
- name: Set up JDK 17
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 17
distribution: zulu
@@ -38,7 +38,7 @@ jobs:
- name: Configure GPG Key
run: echo "${{secrets.SIGNING_KEY}}" | base64 --decode > /tmp/keyring.gpg
- name: Set up JDK 17
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 17
distribution: zulu
diff --git a/.gitignore b/.gitignore
index e240c6d5..165f3dbc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,6 @@
.gradle
build
-**/run*/
\ No newline at end of file
+**/run*/
+.kotlin
+.vscode/
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/UnifiedMetrics.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/UnifiedMetrics.kt
new file mode 100644
index 00000000..426d8515
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/UnifiedMetrics.kt
@@ -0,0 +1,58 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api
+
+import dev.cubxity.plugins.metrics.api.logging.Logger
+import dev.cubxity.plugins.metrics.api.metric.MetricsManager
+import dev.cubxity.plugins.metrics.api.platform.Platform
+import kotlinx.coroutines.CoroutineDispatcher
+
+/**
+ * The UnifiedMetrics API
+ */
+interface UnifiedMetrics {
+ /**
+ * The platform UnifiedMetrics is running on.
+ */
+ val platform: Platform
+
+ /**
+ * The name of this server.
+ *
+ * This is defined in the UnifiedMetrics configuration file, and is used for
+ * grouping server data.
+ *
+ * The default server name is "global"
+ */
+ val serverName: String
+
+ /**
+ * The platform's logger.
+ */
+ val logger: Logger
+
+ /**
+ * The platform's dispatcher.
+ */
+ val dispatcher: CoroutineDispatcher
+
+ /**
+ * The metrics api.
+ */
+ val metricsManager: MetricsManager
+}
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/UnifiedMetricsProvider.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/UnifiedMetricsProvider.kt
new file mode 100644
index 00000000..daa58cb5
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/UnifiedMetricsProvider.kt
@@ -0,0 +1,40 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api
+
+/**
+ * Provides static access to the [UnifiedMetrics] service.
+ */
+object UnifiedMetricsProvider {
+ @JvmStatic
+ private var instance: UnifiedMetrics? = null
+
+ @JvmStatic
+ fun get(): UnifiedMetrics =
+ instance ?: error("The UnifiedMetrics API is not loaded.")
+
+ @JvmStatic
+ fun register(instance: UnifiedMetrics) {
+ UnifiedMetricsProvider.instance = instance
+ }
+
+ @JvmStatic
+ fun unregister() {
+ instance = null
+ }
+}
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/logging/Logger.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/logging/Logger.kt
new file mode 100644
index 00000000..39a93f32
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/logging/Logger.kt
@@ -0,0 +1,30 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.logging
+
+interface Logger {
+ fun info(message: String)
+
+ fun warn(message: String)
+
+ fun warn(message: String, error: Throwable)
+
+ fun severe(message: String)
+
+ fun severe(message: String, error: Throwable)
+}
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsDriver.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsDriver.kt
new file mode 100644
index 00000000..9ac94007
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsDriver.kt
@@ -0,0 +1,24 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric
+
+import java.io.Closeable
+
+interface MetricsDriver : Closeable {
+ fun initialize()
+}
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsDriverFactory.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsDriverFactory.kt
new file mode 100644
index 00000000..80b3b080
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsDriverFactory.kt
@@ -0,0 +1,29 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import kotlinx.serialization.KSerializer
+
+interface MetricsDriverFactory {
+ val configSerializer: KSerializer
+
+ val defaultConfig: T
+
+ fun createDriver(api: UnifiedMetrics, config: T): MetricsDriver
+}
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsManager.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsManager.kt
new file mode 100644
index 00000000..e0aad34d
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/MetricsManager.kt
@@ -0,0 +1,40 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric
+
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+
+interface MetricsManager {
+ val collections: List
+
+ fun initialize()
+
+ fun registerCollection(collection: CollectorCollection)
+
+ fun unregisterCollection(collection: CollectorCollection)
+
+ fun registerDriver(name: String, factory: MetricsDriverFactory)
+
+ /**
+ * This should be called asynchronously
+ */
+ suspend fun collect(): List
+
+ fun dispose()
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Collector.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Collector.kt
new file mode 100644
index 00000000..66fc243c
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Collector.kt
@@ -0,0 +1,33 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric.collector
+
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+
+const val NANOSECONDS_PER_MILLISECOND: Double = 1E6
+const val NANOSECONDS_PER_SECOND: Double = 1E9
+const val MILLISECONDS_PER_SECOND: Double = 1E3
+
+interface Collector {
+ /**
+ * Collects the metric and returns a list of samples.
+ *
+ * @return [List] of [Metric]
+ */
+ fun collect(): List
+}
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/CollectorCollection.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/CollectorCollection.kt
new file mode 100644
index 00000000..3f5a61c8
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/CollectorCollection.kt
@@ -0,0 +1,44 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric.collector
+
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.api.util.fastFlatMap
+
+interface CollectorCollection {
+ /**
+ * List of collectors associated with this metric.
+ */
+ val collectors: List
+
+ /**
+ * Whether the collection should be collected asynchronously.
+ */
+ val isAsync: Boolean get() = false
+
+ fun initialize() {
+ // Do nothing
+ }
+
+ fun dispose() {
+ // Do nothing
+ }
+}
+
+fun CollectorCollection.collect(): List =
+ collectors.fastFlatMap { it.collect() }
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Counter.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Counter.kt
new file mode 100644
index 00000000..599a5a87
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Counter.kt
@@ -0,0 +1,53 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric.collector
+
+import dev.cubxity.plugins.metrics.api.metric.data.CounterMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Labels
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.api.metric.store.DoubleAdderStore
+import dev.cubxity.plugins.metrics.api.metric.store.DoubleStoreFactory
+
+/**
+ * @param name name of the sample. Should end with '_total'
+ */
+class Counter(
+ private val name: String,
+ private val labels: Labels = emptyMap(),
+ valueStoreFactory: DoubleStoreFactory = DoubleAdderStore
+) : Collector {
+ private val count = valueStoreFactory.create()
+
+ override fun collect(): List {
+ return listOf(
+ CounterMetric(name, labels, count.get())
+ )
+ }
+
+ operator fun inc(): Counter = apply {
+ count.add(1.0)
+ }
+
+ operator fun plusAssign(delta: Double) {
+ count.add(delta)
+ }
+
+ operator fun plusAssign(delta: Number) {
+ count.add(delta.toDouble())
+ }
+}
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Histogram.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Histogram.kt
new file mode 100644
index 00000000..e44b2a55
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/collector/Histogram.kt
@@ -0,0 +1,100 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric.collector
+
+import dev.cubxity.plugins.metrics.api.metric.data.Bucket
+import dev.cubxity.plugins.metrics.api.metric.data.HistogramMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Labels
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.api.metric.store.DoubleAdderStore
+import dev.cubxity.plugins.metrics.api.metric.store.DoubleStoreFactory
+import dev.cubxity.plugins.metrics.api.metric.store.LongAdderStore
+import dev.cubxity.plugins.metrics.api.metric.store.LongStoreFactory
+
+private val defaultBuckets = doubleArrayOf(
+ .001, // 1 ms
+ .005, // 5 ms
+ .01, // 10 ms
+ .02, // 20 ms
+ .03, // 30 ms
+ .04, // 40 ms
+ .05, // 50 ms
+ .075, // 75 ms
+ .1, // 100 ms
+ .25, // 250 ms
+ .5, // 500 ms
+ .75, // 750 ms
+ 1.0, // 1 s
+ 2.5, // 2.5 s
+ 5.0, // 5 s
+ 7.5, // 7.5 s
+ 10.0, // 10 s
+ 60.0 // 1 m
+)
+
+/**
+ * @param name name of the sample.
+ */
+class Histogram(
+ private val name: String,
+ private val labels: Labels = emptyMap(),
+ upperBounds: DoubleArray = defaultBuckets,
+ sumStoreFactory: DoubleStoreFactory = DoubleAdderStore,
+ countStoreFactory: LongStoreFactory = LongAdderStore
+) : Collector {
+ private val upperBounds = upperBounds + Double.POSITIVE_INFINITY
+
+ private val sum = sumStoreFactory.create()
+ private val counts = Array(this.upperBounds.size) {
+ countStoreFactory.create()
+ }
+
+ override fun collect(): List {
+ val bucketSize = counts.size
+ val bucket = arrayOfNulls(bucketSize)
+ var count = 0L
+
+ for (i in bucketSize downTo 1) {
+ val index = bucketSize - i
+
+ count += counts[index].get()
+ bucket[index] = Bucket(upperBounds[index], count.toDouble())
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ return listOf(
+ HistogramMetric(name, labels, count.toDouble(), sum.get(), bucket as Array)
+ )
+ }
+
+ operator fun plusAssign(value: Double) {
+ val size = upperBounds.size
+ for (i in size downTo 1) {
+ val index = size - i
+ if (value <= upperBounds[index]) {
+ counts[index].add(1)
+ break
+ }
+ }
+ sum.add(value)
+ }
+
+ operator fun plusAssign(value: Number) {
+ plusAssign(value.toDouble())
+ }
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/data/Metric.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/data/Metric.kt
new file mode 100644
index 00000000..3a2190a0
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/data/Metric.kt
@@ -0,0 +1,69 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+@file:Suppress("FunctionName")
+
+package dev.cubxity.plugins.metrics.api.metric.data
+
+typealias Labels = Map
+
+sealed class Metric(
+ val name: String,
+ val labels: Labels = emptyMap()
+)
+
+class GaugeMetric(
+ name: String,
+ labels: Labels = emptyMap(),
+ val value: Double
+) : Metric(name, labels) {
+ constructor(
+ name: String,
+ labels: Labels = emptyMap(),
+ value: Number
+ ) : this(name, labels, value.toDouble())
+}
+
+class CounterMetric(
+ name: String,
+ labels: Labels = emptyMap(),
+ val value: Double
+) : Metric(name, labels) {
+ constructor(
+ name: String,
+ labels: Labels = emptyMap(),
+ value: Number
+ ) : this(name, labels, value.toDouble())
+}
+
+class HistogramMetric(
+ name: String,
+ labels: Labels = emptyMap(),
+ val sampleCount: Double,
+ val sampleSum: Double,
+ val bucket: Array
+) : Metric(name, labels) {
+ constructor(
+ name: String,
+ labels: Labels = emptyMap(),
+ sampleCount: Number,
+ sampleSum: Number,
+ bucket: Array
+ ) : this(name, labels, sampleCount.toDouble(), sampleSum.toDouble(), bucket)
+}
+
+data class Bucket(val upperBound: Double, val cumulativeCount: Double)
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/data/MetricType.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/data/MetricType.kt
new file mode 100644
index 00000000..01a187c8
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/data/MetricType.kt
@@ -0,0 +1,28 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric.data
+
+/**
+ * Prometheus-compatible metric types. The Prometheus server does not yet make use of the type information.
+ */
+sealed class MetricType {
+ object Unknown : MetricType()
+ object Counter : MetricType()
+ object Gauge : MetricType()
+ object Histogram : MetricType()
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Double.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Double.kt
new file mode 100644
index 00000000..5a1587b9
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Double.kt
@@ -0,0 +1,53 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric.store
+
+import java.util.concurrent.atomic.DoubleAdder
+
+typealias DoubleStore = Store
+
+typealias DoubleStoreFactory = StoreFactory
+
+class VolatileDoubleStore : DoubleStore {
+ @Volatile
+ private var value: Double = 0.0
+
+ override fun add(delta: Double) {
+ value += delta
+ }
+
+ override fun get(): Double = value
+
+ companion object Factory : DoubleStoreFactory {
+ override fun create(): DoubleStore = VolatileDoubleStore()
+ }
+}
+
+class DoubleAdderStore : DoubleStore {
+ private val value = DoubleAdder()
+
+ override fun add(delta: Double) {
+ value.add(delta)
+ }
+
+ override fun get(): Double = value.sum()
+
+ companion object Factory : DoubleStoreFactory {
+ override fun create(): DoubleStore = DoubleAdderStore()
+ }
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Long.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Long.kt
new file mode 100644
index 00000000..9a4e09cf
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Long.kt
@@ -0,0 +1,53 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric.store
+
+import java.util.concurrent.atomic.LongAdder
+
+typealias LongStore = Store
+
+typealias LongStoreFactory = StoreFactory
+
+class VolatileLongStore : LongStore {
+ @Volatile
+ private var value: Long = 0
+
+ override fun add(delta: Long) {
+ value += delta
+ }
+
+ override fun get(): Long = value
+
+ companion object Factory : LongStoreFactory {
+ override fun create(): LongStore = VolatileLongStore()
+ }
+}
+
+class LongAdderStore : LongStore {
+ private val value = LongAdder()
+
+ override fun add(delta: Long) {
+ value.add(delta)
+ }
+
+ override fun get(): Long = value.sum()
+
+ companion object Factory : LongStoreFactory {
+ override fun create(): LongStore = LongAdderStore()
+ }
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Store.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Store.kt
new file mode 100644
index 00000000..eab7fd6e
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/metric/store/Store.kt
@@ -0,0 +1,28 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.metric.store
+
+interface Store {
+ fun add(delta: T)
+
+ fun get(): T
+}
+
+interface StoreFactory> {
+ fun create(): T
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/platform/Platform.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/platform/Platform.kt
new file mode 100644
index 00000000..b2ed2a97
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/platform/Platform.kt
@@ -0,0 +1,30 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.platform
+
+/**
+ * Represents the platform that UnifiedMetrics is running on.
+ */
+interface Platform {
+ /**
+ * The platform that UnifiedMetrics is running on.
+ *
+ * @see PlatformType
+ */
+ val type: PlatformType
+}
\ No newline at end of file
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/platform/PlatformType.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/platform/PlatformType.kt
new file mode 100644
index 00000000..d593e11f
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/platform/PlatformType.kt
@@ -0,0 +1,29 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.platform
+
+sealed class PlatformType(val name: String) {
+ // Server implementations
+ object Bukkit : PlatformType("Bukkit")
+ object Minestom : PlatformType("Minestom")
+ object Fabric : PlatformType("Fabric")
+
+ // Proxies
+ object Velocity : PlatformType("Velocity")
+ object BungeeCord : PlatformType("BungeeCord")
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/util/Arrays.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/util/Arrays.kt
new file mode 100644
index 00000000..fb74a26c
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/util/Arrays.kt
@@ -0,0 +1,25 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.util
+
+inline fun Array.fastForEach(block: (T) -> Unit) {
+ val size = size
+ for (index in size downTo 1) {
+ block(get(size - index))
+ }
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/util/Collections.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/util/Collections.kt
new file mode 100644
index 00000000..8bdccafc
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/util/Collections.kt
@@ -0,0 +1,33 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.util
+
+inline fun List.fastForEach(block: (T) -> Unit) {
+ val size = size
+ for (i in size downTo 1) {
+ block(get(size - i))
+ }
+}
+
+inline fun List.fastFlatMap(block: (T) -> Collection): List {
+ val list = ArrayList()
+ fastForEach {
+ list.addAll(block(it))
+ }
+ return list
+}
diff --git a/api/bin/main/dev/cubxity/plugins/metrics/api/util/Numbers.kt b/api/bin/main/dev/cubxity/plugins/metrics/api/util/Numbers.kt
new file mode 100644
index 00000000..bbe5cfac
--- /dev/null
+++ b/api/bin/main/dev/cubxity/plugins/metrics/api/util/Numbers.kt
@@ -0,0 +1,24 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.api.util
+
+fun Double.toGoString(): String = when (this) {
+ Double.POSITIVE_INFINITY -> "+Inf"
+ Double.NEGATIVE_INFINITY -> "-Inf"
+ else -> toString()
+}
diff --git a/api/build.gradle.kts b/api/build.gradle.kts
index fdfbd6c3..cb3fa361 100644
--- a/api/build.gradle.kts
+++ b/api/build.gradle.kts
@@ -18,8 +18,8 @@
dependencies {
api(platform(kotlin("bom")))
api(kotlin("stdlib"))
- api("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")
- api("org.jetbrains.kotlinx", "kotlinx-serialization-core", "1.6.0")
+ api("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.8.1")
+ api("org.jetbrains.kotlinx", "kotlinx-serialization-core", "1.7.1")
}
java {
diff --git a/build.gradle.kts b/build.gradle.kts
index ef55a3b0..0ee24b7e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -15,21 +15,23 @@
* along with UnifiedMetrics. If not, see .
*/
-import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
- kotlin("jvm") version "1.9.10" apply false
- kotlin("kapt") version "1.9.10" apply false
- kotlin("plugin.serialization") version "1.9.10" apply false
+ kotlin("jvm") version "2.0.0" apply false
+ kotlin("kapt") version "2.0.0" apply false
+ kotlin("plugin.serialization") version "2.0.0" apply false
id("com.github.johnrengelman.shadow") version "8.1.1" apply false
- id("net.kyori.blossom") version "1.3.1" apply false
+
+ // The fabric-loom plugin must be defined in the root project for it to function properly.
+ id("fabric-loom") version "1.9-SNAPSHOT" apply false
}
allprojects {
group = "dev.cubxity.plugins"
description = "Fully featured metrics collector agent for Minecraft servers."
- version = "0.3.9-SNAPSHOT"
+ version = "0.3.10-SNAPSHOT"
repositories {
mavenCentral()
@@ -43,13 +45,13 @@ subprojects {
apply(plugin = "maven-publish")
tasks.withType {
- kotlinOptions {
- kotlinOptions.jvmTarget = "1.8"
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_21)
freeCompilerArgs = listOf("-opt-in=kotlin.RequiresOptIn")
}
}
configure {
- targetCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_21
}
configure {
repositories {
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/UnifiedMetricsBootstrap.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/UnifiedMetricsBootstrap.kt
new file mode 100644
index 00000000..e7f0dff7
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/UnifiedMetricsBootstrap.kt
@@ -0,0 +1,60 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common
+
+import dev.cubxity.plugins.metrics.api.logging.Logger
+import dev.cubxity.plugins.metrics.api.platform.PlatformType
+import kotlinx.coroutines.CoroutineDispatcher
+import java.nio.file.Path
+
+interface UnifiedMetricsBootstrap {
+ /**
+ * The plugin's platform type
+ */
+ val type: PlatformType
+
+ /**
+ * The installed plugin's version
+ */
+ val version: String
+
+ /**
+ * The server's brand
+ */
+ val serverBrand: String
+
+ /**
+ * The plugin's data directory
+ */
+ val dataDirectory: Path
+
+ /**
+ * The plugin's config directory
+ */
+ val configDirectory: Path
+
+ /**
+ * The platform's logger
+ */
+ val logger: Logger
+
+ /**
+ * The platform's dispatcher
+ */
+ val dispatcher: CoroutineDispatcher
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/api/MetricsManagerImpl.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/api/MetricsManagerImpl.kt
new file mode 100644
index 00000000..d1d20de6
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/api/MetricsManagerImpl.kt
@@ -0,0 +1,156 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.api
+
+import com.charleskorn.kaml.Yaml
+import com.charleskorn.kaml.YamlConfiguration
+import dev.cubxity.plugins.metrics.api.metric.MetricsDriver
+import dev.cubxity.plugins.metrics.api.metric.MetricsDriverFactory
+import dev.cubxity.plugins.metrics.api.metric.MetricsManager
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.collect
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.api.util.fastForEach
+import dev.cubxity.plugins.metrics.common.plugin.UnifiedMetricsPlugin
+import dev.cubxity.plugins.metrics.common.plugin.dispatcher.CurrentThreadDispatcher
+import kotlinx.coroutines.withContext
+import java.nio.file.Files
+import kotlin.system.measureTimeMillis
+
+class MetricsManagerImpl(private val plugin: UnifiedMetricsPlugin) : MetricsManager {
+ private val yaml = Yaml(configuration = YamlConfiguration(strictMode = false))
+ private val driverDirectory = plugin.bootstrap.configDirectory.resolve("driver")
+
+ private val metricDrivers: MutableMap> = HashMap()
+ private val _collections: MutableList = ArrayList()
+
+ private var shouldInitialize: Boolean = false
+ private var driver: MetricsDriver? = null
+
+ override val collections: List
+ get() = _collections
+
+ override fun initialize() {
+ shouldInitialize = true
+
+ val driverName = plugin.config.metrics.driver
+ val factory = metricDrivers[driverName]
+
+ Files.createDirectories(driverDirectory)
+
+ if (factory !== null) {
+ initializeDriver(driverName, factory)
+ } else {
+ plugin.bootstrap.logger.warn("Driver '$driverName' not found. Metrics will be enabled when the driver is loaded.")
+ }
+ }
+
+ override fun registerCollection(collection: CollectorCollection) {
+ try {
+ collection.initialize()
+ _collections.add(collection)
+ } catch (error: Throwable) {
+ plugin.bootstrap.logger.warn("An error occurred whilst registering metric", error)
+ }
+ }
+
+ override fun unregisterCollection(collection: CollectorCollection) {
+ try {
+ _collections.remove(collection)
+ collection.dispose()
+ } catch (error: Throwable) {
+ plugin.bootstrap.logger.warn("An error occurred whilst unregistering metric", error)
+ }
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun registerDriver(name: String, factory: MetricsDriverFactory) {
+ metricDrivers[name] = factory as MetricsDriverFactory
+
+ if (shouldInitialize && driver === null) {
+ if (name == plugin.config.metrics.driver) {
+ initializeDriver(name, factory)
+ }
+ }
+ }
+
+ override suspend fun collect(): List {
+ val list = ArrayList()
+ val dispatcher = plugin.apiProvider.dispatcher
+
+ if (dispatcher is CurrentThreadDispatcher) {
+ collections.fastForEach { collection ->
+ list.addAll(collection.collect())
+ }
+ } else {
+ withContext(dispatcher) {
+ collections.fastForEach { collection ->
+ if (!collection.isAsync) {
+ list.addAll(collection.collect())
+ }
+ }
+ }
+ collections.fastForEach { collection ->
+ if (collection.isAsync) {
+ list.addAll(collection.collect())
+ }
+ }
+ }
+ return list
+ }
+
+ override fun dispose() {
+ shouldInitialize = false
+
+ collections.toList().fastForEach { collection ->
+ unregisterCollection(collection)
+ }
+
+ driver?.close()
+ driver = null
+ }
+
+ private fun initializeDriver(name: String, factory: MetricsDriverFactory) {
+ plugin.bootstrap.logger.info("Initializing driver '$name'.")
+ val time = measureTimeMillis {
+ try {
+ val file = driverDirectory.toFile().resolve("$name.yml")
+
+ val serializer = factory.configSerializer
+ val config = when {
+ file.exists() -> yaml.decodeFromString(serializer, file.readText())
+ else -> factory.defaultConfig
+ }
+
+ try {
+ file.writeText(yaml.encodeToString(serializer, config))
+ } catch (exception: Exception) {
+ plugin.apiProvider.logger.severe("An error occurred whilst saving driver config file ", exception)
+ }
+
+ val driver = factory.createDriver(plugin.apiProvider, config)
+ driver.initialize()
+
+ this.driver = driver
+ } catch (error: Throwable) {
+ plugin.apiProvider.logger.severe("An error occurred whilst initializing metrics driver $name", error)
+ }
+ }
+ plugin.bootstrap.logger.info("Driver '$name' initialized ($time ms).")
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/api/PlatformImpl.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/api/PlatformImpl.kt
new file mode 100644
index 00000000..57a95365
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/api/PlatformImpl.kt
@@ -0,0 +1,27 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.api
+
+import dev.cubxity.plugins.metrics.common.plugin.UnifiedMetricsPlugin
+import dev.cubxity.plugins.metrics.api.platform.Platform
+import dev.cubxity.plugins.metrics.api.platform.PlatformType
+
+class PlatformImpl(private val plugin: UnifiedMetricsPlugin) : Platform {
+ override val type: PlatformType
+ get() = plugin.bootstrap.type
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/api/UnifiedMetricsApiProvider.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/api/UnifiedMetricsApiProvider.kt
new file mode 100644
index 00000000..7bcc7272
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/api/UnifiedMetricsApiProvider.kt
@@ -0,0 +1,41 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.api
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.api.logging.Logger
+import dev.cubxity.plugins.metrics.api.metric.MetricsManager
+import dev.cubxity.plugins.metrics.api.platform.Platform
+import dev.cubxity.plugins.metrics.common.plugin.UnifiedMetricsPlugin
+import kotlinx.coroutines.CoroutineDispatcher
+
+open class UnifiedMetricsApiProvider(val plugin: UnifiedMetricsPlugin) : UnifiedMetrics {
+ override val platform: Platform = PlatformImpl(plugin)
+
+ override val serverName: String
+ get() = plugin.config.server.name
+
+ override val logger: Logger
+ get() = plugin.bootstrap.logger
+
+ override val dispatcher: CoroutineDispatcher
+ get() = plugin.bootstrap.dispatcher
+
+ override val metricsManager: MetricsManager =
+ MetricsManagerImpl(plugin)
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/config/UnifiedMetricsConfig.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/config/UnifiedMetricsConfig.kt
new file mode 100644
index 00000000..ffd2abbb
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/config/UnifiedMetricsConfig.kt
@@ -0,0 +1,54 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.config
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class UnifiedMetricsConfig(
+ val server: UnifiedMetricsServerConfig = UnifiedMetricsServerConfig(),
+ val metrics: UnifiedMetricsMetricsConfig = UnifiedMetricsMetricsConfig()
+)
+
+@Serializable
+data class UnifiedMetricsServerConfig(
+ val name: String = env("SERVER_NAME", "global")
+)
+
+@Serializable
+data class UnifiedMetricsMetricsConfig(
+ val enabled: Boolean = true,
+ val driver: String = "prometheus",
+ val collectors: UnifiedMetricsCollectorsConfig = UnifiedMetricsCollectorsConfig()
+)
+
+@Serializable
+data class UnifiedMetricsCollectorsConfig(
+ val systemGc: Boolean = true,
+ val systemMemory: Boolean = true,
+ val systemProcess: Boolean = true,
+ val systemThread: Boolean = true,
+ val server: Boolean = true,
+ val world: Boolean = true,
+ val tick: Boolean = true,
+ val events: Boolean = true,
+ val regionizedServer: Boolean = true
+)
+
+private fun env(name: String, default: String): String =
+ System.getenv("UNIFIEDMETRICS_$name") ?: default
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/Metrics.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/Metrics.kt
new file mode 100644
index 00000000..8bfbeadb
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/Metrics.kt
@@ -0,0 +1,46 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric
+
+object Metrics {
+ object Events {
+ const val Login = "minecraft_events_login_total"
+ const val Join = "minecraft_events_join_total"
+ const val Quit = "minecraft_events_quit_total"
+ const val Chat = "minecraft_events_chat_total"
+ const val Ping = "minecraft_events_ping_total"
+ }
+
+ object Server {
+ const val Plugins = "minecraft_plugins"
+ const val PlayersCount = "minecraft_players_count"
+ const val PlayersMax = "minecraft_players_max"
+ const val TickDurationSeconds = "minecraft_tick_duration_seconds"
+ const val WorldEntitiesCount = "minecraft_world_entities_count"
+ const val WorldPlayersCount = "minecraft_world_players_count"
+ const val WorldLoadedChunks = "minecraft_world_loaded_chunks"
+ }
+
+ object RegionizedServer {
+ const val RegionCount = "minecraft_regionized_region_count"
+ const val RegionTick = "minecraft_regionized_region_tick_total"
+ const val RegionEntitiesCount = "minecraft_regionized_region_entities_count"
+ const val RegionPlayersCount = "minecraft_regionized_region_players_count"
+ const val RegionChunksCount = "minecraft_regionized_region_chunks_count"
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/gc/GCCollection.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/gc/GCCollection.kt
new file mode 100644
index 00000000..03e1f4ee
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/gc/GCCollection.kt
@@ -0,0 +1,77 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric.system.gc
+
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Histogram
+import dev.cubxity.plugins.metrics.api.util.fastForEach
+import java.lang.management.GarbageCollectorMXBean
+import java.lang.management.ManagementFactory
+import java.util.*
+import javax.management.NotificationEmitter
+
+private val byteBuckets = doubleArrayOf(
+ 25_000_000.0, // 25 MB
+ 50_000_000.0, // 50 MB
+ 100_000_000.0, // 100 MB
+ 250_000_000.0, // 250 MB
+ 500_000_000.0, // 500 MB
+ 1_000_000_000.0, // 1 GB
+ 2_000_000_000.0, // 2 GB
+ 3_000_000_000.0, // 3 GB
+ 5_000_000_000.0, // 5 GB
+)
+
+class GCCollection : CollectorCollection {
+ private val monitors = WeakHashMap()
+
+ override val collectors = ArrayList()
+
+ override val isAsync: Boolean
+ get() = true
+
+ override fun initialize() {
+ ManagementFactory.getGarbageCollectorMXBeans().fastForEach { bean ->
+ if (bean is NotificationEmitter) {
+ val labels = mapOf("gc" to bean.name)
+ val durationHistogram = Histogram("jvm_gc_duration_seconds", labels)
+ val freedHistogram = Histogram("jvm_gc_freed_bytes", labels, byteBuckets)
+
+ collectors += durationHistogram
+ collectors += freedHistogram
+
+ val monitor = GCMonitor(durationHistogram, freedHistogram)
+ monitors[bean] = monitor
+
+ bean.addNotificationListener(monitor, null, null)
+ }
+ }
+ }
+
+ override fun dispose() {
+ ManagementFactory.getGarbageCollectorMXBeans().fastForEach { bean ->
+ if (bean is NotificationEmitter) {
+ val monitor = monitors.remove(bean)
+ if (monitor !== null) {
+ bean.removeNotificationListener(monitor)
+ }
+ }
+ }
+ collectors.clear()
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/gc/GCMonitor.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/gc/GCMonitor.kt
new file mode 100644
index 00000000..b50e8df4
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/gc/GCMonitor.kt
@@ -0,0 +1,52 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric.system.gc
+
+import com.sun.management.GarbageCollectionNotificationInfo
+import dev.cubxity.plugins.metrics.api.metric.collector.Histogram
+import dev.cubxity.plugins.metrics.api.metric.collector.MILLISECONDS_PER_SECOND
+import javax.management.Notification
+import javax.management.NotificationListener
+import javax.management.openmbean.CompositeData
+
+class GCMonitor(
+ private val durationHistogram: Histogram,
+ private val freedHistogram: Histogram
+) : NotificationListener {
+ override fun handleNotification(notification: Notification, handback: Any?) {
+ if (notification.type != GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION) {
+ return
+ }
+
+ val info = (notification.userData as? CompositeData)
+ ?.let { GarbageCollectionNotificationInfo.from(it) }?.gcInfo ?: return
+
+ durationHistogram += info.duration / MILLISECONDS_PER_SECOND
+
+ var diff = 0L
+
+ for (usage in info.memoryUsageBeforeGc.values) {
+ diff += usage.used
+ }
+ for (usage in info.memoryUsageAfterGc.values) {
+ diff -= usage.used
+ }
+
+ freedHistogram += diff
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/memory/MemoryCollection.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/memory/MemoryCollection.kt
new file mode 100644
index 00000000..69ab722d
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/memory/MemoryCollection.kt
@@ -0,0 +1,28 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric.system.memory
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+
+class MemoryCollection : CollectorCollection {
+ override val collectors: List = listOf(MemoryCollector())
+
+ override val isAsync: Boolean
+ get() = true
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/memory/MemoryCollector.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/memory/MemoryCollector.kt
new file mode 100644
index 00000000..a320ce1e
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/memory/MemoryCollector.kt
@@ -0,0 +1,46 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric.system.memory
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import java.lang.management.ManagementFactory
+
+class MemoryCollector : Collector {
+ private val bean = ManagementFactory.getMemoryMXBean()
+
+ override fun collect(): List {
+ val heapUsage = bean.heapMemoryUsage
+ val nonHeapUsage = bean.nonHeapMemoryUsage
+
+ val heapTags = mapOf("area" to "heap")
+ val nonHeapTags = mapOf("area" to "nonheap")
+
+ return listOf(
+ GaugeMetric("jvm_memory_bytes_used", heapTags, heapUsage.used),
+ GaugeMetric("jvm_memory_bytes_used", nonHeapTags, nonHeapUsage.used),
+ GaugeMetric("jvm_memory_bytes_committed", heapTags, heapUsage.committed),
+ GaugeMetric("jvm_memory_bytes_committed", nonHeapTags, nonHeapUsage.committed),
+ GaugeMetric("jvm_memory_bytes_max", heapTags, heapUsage.max),
+ GaugeMetric("jvm_memory_bytes_max", nonHeapTags, nonHeapUsage.max),
+ GaugeMetric("jvm_memory_bytes_init", heapTags, heapUsage.init),
+ GaugeMetric("jvm_memory_bytes_init", nonHeapTags, nonHeapUsage.init)
+ )
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/process/ProcessCollection.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/process/ProcessCollection.kt
new file mode 100644
index 00000000..d1c85550
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/process/ProcessCollection.kt
@@ -0,0 +1,28 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric.system.process
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+
+class ProcessCollection : CollectorCollection {
+ override val collectors: List = listOf(ProcessCollector())
+
+ override val isAsync: Boolean
+ get() = true
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/process/ProcessCollector.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/process/ProcessCollector.kt
new file mode 100644
index 00000000..bfd08018
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/process/ProcessCollector.kt
@@ -0,0 +1,41 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric.system.process
+
+import com.sun.management.OperatingSystemMXBean
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.MILLISECONDS_PER_SECOND
+import dev.cubxity.plugins.metrics.api.metric.collector.NANOSECONDS_PER_SECOND
+import dev.cubxity.plugins.metrics.api.metric.data.CounterMetric
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import java.lang.management.ManagementFactory
+
+class ProcessCollector : Collector {
+ private val osBean = ManagementFactory.getOperatingSystemMXBean()
+ private val runtimeBean = ManagementFactory.getRuntimeMXBean()
+
+ override fun collect(): List = ArrayList(3).apply {
+ (osBean as? OperatingSystemMXBean)?.apply {
+ add(GaugeMetric("process_cpu_load_ratio", value = processCpuLoad))
+ add(CounterMetric("process_cpu_seconds_total", value = processCpuTime / NANOSECONDS_PER_SECOND))
+ }
+
+ add(GaugeMetric("process_start_time_seconds", value = runtimeBean.startTime / MILLISECONDS_PER_SECOND))
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/thread/ThreadCollection.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/thread/ThreadCollection.kt
new file mode 100644
index 00000000..acb525b0
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/thread/ThreadCollection.kt
@@ -0,0 +1,28 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric.system.thread
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+
+class ThreadCollection : CollectorCollection {
+ override val collectors: List = listOf(ThreadCollector())
+
+ override val isAsync: Boolean
+ get() = true
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/thread/ThreadCollector.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/thread/ThreadCollector.kt
new file mode 100644
index 00000000..0e48972c
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/metric/system/thread/ThreadCollector.kt
@@ -0,0 +1,55 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.metric.system.thread
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.NANOSECONDS_PER_SECOND
+import dev.cubxity.plugins.metrics.api.metric.data.CounterMetric
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import java.lang.management.ManagementFactory
+
+class ThreadCollector : Collector {
+ private val bean = ManagementFactory.getThreadMXBean()
+
+ override fun collect(): List {
+ val ids = bean.allThreadIds
+ val list = ArrayList(4 + 2 * ids.size)
+
+ list += GaugeMetric("jvm_threads_current_count", value = bean.threadCount)
+ list += GaugeMetric("jvm_threads_daemon_count", value = bean.daemonThreadCount)
+ list += CounterMetric("jvm_threads_started_total", value = bean.totalStartedThreadCount)
+ list += GaugeMetric("jvm_threads_peak", value = bean.peakThreadCount)
+
+ ids.forEach { id ->
+ val info = bean.getThreadInfo(id) ?: return@forEach
+ val labels = mapOf("thread" to info.threadName)
+ list += CounterMetric(
+ "jvm_threads_cpu_time_total",
+ value = bean.getThreadCpuTime(id) / NANOSECONDS_PER_SECOND,
+ labels = labels
+ )
+ list += CounterMetric(
+ "jvm_threads_user_time_total",
+ value = bean.getThreadUserTime(id) / NANOSECONDS_PER_SECOND,
+ labels = labels
+ )
+ }
+ return list
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/AbstractUnifiedMetricsPlugin.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/AbstractUnifiedMetricsPlugin.kt
new file mode 100644
index 00000000..86d7ad6c
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/AbstractUnifiedMetricsPlugin.kt
@@ -0,0 +1,108 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.plugin
+
+import com.charleskorn.kaml.Yaml
+import com.charleskorn.kaml.YamlConfiguration
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.api.UnifiedMetricsProvider
+import dev.cubxity.plugins.metrics.common.api.UnifiedMetricsApiProvider
+import dev.cubxity.plugins.metrics.common.config.UnifiedMetricsConfig
+import dev.cubxity.plugins.metrics.common.metric.system.gc.GCCollection
+import dev.cubxity.plugins.metrics.common.metric.system.memory.MemoryCollection
+import dev.cubxity.plugins.metrics.common.metric.system.process.ProcessCollection
+import dev.cubxity.plugins.metrics.common.metric.system.thread.ThreadCollection
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.encodeToString
+import java.nio.file.Files
+
+abstract class AbstractUnifiedMetricsPlugin : UnifiedMetricsPlugin {
+ private val yaml = Yaml(configuration = YamlConfiguration(strictMode = false))
+
+ private var _config: UnifiedMetricsConfig? = null
+ private var _apiProvider: UnifiedMetricsApiProvider? = null
+
+ override val config: UnifiedMetricsConfig
+ get() = _config ?: error("The UnifiedMetrics plugin is not loaded.")
+
+ override val apiProvider: UnifiedMetricsApiProvider
+ get() = _apiProvider ?: error("The UnifiedMetrics plugin is not loaded.")
+
+ open fun enable() {
+ Files.createDirectories(bootstrap.dataDirectory)
+ Files.createDirectories(bootstrap.configDirectory)
+
+ _config = loadConfig()
+ _apiProvider = UnifiedMetricsApiProvider(this)
+
+ try {
+ saveConfig()
+ } catch (exception: Exception) {
+ apiProvider.logger.severe("An error occurred whilst saving plugin config file", exception)
+ }
+
+ UnifiedMetricsProvider.register(apiProvider)
+ registerPlatformService(apiProvider)
+
+ if (config.metrics.enabled) {
+ registerMetricsDrivers()
+ registerPlatformMetrics()
+ apiProvider.metricsManager.initialize()
+ }
+ }
+
+ open fun disable() {
+ if (config.metrics.enabled) {
+ apiProvider.metricsManager.dispose()
+ }
+
+ UnifiedMetricsProvider.unregister()
+ _apiProvider = null
+ }
+
+ abstract fun registerPlatformService(api: UnifiedMetrics)
+
+ open fun registerMetricsDrivers() {
+
+ }
+
+ open fun registerPlatformMetrics() {
+ apiProvider.metricsManager.apply {
+ with(config.metrics.collectors) {
+ if (systemGc) registerCollection(GCCollection())
+ if (systemMemory) registerCollection(MemoryCollection())
+ if (systemProcess) registerCollection(ProcessCollection())
+ if (systemThread) registerCollection(ThreadCollection())
+ }
+ }
+ }
+
+ private fun loadConfig(): UnifiedMetricsConfig {
+ val file = bootstrap.configDirectory.toFile().resolve("config.yml")
+
+ return when {
+ file.exists() -> yaml.decodeFromString(file.readText())
+ else -> UnifiedMetricsConfig()
+ }
+ }
+
+ private fun saveConfig() {
+ val file = bootstrap.configDirectory.toFile().resolve("config.yml")
+ file.writeText(yaml.encodeToString(config))
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/UnifiedMetricsPlugin.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/UnifiedMetricsPlugin.kt
new file mode 100644
index 00000000..33026884
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/UnifiedMetricsPlugin.kt
@@ -0,0 +1,30 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.plugin
+
+import dev.cubxity.plugins.metrics.common.UnifiedMetricsBootstrap
+import dev.cubxity.plugins.metrics.common.api.UnifiedMetricsApiProvider
+import dev.cubxity.plugins.metrics.common.config.UnifiedMetricsConfig
+
+interface UnifiedMetricsPlugin {
+ val bootstrap: UnifiedMetricsBootstrap
+
+ val config: UnifiedMetricsConfig
+
+ val apiProvider: UnifiedMetricsApiProvider
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/dispatcher/CurrentThreadDispatcher.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/dispatcher/CurrentThreadDispatcher.kt
new file mode 100644
index 00000000..4ab2681c
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/dispatcher/CurrentThreadDispatcher.kt
@@ -0,0 +1,28 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.plugin.dispatcher
+
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Runnable
+import kotlin.coroutines.CoroutineContext
+
+object CurrentThreadDispatcher : CoroutineDispatcher() {
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ block.run()
+ }
+}
\ No newline at end of file
diff --git a/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/logger/JavaLogger.kt b/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/logger/JavaLogger.kt
new file mode 100644
index 00000000..e9a96860
--- /dev/null
+++ b/common/bin/main/dev/cubxity/plugins/metrics/common/plugin/logger/JavaLogger.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.common.plugin.logger
+
+import dev.cubxity.plugins.metrics.api.logging.Logger
+import java.util.logging.Level
+
+class JavaLogger(private val logger: java.util.logging.Logger) : Logger {
+ override fun info(message: String) {
+ logger.log(Level.INFO, message)
+ }
+
+ override fun warn(message: String) {
+ logger.log(Level.WARNING, message)
+ }
+
+ override fun warn(message: String, error: Throwable) {
+ logger.log(Level.WARNING, message, error)
+ }
+
+ override fun severe(message: String) {
+ logger.log(Level.SEVERE, message)
+ }
+
+ override fun severe(message: String, error: Throwable) {
+ logger.log(Level.SEVERE, message, error)
+ }
+}
\ No newline at end of file
diff --git a/common/build.gradle.kts b/common/build.gradle.kts
index e4b76d3b..fa41e02b 100644
--- a/common/build.gradle.kts
+++ b/common/build.gradle.kts
@@ -19,5 +19,5 @@ apply(plugin = "kotlinx-serialization")
dependencies {
api(project(":unifiedmetrics-api"))
- implementation("com.charleskorn.kaml:kaml:0.55.0")
+ implementation("com.charleskorn.kaml:kaml:0.60.0")
}
diff --git a/core/bin/main/dev/cubxity/plugins/metrics/core/plugin/CoreUnifiedMetricsPlugin.kt b/core/bin/main/dev/cubxity/plugins/metrics/core/plugin/CoreUnifiedMetricsPlugin.kt
new file mode 100644
index 00000000..bdf077cb
--- /dev/null
+++ b/core/bin/main/dev/cubxity/plugins/metrics/core/plugin/CoreUnifiedMetricsPlugin.kt
@@ -0,0 +1,31 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.core.plugin
+
+import dev.cubxity.plugins.metrics.common.plugin.AbstractUnifiedMetricsPlugin
+import dev.cubxity.plugins.metrics.influx.InfluxMetricsDriverFactory
+import dev.cubxity.plugins.metrics.prometheus.PrometheusMetricsDriverFactory
+
+abstract class CoreUnifiedMetricsPlugin : AbstractUnifiedMetricsPlugin() {
+ override fun registerMetricsDrivers() {
+ apiProvider.metricsManager.apply {
+ registerDriver("influx", InfluxMetricsDriverFactory)
+ registerDriver("prometheus", PrometheusMetricsDriverFactory)
+ }
+ }
+}
\ No newline at end of file
diff --git a/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/InfluxMetricsDriver.kt b/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/InfluxMetricsDriver.kt
new file mode 100644
index 00000000..09c9d2ae
--- /dev/null
+++ b/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/InfluxMetricsDriver.kt
@@ -0,0 +1,112 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.influx
+
+import com.influxdb.client.InfluxDBClient
+import com.influxdb.client.InfluxDBClientFactory
+import com.influxdb.client.InfluxDBClientOptions
+import com.influxdb.client.WriteApi
+import com.influxdb.client.write.Point
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.api.metric.MetricsDriver
+import dev.cubxity.plugins.metrics.api.metric.data.CounterMetric
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.HistogramMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.api.util.fastForEach
+import dev.cubxity.plugins.metrics.api.util.toGoString
+import dev.cubxity.plugins.metrics.influx.config.InfluxConfig
+import kotlinx.coroutines.*
+import kotlin.math.max
+import kotlin.system.measureTimeMillis
+
+class InfluxMetricsDriver(private val api: UnifiedMetrics, private val config: InfluxConfig) : MetricsDriver {
+ private val coroutineScope = CoroutineScope(Dispatchers.Default) + SupervisorJob()
+
+ private var influxDBClient: InfluxDBClient? = null
+ private var writeApi: WriteApi? = null
+
+ override fun initialize() {
+ val options = InfluxDBClientOptions.builder()
+ .url(config.output.url)
+ .apply {
+ when (config.authentication.scheme) {
+ InfluxDBClientOptions.AuthScheme.TOKEN ->
+ authenticateToken(config.authentication.token.toCharArray())
+ InfluxDBClientOptions.AuthScheme.SESSION ->
+ authenticate(config.authentication.username, config.authentication.password.toCharArray())
+ }
+ }
+ .bucket(config.output.bucket)
+ .org(config.output.organization)
+ .build()
+
+ influxDBClient = InfluxDBClientFactory.create(options)
+ writeApi = influxDBClient?.makeWriteApi()
+
+ scheduleTasks()
+ }
+
+ override fun close() {
+ coroutineScope.cancel()
+ writeApi?.close()
+ influxDBClient?.close()
+ influxDBClient = null
+ }
+
+ private fun scheduleTasks() {
+ val interval = config.output.interval * 1000
+
+ coroutineScope.launch {
+ while (true) {
+ val time = measureTimeMillis {
+ try {
+ val metrics = api.metricsManager.collect()
+ writeMetrics(metrics)
+ } catch (error: Throwable) {
+ api.logger.severe("An error occurred whilst writing samples to InfluxDB", error)
+ }
+ }
+ delay(max(0, interval - time))
+ }
+ }
+ }
+
+ private fun writeMetrics(metrics: List) {
+ val writeApi = writeApi ?: return
+ metrics.fastForEach { metric ->
+ val point = Point(metric.name)
+ point.addTags(metric.labels)
+ point.addTag("server", api.serverName)
+
+ when (metric) {
+ is GaugeMetric -> point.addField("gauge", metric.value)
+ is CounterMetric -> point.addField("counter", metric.value)
+ is HistogramMetric -> {
+ metric.bucket.fastForEach { bucket ->
+ point.addField(bucket.upperBound.toGoString(), bucket.cumulativeCount)
+ }
+ point.addField("count", metric.sampleCount)
+ point.addField("sum", metric.sampleSum)
+ }
+ }
+
+ writeApi.writePoint(point)
+ }
+ }
+}
diff --git a/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/InfluxMetricsDriverFactory.kt b/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/InfluxMetricsDriverFactory.kt
new file mode 100644
index 00000000..d9a1aed1
--- /dev/null
+++ b/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/InfluxMetricsDriverFactory.kt
@@ -0,0 +1,35 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.influx
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.api.metric.MetricsDriver
+import dev.cubxity.plugins.metrics.api.metric.MetricsDriverFactory
+import dev.cubxity.plugins.metrics.influx.config.InfluxConfig
+import kotlinx.serialization.KSerializer
+
+object InfluxMetricsDriverFactory : MetricsDriverFactory {
+ override val configSerializer: KSerializer
+ get() = InfluxConfig.serializer()
+
+ override val defaultConfig: InfluxConfig
+ get() = InfluxConfig()
+
+ override fun createDriver(api: UnifiedMetrics, config: InfluxConfig): MetricsDriver =
+ InfluxMetricsDriver(api, config)
+}
\ No newline at end of file
diff --git a/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/config/InfluxSpec.kt b/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/config/InfluxSpec.kt
new file mode 100644
index 00000000..2ca3736b
--- /dev/null
+++ b/drivers/influx/bin/main/dev/cubxity/plugins/metrics/influx/config/InfluxSpec.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.influx.config
+
+import com.influxdb.client.InfluxDBClientOptions
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class InfluxConfig(
+ val output: InfluxOutputConfig = InfluxOutputConfig(),
+ val authentication: InfluxAuthenticationConfig = InfluxAuthenticationConfig()
+)
+
+@Serializable
+data class InfluxOutputConfig(
+ val url: String = "http://influxdb:8086",
+ val organization: String = "-",
+ val bucket: String = "unifiedmetrics",
+ val interval: Long = 10
+)
+
+@Serializable
+data class InfluxAuthenticationConfig(
+ val scheme: InfluxDBClientOptions.AuthScheme = InfluxDBClientOptions.AuthScheme.TOKEN,
+ val username: String = "influx",
+ val password: String = "influx",
+ val token: String = "insert_your_token"
+)
diff --git a/drivers/influx/build.gradle.kts b/drivers/influx/build.gradle.kts
index 86a9b852..98d8b6a1 100644
--- a/drivers/influx/build.gradle.kts
+++ b/drivers/influx/build.gradle.kts
@@ -19,5 +19,5 @@ apply(plugin = "kotlinx-serialization")
dependencies {
compileOnly(project(":unifiedmetrics-api"))
- api("com.influxdb:influxdb-client-java:6.10.0")
+ api("com.influxdb:influxdb-client-java:7.1.0")
}
diff --git a/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/PrometheusMetricsDriver.kt b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/PrometheusMetricsDriver.kt
new file mode 100644
index 00000000..321c973b
--- /dev/null
+++ b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/PrometheusMetricsDriver.kt
@@ -0,0 +1,41 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.prometheus
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.api.metric.MetricsDriver
+import dev.cubxity.plugins.metrics.prometheus.config.PrometheusConfig
+import dev.cubxity.plugins.metrics.prometheus.config.PrometheusMode
+import dev.cubxity.plugins.metrics.prometheus.exporter.PrometheusExporter
+import dev.cubxity.plugins.metrics.prometheus.exporter.PrometheusHTTPExporter
+import dev.cubxity.plugins.metrics.prometheus.exporter.PushGatewayExporter
+
+class PrometheusMetricsDriver(api: UnifiedMetrics, val config: PrometheusConfig) : MetricsDriver {
+ private val exporter: PrometheusExporter = when (config.mode) {
+ PrometheusMode.Http -> PrometheusHTTPExporter(api, this)
+ PrometheusMode.PushGateway -> PushGatewayExporter(api, this)
+ }
+
+ override fun initialize() {
+ exporter.initialize()
+ }
+
+ override fun close() {
+ exporter.close()
+ }
+}
\ No newline at end of file
diff --git a/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/PrometheusMetricsDriverFactory.kt b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/PrometheusMetricsDriverFactory.kt
new file mode 100644
index 00000000..2d0b4fca
--- /dev/null
+++ b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/PrometheusMetricsDriverFactory.kt
@@ -0,0 +1,35 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.prometheus
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.api.metric.MetricsDriver
+import dev.cubxity.plugins.metrics.api.metric.MetricsDriverFactory
+import dev.cubxity.plugins.metrics.prometheus.config.PrometheusConfig
+import kotlinx.serialization.KSerializer
+
+object PrometheusMetricsDriverFactory : MetricsDriverFactory {
+ override val configSerializer: KSerializer
+ get() = PrometheusConfig.serializer()
+
+ override val defaultConfig: PrometheusConfig
+ get() = PrometheusConfig()
+
+ override fun createDriver(api: UnifiedMetrics, config: PrometheusConfig): MetricsDriver =
+ PrometheusMetricsDriver(api, config)
+}
\ No newline at end of file
diff --git a/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/collector/MetricSamplesCollection.kt b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/collector/MetricSamplesCollection.kt
new file mode 100644
index 00000000..681fbf9c
--- /dev/null
+++ b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/collector/MetricSamplesCollection.kt
@@ -0,0 +1,24 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.prometheus.collector
+
+import io.prometheus.client.Collector
+
+class MetricSamplesCollection(private val collection: List) : Collector() {
+ override fun collect(): List = collection
+}
\ No newline at end of file
diff --git a/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/collector/UnifiedMetricsCollector.kt b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/collector/UnifiedMetricsCollector.kt
new file mode 100644
index 00000000..a5ce6515
--- /dev/null
+++ b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/collector/UnifiedMetricsCollector.kt
@@ -0,0 +1,38 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.prometheus.collector
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.prometheus.exporter.toPrometheus
+import io.prometheus.client.Collector
+import kotlinx.coroutines.runBlocking
+
+class UnifiedMetricsCollector(private val api: UnifiedMetrics) : Collector() {
+ override fun collect(): List {
+ return try {
+ val metrics = runBlocking {
+ api.metricsManager.collect()
+ }
+
+ metrics.toPrometheus()
+ } catch (exception: Exception) {
+ api.logger.severe("An error occurred whilst collecting metrics", exception)
+ emptyList()
+ }
+ }
+}
\ No newline at end of file
diff --git a/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/config/PrometheusConfig.kt b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/config/PrometheusConfig.kt
new file mode 100644
index 00000000..9203d0cb
--- /dev/null
+++ b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/config/PrometheusConfig.kt
@@ -0,0 +1,68 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.prometheus.config
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class PrometheusConfig(
+ val mode: PrometheusMode = PrometheusMode.Http,
+ val http: PrometheusHttpConfig = PrometheusHttpConfig(),
+ val pushGateway: PushGatewayConfig = PushGatewayConfig()
+)
+
+@Serializable
+enum class PrometheusMode {
+ @SerialName("HTTP")
+ Http,
+
+ @SerialName("PUSHGATEWAY")
+ PushGateway
+}
+
+@Serializable
+data class PrometheusHttpConfig(
+ val host: String = "0.0.0.0",
+ val port: Int = 9100,
+ val authentication: AuthenticationConfig = AuthenticationConfig()
+)
+
+@Serializable
+data class PushGatewayConfig(
+ val job: String = "unifiedmetrics",
+ val url: String = "http://pushgateway:9091",
+ val authentication: AuthenticationConfig = AuthenticationConfig(),
+ val interval: Long = 10
+)
+
+@Serializable
+enum class AuthenticationScheme {
+ @SerialName("NONE")
+ None,
+
+ @SerialName("BASIC")
+ Basic
+}
+
+@Serializable
+data class AuthenticationConfig(
+ val scheme: AuthenticationScheme = AuthenticationScheme.None,
+ val username: String = "username",
+ val password: String = "password"
+)
diff --git a/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PrometheusExporter.kt b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PrometheusExporter.kt
new file mode 100644
index 00000000..b70cbbfd
--- /dev/null
+++ b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PrometheusExporter.kt
@@ -0,0 +1,99 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.prometheus.exporter
+
+import dev.cubxity.plugins.metrics.api.metric.data.CounterMetric
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.HistogramMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.api.util.fastForEach
+import dev.cubxity.plugins.metrics.api.util.toGoString
+import io.prometheus.client.Collector
+import java.io.Closeable
+
+interface PrometheusExporter : Closeable {
+ fun initialize()
+}
+
+fun List.toPrometheus(): List {
+ val map = LinkedHashMap>(size)
+
+ fastForEach { metric ->
+ map.computeIfAbsent(metric.name) { ArrayList() }.add(metric)
+ }
+
+ return map.map { (name, metrics) ->
+ val type: Collector.Type
+ val samples: MutableList
+
+ when (val metric = metrics.first()) {
+ is CounterMetric -> {
+ type = Collector.Type.COUNTER
+ samples = ArrayList(metrics.size)
+ }
+ is GaugeMetric -> {
+ type = Collector.Type.GAUGE
+ samples = ArrayList(metrics.size)
+ }
+ is HistogramMetric -> {
+ type = Collector.Type.HISTOGRAM
+ samples = ArrayList((2 + metric.bucket.size) * metrics.size)
+ }
+ }
+
+ metrics.fastForEach { metric ->
+ val keys = metric.labels.keys.toList()
+ val values = metric.labels.values.toList()
+
+ when (metric) {
+ is CounterMetric -> {
+ samples += Collector.MetricFamilySamples.Sample(metric.name, keys, values, metric.value)
+ }
+ is GaugeMetric -> {
+ samples += Collector.MetricFamilySamples.Sample(metric.name, keys, values, metric.value)
+ }
+ is HistogramMetric -> {
+ val keysWithLe = keys.toMutableList()
+ keysWithLe += "le"
+
+ val bucketName = "${metric.name}_bucket"
+
+ metric.bucket.fastForEach { bucket ->
+ val valuesWithLe = values.toMutableList()
+ valuesWithLe += bucket.upperBound.toGoString()
+
+ samples += Collector.MetricFamilySamples.Sample(
+ bucketName,
+ keysWithLe,
+ valuesWithLe,
+ bucket.cumulativeCount
+ )
+ }
+
+ samples +=
+ Collector.MetricFamilySamples.Sample("${metric.name}_count", keys, values, metric.sampleCount)
+
+ samples +=
+ Collector.MetricFamilySamples.Sample("${metric.name}_sum", keys, values, metric.sampleSum)
+ }
+ }
+ }
+
+ Collector.MetricFamilySamples(name, type, "", samples)
+ }
+}
\ No newline at end of file
diff --git a/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PrometheusHTTPExporter.kt b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PrometheusHTTPExporter.kt
new file mode 100644
index 00000000..a2b39bdd
--- /dev/null
+++ b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PrometheusHTTPExporter.kt
@@ -0,0 +1,64 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.prometheus.exporter
+
+import com.sun.net.httpserver.BasicAuthenticator
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.prometheus.PrometheusMetricsDriver
+import dev.cubxity.plugins.metrics.prometheus.collector.UnifiedMetricsCollector
+import dev.cubxity.plugins.metrics.prometheus.config.AuthenticationScheme
+import io.prometheus.client.CollectorRegistry
+import io.prometheus.client.exporter.HTTPServer
+
+class PrometheusHTTPExporter(
+ private val api: UnifiedMetrics,
+ private val driver: PrometheusMetricsDriver
+) : PrometheusExporter {
+ private var server: HTTPServer? = null
+
+ override fun initialize() {
+ val registry = CollectorRegistry()
+ registry.register(UnifiedMetricsCollector(api))
+
+ server = HTTPServer.Builder()
+ .withHostname(driver.config.http.host)
+ .withPort(driver.config.http.port)
+ .withRegistry(registry)
+ .apply {
+ with(driver.config.http.authentication) {
+ if (scheme == AuthenticationScheme.Basic) {
+ withAuthenticator(Authenticator(username, password))
+ }
+ }
+ }
+ .build()
+ }
+
+ override fun close() {
+ server?.close()
+ server = null
+ }
+
+ private class Authenticator(
+ private val username: String,
+ private val password: String
+ ) : BasicAuthenticator("unifiedmetrics") {
+ override fun checkCredentials(username: String?, password: String?): Boolean =
+ this.username == username && this.password == password
+ }
+}
\ No newline at end of file
diff --git a/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PushGatewayExporter.kt b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PushGatewayExporter.kt
new file mode 100644
index 00000000..ae14dcd2
--- /dev/null
+++ b/drivers/prometheus/bin/main/dev/cubxity/plugins/metrics/prometheus/exporter/PushGatewayExporter.kt
@@ -0,0 +1,78 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.prometheus.exporter
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.prometheus.PrometheusMetricsDriver
+import dev.cubxity.plugins.metrics.prometheus.collector.MetricSamplesCollection
+import dev.cubxity.plugins.metrics.prometheus.config.AuthenticationScheme
+import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory
+import io.prometheus.client.exporter.PushGateway
+import kotlinx.coroutines.*
+import java.net.URL
+import kotlin.math.max
+import kotlin.system.measureTimeMillis
+
+class PushGatewayExporter(
+ private val api: UnifiedMetrics,
+ private val driver: PrometheusMetricsDriver
+) : PrometheusExporter {
+ private val coroutineScope = CoroutineScope(Dispatchers.IO) + SupervisorJob()
+ private val groupingKey = mapOf("server" to api.serverName)
+
+ private var gateway: PushGateway? = null
+
+ override fun initialize() {
+ val config = driver.config.pushGateway
+
+ gateway = PushGateway(URL(config.url)).apply {
+ with(config.authentication) {
+ if (scheme == AuthenticationScheme.Basic) {
+ setConnectionFactory(BasicAuthHttpConnectionFactory(username, password))
+ }
+ }
+ }
+
+ scheduleTasks()
+ }
+
+ override fun close() {
+ coroutineScope.cancel()
+ gateway = null
+ }
+
+ private fun scheduleTasks() {
+ val interval = driver.config.pushGateway.interval * 1000
+
+ coroutineScope.launch {
+ while (true) {
+ val time = measureTimeMillis {
+ try {
+ val samples = api.metricsManager.collect()
+ val collection = MetricSamplesCollection(samples.toPrometheus())
+
+ gateway?.push(collection, driver.config.pushGateway.job, groupingKey)
+ } catch (error: Throwable) {
+ api.logger.severe("An error occurred whilst writing samples to Prometheus", error)
+ }
+ }
+ delay(max(0, interval - time))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 7f93135c..2c352119 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 3fa8f862..e0fd0202 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index 1aa94a42..f5feea6d 100755
--- a/gradlew
+++ b/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
diff --git a/gradlew.bat b/gradlew.bat
index 6689b85b..9b42019c 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/Dispatchers.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/Dispatchers.kt
new file mode 100644
index 00000000..5cbea24a
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/Dispatchers.kt
@@ -0,0 +1,62 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit
+
+import io.papermc.paper.threadedregions.RegionizedServer
+import kotlinx.coroutines.*
+import org.bukkit.Bukkit
+import org.bukkit.plugin.java.JavaPlugin
+import kotlin.coroutines.CoroutineContext
+
+@OptIn(InternalCoroutinesApi::class)
+class BukkitDispatcher(private val plugin: JavaPlugin) : CoroutineDispatcher(), Delay {
+ @OptIn(ExperimentalCoroutinesApi::class)
+ override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) {
+ val task = plugin.server.scheduler.runTaskLater(
+ plugin,
+ Runnable {
+ continuation.apply { resumeUndispatched(Unit) }
+ },
+ timeMillis / 50
+ )
+ continuation.invokeOnCancellation { task.cancel() }
+ }
+
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ if (!context.isActive) {
+ return
+ }
+
+ if (Bukkit.isPrimaryThread()) {
+ block.run()
+ } else {
+ plugin.server.scheduler.runTask(plugin, block)
+ }
+ }
+}
+
+@OptIn(InternalCoroutinesApi::class)
+class FoliaDispatcher : CoroutineDispatcher(), Delay {
+ override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) {
+ TODO("Not yet implemented")
+ }
+
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ RegionizedServer.getInstance().addTask(block)
+ }
+}
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/UnifiedMetricsBukkitPlugin.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/UnifiedMetricsBukkitPlugin.kt
new file mode 100644
index 00000000..141f0dbf
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/UnifiedMetricsBukkitPlugin.kt
@@ -0,0 +1,62 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+import dev.cubxity.plugins.metrics.bukkit.metric.events.EventsCollection
+import dev.cubxity.plugins.metrics.bukkit.metric.regionized.FoliaRegionCollection
+import dev.cubxity.plugins.metrics.bukkit.metric.server.ServerCollection
+import dev.cubxity.plugins.metrics.bukkit.metric.tick.TickCollection
+import dev.cubxity.plugins.metrics.bukkit.metric.world.WorldCollection
+import dev.cubxity.plugins.metrics.bukkit.util.BukkitPlatform
+import dev.cubxity.plugins.metrics.core.plugin.CoreUnifiedMetricsPlugin
+import org.bukkit.plugin.ServicePriority
+import java.util.concurrent.Executors
+
+class UnifiedMetricsBukkitPlugin(
+ override val bootstrap: UnifiedMetricsBukkitBootstrap
+) : CoreUnifiedMetricsPlugin() {
+ private val executor = Executors.newScheduledThreadPool(1)
+
+ override fun disable() {
+ executor.shutdownNow()
+ super.disable()
+ }
+
+ override fun registerPlatformService(api: UnifiedMetrics) {
+ bootstrap.server.servicesManager.register(UnifiedMetrics::class.java, api, bootstrap, ServicePriority.Normal)
+ }
+
+ override fun registerPlatformMetrics() {
+ super.registerPlatformMetrics()
+
+ apiProvider.metricsManager.apply {
+ with(config.metrics.collectors) {
+ if (server) registerCollection(ServerCollection(bootstrap))
+ if (world) registerCollection(WorldCollection(bootstrap))
+ if (tick) registerCollection(TickCollection(bootstrap))
+ if (events) registerCollection(EventsCollection(bootstrap))
+
+ if (regionizedServer && BukkitPlatform.current == BukkitPlatform.Folia) {
+ registerCollection(FoliaRegionCollection())
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/bootstrap/UnifiedMetricsBukkitBootstrap.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/bootstrap/UnifiedMetricsBukkitBootstrap.kt
new file mode 100644
index 00000000..a7fe9c43
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/bootstrap/UnifiedMetricsBukkitBootstrap.kt
@@ -0,0 +1,65 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.bootstrap
+
+import dev.cubxity.plugins.metrics.api.platform.PlatformType
+import dev.cubxity.plugins.metrics.bukkit.BukkitDispatcher
+import dev.cubxity.plugins.metrics.bukkit.FoliaDispatcher
+import dev.cubxity.plugins.metrics.bukkit.UnifiedMetricsBukkitPlugin
+import dev.cubxity.plugins.metrics.bukkit.util.BukkitPlatform
+import dev.cubxity.plugins.metrics.common.UnifiedMetricsBootstrap
+import dev.cubxity.plugins.metrics.common.plugin.logger.JavaLogger
+import kotlinx.coroutines.CoroutineDispatcher
+import org.bukkit.plugin.java.JavaPlugin
+import java.nio.file.Path
+
+@Suppress("MemberVisibilityCanBePrivate")
+class UnifiedMetricsBukkitBootstrap : JavaPlugin(), UnifiedMetricsBootstrap {
+ private val plugin = UnifiedMetricsBukkitPlugin(this)
+
+ override val type: PlatformType
+ get() = PlatformType.Bukkit
+
+ override val version: String
+ get() = description.version
+
+ override val serverBrand: String
+ get() = server.name
+
+ override val dataDirectory: Path
+ get() = dataFolder.toPath()
+
+ override val configDirectory: Path
+ get() = dataFolder.toPath()
+
+ override val logger = JavaLogger(getLogger())
+
+ override val dispatcher: CoroutineDispatcher = when (BukkitPlatform.current) {
+ BukkitPlatform.Folia -> FoliaDispatcher()
+ else -> BukkitDispatcher(this)
+ }
+
+ override fun onEnable() {
+ (this as UnifiedMetricsBootstrap).logger.info("Running on Bukkit platform ${BukkitPlatform.current}")
+ plugin.enable()
+ }
+
+ override fun onDisable() {
+ plugin.disable()
+ }
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/events/EventsCollection.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/events/EventsCollection.kt
new file mode 100644
index 00000000..fd4e30b0
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/events/EventsCollection.kt
@@ -0,0 +1,83 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+@file:Suppress("DEPRECATION") // Using Paper's event will cause incompatibility with non-paper bukkit/spigot servers
+
+package dev.cubxity.plugins.metrics.bukkit.metric.events
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Counter
+import dev.cubxity.plugins.metrics.api.metric.store.VolatileDoubleStore
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+import org.bukkit.event.EventHandler
+import org.bukkit.event.HandlerList
+import org.bukkit.event.Listener
+import org.bukkit.event.player.AsyncPlayerChatEvent
+import org.bukkit.event.player.AsyncPlayerPreLoginEvent
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerQuitEvent
+import org.bukkit.event.server.ServerListPingEvent
+
+@Suppress("UNUSED_PARAMETER")
+class EventsCollection(private val bootstrap: UnifiedMetricsBukkitBootstrap) : CollectorCollection, Listener {
+ private val loginCounter = Counter(Metrics.Events.Login)
+ private val joinCounter = Counter(Metrics.Events.Join, valueStoreFactory = VolatileDoubleStore)
+ private val quitCounter = Counter(Metrics.Events.Quit, valueStoreFactory = VolatileDoubleStore)
+ private val chatCounter = Counter(Metrics.Events.Chat)
+ private val pingCounter = Counter(Metrics.Events.Ping) // TODO: is this async?
+
+ override val collectors: List =
+ listOf(loginCounter, joinCounter, quitCounter, chatCounter, pingCounter)
+
+ override val isAsync: Boolean
+ get() = true
+
+ override fun initialize() {
+ bootstrap.server.pluginManager.registerEvents(this, bootstrap)
+ }
+
+ override fun dispose() {
+ HandlerList.unregisterAll(this)
+ }
+
+ @EventHandler
+ fun onLogin(event: AsyncPlayerPreLoginEvent) {
+ loginCounter.inc()
+ }
+
+ @EventHandler
+ fun onJoin(event: PlayerJoinEvent) {
+ joinCounter.inc()
+ }
+
+ @EventHandler
+ fun onQuit(event: PlayerQuitEvent) {
+ quitCounter.inc()
+ }
+
+ @EventHandler
+ fun onChat(event: AsyncPlayerChatEvent) {
+ chatCounter.inc()
+ }
+
+ @EventHandler
+ fun onPing(event: ServerListPingEvent) {
+ pingCounter.inc()
+ }
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/regionized/FoliaRegionCollection.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/regionized/FoliaRegionCollection.kt
new file mode 100644
index 00000000..54ad8b72
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/regionized/FoliaRegionCollection.kt
@@ -0,0 +1,27 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.regionized
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+
+class FoliaRegionCollection : CollectorCollection {
+ override val collectors: List = listOf(FoliaRegionCollector())
+ override val isAsync: Boolean
+ get() = true
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/regionized/FoliaRegionCollector.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/regionized/FoliaRegionCollector.kt
new file mode 100644
index 00000000..93a97c97
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/regionized/FoliaRegionCollector.kt
@@ -0,0 +1,56 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.regionized
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.CounterMetric
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.bukkit.util.regioniser
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+import io.papermc.paper.threadedregions.ThreadedRegionizer.ThreadedRegion
+import io.papermc.paper.threadedregions.TickRegions.TickRegionData
+import io.papermc.paper.threadedregions.TickRegions.TickRegionSectionData
+import org.bukkit.Bukkit
+
+
+class FoliaRegionCollector : Collector {
+ override fun collect(): List {
+ val worlds = Bukkit.getWorlds()
+
+ val regions = ArrayList>()
+ for (world in worlds) {
+ world.regioniser.computeForAllRegions(regions::add)
+ }
+
+ val samples = ArrayList(regions.size * 4 + 1)
+ for (region in regions) {
+ val tags = mapOf("world" to region.data.world.serverLevelData.levelName, "region" to "${region.id}")
+ samples.add(CounterMetric(Metrics.RegionizedServer.RegionTick, tags, region.data.currentTick))
+
+ val stats = region.data.regionStats
+ samples.add(GaugeMetric(Metrics.RegionizedServer.RegionEntitiesCount, tags, stats.entityCount))
+ samples.add(GaugeMetric(Metrics.RegionizedServer.RegionPlayersCount, tags, stats.playerCount))
+ samples.add(GaugeMetric(Metrics.RegionizedServer.RegionChunksCount, tags, stats.chunkCount))
+ }
+
+ samples.add(GaugeMetric(Metrics.RegionizedServer.RegionCount, value = regions.size))
+
+ return samples
+ }
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/server/ServerCollection.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/server/ServerCollection.kt
new file mode 100644
index 00000000..8f58d85c
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/server/ServerCollection.kt
@@ -0,0 +1,26 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.server
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+
+class ServerCollection(bootstrap: UnifiedMetricsBukkitBootstrap) : CollectorCollection {
+ override val collectors: List = listOf(ServerCollector(bootstrap))
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/server/ServerCollector.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/server/ServerCollector.kt
new file mode 100644
index 00000000..7f6068c6
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/server/ServerCollector.kt
@@ -0,0 +1,35 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.server
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+
+class ServerCollector(private val bootstrap: UnifiedMetricsBukkitBootstrap) : Collector {
+ override fun collect(): List {
+ val server = bootstrap.server
+ return listOf(
+ GaugeMetric(Metrics.Server.Plugins, value = server.pluginManager.plugins.size),
+ GaugeMetric(Metrics.Server.PlayersCount, value = server.onlinePlayers.size),
+ GaugeMetric(Metrics.Server.PlayersMax, value = server.maxPlayers)
+ )
+ }
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/BukkitTickReporter.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/BukkitTickReporter.kt
new file mode 100644
index 00000000..32cf49ea
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/BukkitTickReporter.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.tick
+
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+
+class BukkitTickReporter(
+ private val metric: TickCollection,
+ private val bootstrap: UnifiedMetricsBukkitBootstrap
+) : TickReporter, Runnable {
+ private var taskId: Int? = null
+
+ override fun initialize() {
+ taskId = bootstrap.server.scheduler.runTaskTimer(bootstrap, this, 1, 1).taskId
+ }
+
+ override fun dispose() {
+ val taskId = taskId
+ if (taskId !== null) {
+ bootstrap.server.scheduler.cancelTask(taskId)
+ this.taskId = null
+ }
+ }
+
+ override fun run() {
+ metric.onTick(0.0)
+ }
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/PaperTickReporter.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/PaperTickReporter.kt
new file mode 100644
index 00000000..1410c6b5
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/PaperTickReporter.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.tick
+
+import com.destroystokyo.paper.event.server.ServerTickEndEvent
+import dev.cubxity.plugins.metrics.api.metric.collector.MILLISECONDS_PER_SECOND
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+import org.bukkit.event.EventHandler
+import org.bukkit.event.HandlerList
+import org.bukkit.event.Listener
+
+class PaperTickReporter(
+ private val metric: TickCollection,
+ private val bootstrap: UnifiedMetricsBukkitBootstrap
+) : TickReporter, Listener {
+ override fun initialize() {
+ bootstrap.server.pluginManager.registerEvents(this, bootstrap)
+ }
+
+ override fun dispose() {
+ HandlerList.unregisterAll(this)
+ }
+
+ @EventHandler
+ fun onTick(event: ServerTickEndEvent) {
+ metric.onTick(event.tickDuration / MILLISECONDS_PER_SECOND)
+ }
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/TickCollection.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/TickCollection.kt
new file mode 100644
index 00000000..93759d47
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/TickCollection.kt
@@ -0,0 +1,61 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.tick
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Histogram
+import dev.cubxity.plugins.metrics.api.metric.store.VolatileDoubleStore
+import dev.cubxity.plugins.metrics.api.metric.store.VolatileLongStore
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+import dev.cubxity.plugins.metrics.bukkit.util.BukkitPlatform
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+
+class TickCollection(bootstrap: UnifiedMetricsBukkitBootstrap) : CollectorCollection {
+ private val reporter = when (BukkitPlatform.current) {
+ BukkitPlatform.Folia, BukkitPlatform.Paper -> PaperTickReporter(this, bootstrap)
+ else -> BukkitTickReporter(this, bootstrap)
+ }
+
+ // The callback is called from a single thread
+ private val tickDuration = Histogram(
+ Metrics.Server.TickDurationSeconds,
+ sumStoreFactory = VolatileDoubleStore,
+ countStoreFactory = VolatileLongStore
+ )
+
+ override val collectors: List = listOf(tickDuration)
+
+ override val isAsync: Boolean
+ get() = true
+
+ override fun initialize() {
+ reporter.initialize()
+ }
+
+ override fun dispose() {
+ reporter.dispose()
+ }
+
+ /**
+ * @param duration tick duration in seconds
+ */
+ fun onTick(duration: Double) {
+ tickDuration += duration
+ }
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/TickReporter.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/TickReporter.kt
new file mode 100644
index 00000000..11a603e9
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/tick/TickReporter.kt
@@ -0,0 +1,24 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.tick
+
+interface TickReporter {
+ fun initialize()
+
+ fun dispose()
+}
\ No newline at end of file
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/BukkitWorldCollector.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/BukkitWorldCollector.kt
new file mode 100644
index 00000000..878bf108
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/BukkitWorldCollector.kt
@@ -0,0 +1,41 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.world
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.api.util.fastForEach
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+
+class BukkitWorldCollector(private val bootstrap: UnifiedMetricsBukkitBootstrap) : Collector {
+ override fun collect(): List {
+ val worlds = bootstrap.server.worlds
+ val samples = ArrayList(worlds.size * 3)
+
+ worlds.fastForEach { world ->
+ val tags = mapOf("world" to world.name)
+ samples.add(GaugeMetric(Metrics.Server.WorldEntitiesCount, tags, world.entities.size))
+ samples.add(GaugeMetric(Metrics.Server.WorldPlayersCount, tags, world.players.size))
+ samples.add(GaugeMetric(Metrics.Server.WorldLoadedChunks, tags, world.loadedChunks.size))
+ }
+
+ return samples
+ }
+}
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/PaperWorldCollector.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/PaperWorldCollector.kt
new file mode 100644
index 00000000..156fa43b
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/PaperWorldCollector.kt
@@ -0,0 +1,41 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.world
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.api.util.fastForEach
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+
+class PaperWorldCollector(private val bootstrap: UnifiedMetricsBukkitBootstrap) : Collector {
+ override fun collect(): List {
+ val worlds = bootstrap.server.worlds
+ val samples = ArrayList(worlds.size * 3)
+
+ worlds.fastForEach { world ->
+ val tags = mapOf("world" to world.name)
+ samples.add(GaugeMetric(Metrics.Server.WorldEntitiesCount, tags, world.entityCount))
+ samples.add(GaugeMetric(Metrics.Server.WorldPlayersCount, tags, world.playerCount))
+ samples.add(GaugeMetric(Metrics.Server.WorldLoadedChunks, tags, world.chunkCount))
+ }
+
+ return samples
+ }
+}
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/WorldCollection.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/WorldCollection.kt
new file mode 100644
index 00000000..1cd9864f
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/metric/world/WorldCollection.kt
@@ -0,0 +1,33 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.metric.world
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+import dev.cubxity.plugins.metrics.bukkit.util.declaredMethodExists
+
+class WorldCollection(bootstrap: UnifiedMetricsBukkitBootstrap) : CollectorCollection {
+ private val collector = if (declaredMethodExists("org.bukkit.World", "getEntityCount")) {
+ PaperWorldCollector(bootstrap)
+ } else {
+ BukkitWorldCollector(bootstrap)
+ }
+
+ override val collectors: List = listOf(collector)
+}
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/BukkitPlatform.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/BukkitPlatform.kt
new file mode 100644
index 00000000..aec8dd4d
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/BukkitPlatform.kt
@@ -0,0 +1,32 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.util
+
+enum class BukkitPlatform {
+ Bukkit,
+ Paper,
+ Folia;
+
+ companion object {
+ val current = when {
+ classExists("io.papermc.paper.threadedregions.RegionizedServer") -> Folia
+ classExists("com.destroystokyo.paper.event.server.ServerTickStartEvent") -> Paper
+ else -> Bukkit
+ }
+ }
+}
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/ClassUtils.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/ClassUtils.kt
new file mode 100644
index 00000000..907a4812
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/ClassUtils.kt
@@ -0,0 +1,32 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.util
+
+fun classExists(className: String): Boolean = try {
+ Class.forName(className)
+ true
+} catch (e: ClassNotFoundException) {
+ false
+}
+
+fun declaredMethodExists(className: String, methodName: String, vararg parameterTypes: Class<*>): Boolean = try {
+ Class.forName(className).getDeclaredMethod(methodName, *parameterTypes)
+ true
+} catch (e: ReflectiveOperationException) {
+ false
+}
diff --git a/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/FoliaExt.kt b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/FoliaExt.kt
new file mode 100644
index 00000000..05ffbd8b
--- /dev/null
+++ b/platforms/bukkit/bin/main/dev/cubxity/plugins/metrics/bukkit/util/FoliaExt.kt
@@ -0,0 +1,27 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bukkit.util
+
+import io.papermc.paper.threadedregions.ThreadedRegionizer
+import io.papermc.paper.threadedregions.TickRegions.TickRegionData
+import io.papermc.paper.threadedregions.TickRegions.TickRegionSectionData
+import org.bukkit.World
+import org.bukkit.craftbukkit.CraftWorld;
+
+val World.regioniser: ThreadedRegionizer
+ get() = (this as CraftWorld).handle.regioniser
diff --git a/platforms/bukkit/bin/main/plugin.yml b/platforms/bukkit/bin/main/plugin.yml
new file mode 100644
index 00000000..bf6c80fd
--- /dev/null
+++ b/platforms/bukkit/bin/main/plugin.yml
@@ -0,0 +1,8 @@
+name: UnifiedMetrics
+main: dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
+description: "Fully-featured metrics plugin for Minecraft servers"
+api-version: 1.21
+folia-supported: true
+author: Cubxity
+version: ${version}
+load: STARTUP
\ No newline at end of file
diff --git a/platforms/bukkit/build.gradle.kts b/platforms/bukkit/build.gradle.kts
index 75bed03a..1b64ceb4 100644
--- a/platforms/bukkit/build.gradle.kts
+++ b/platforms/bukkit/build.gradle.kts
@@ -17,7 +17,7 @@
plugins {
id("com.github.johnrengelman.shadow")
- id("io.papermc.paperweight.userdev") version "1.5.3"
+ id("io.papermc.paperweight.userdev") version "2.0.0-beta.8"
}
repositories {
@@ -27,14 +27,11 @@ repositories {
dependencies {
api(project(":unifiedmetrics-core"))
-// compileOnly("com.destroystokyo.paper", "paper-api", "1.16.5-R0.1-SNAPSHOT")
- paperweight.devBundle("dev.folia", "1.20.1-R0.1-SNAPSHOT")
+ // compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
+ paperweight.devBundle("dev.folia", "1.21.4-R0.1-SNAPSHOT")
}
tasks {
- assemble {
- dependsOn(reobfJar)
- }
shadowJar {
archiveClassifier.set("")
relocate("retrofit2", "dev.cubxity.plugins.metrics.libs.retrofit2")
@@ -43,6 +40,10 @@ tasks {
relocate("okhttp", "dev.cubxity.plugins.metrics.libs.okhttp")
relocate("okio", "dev.cubxity.plugins.metrics.libs.okio")
relocate("io.prometheus", "dev.cubxity.plugins.metrics.libs.io.prometheus")
+
+ manifest {
+ attributes(mapOf("paperweight-mappings-namespace" to "mojang"))
+ }
}
processResources {
filesMatching("plugin.yml") {
diff --git a/platforms/bukkit/src/main/kotlin/dev/cubxity/plugins/metrics/bukkit/util/FoliaExt.kt b/platforms/bukkit/src/main/kotlin/dev/cubxity/plugins/metrics/bukkit/util/FoliaExt.kt
index 85f98282..05ffbd8b 100644
--- a/platforms/bukkit/src/main/kotlin/dev/cubxity/plugins/metrics/bukkit/util/FoliaExt.kt
+++ b/platforms/bukkit/src/main/kotlin/dev/cubxity/plugins/metrics/bukkit/util/FoliaExt.kt
@@ -21,7 +21,7 @@ import io.papermc.paper.threadedregions.ThreadedRegionizer
import io.papermc.paper.threadedregions.TickRegions.TickRegionData
import io.papermc.paper.threadedregions.TickRegions.TickRegionSectionData
import org.bukkit.World
-import org.bukkit.craftbukkit.v1_20_R1.CraftWorld
+import org.bukkit.craftbukkit.CraftWorld;
val World.regioniser: ThreadedRegionizer
get() = (this as CraftWorld).handle.regioniser
diff --git a/platforms/bukkit/src/main/resources/plugin.yml b/platforms/bukkit/src/main/resources/plugin.yml
index d336f5cb..bf6c80fd 100644
--- a/platforms/bukkit/src/main/resources/plugin.yml
+++ b/platforms/bukkit/src/main/resources/plugin.yml
@@ -1,7 +1,7 @@
name: UnifiedMetrics
main: dev.cubxity.plugins.metrics.bukkit.bootstrap.UnifiedMetricsBukkitBootstrap
description: "Fully-featured metrics plugin for Minecraft servers"
-api-version: 1.16
+api-version: 1.21
folia-supported: true
author: Cubxity
version: ${version}
diff --git a/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/UnifiedMetricsBungeePlugin.kt b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/UnifiedMetricsBungeePlugin.kt
new file mode 100644
index 00000000..56a24511
--- /dev/null
+++ b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/UnifiedMetricsBungeePlugin.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bungee
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.bungee.bootstrap.UnifiedMetricsBungeeBootstrap
+import dev.cubxity.plugins.metrics.bungee.metric.events.EventsCollection
+import dev.cubxity.plugins.metrics.bungee.metric.server.ServerCollection
+import dev.cubxity.plugins.metrics.core.plugin.CoreUnifiedMetricsPlugin
+
+class UnifiedMetricsBungeePlugin(
+ override val bootstrap: UnifiedMetricsBungeeBootstrap
+) : CoreUnifiedMetricsPlugin() {
+ override fun registerPlatformService(api: UnifiedMetrics) {
+ // Bungee doesn't have a service manager
+ }
+
+ override fun registerPlatformMetrics() {
+ super.registerPlatformMetrics()
+
+ apiProvider.metricsManager.apply {
+ with(config.metrics.collectors) {
+ if (server) registerCollection(ServerCollection(bootstrap))
+ if (events) registerCollection(EventsCollection(bootstrap))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/bootstrap/UnifiedMetricsBungeeBootstrap.kt b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/bootstrap/UnifiedMetricsBungeeBootstrap.kt
new file mode 100644
index 00000000..4f6cb5bf
--- /dev/null
+++ b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/bootstrap/UnifiedMetricsBungeeBootstrap.kt
@@ -0,0 +1,58 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bungee.bootstrap
+
+import dev.cubxity.plugins.metrics.api.platform.PlatformType
+import dev.cubxity.plugins.metrics.bungee.UnifiedMetricsBungeePlugin
+import dev.cubxity.plugins.metrics.common.UnifiedMetricsBootstrap
+import dev.cubxity.plugins.metrics.common.plugin.dispatcher.CurrentThreadDispatcher
+import dev.cubxity.plugins.metrics.common.plugin.logger.JavaLogger
+import kotlinx.coroutines.CoroutineDispatcher
+import net.md_5.bungee.api.plugin.Plugin
+import java.nio.file.Path
+
+class UnifiedMetricsBungeeBootstrap : Plugin(), UnifiedMetricsBootstrap {
+ private val plugin = UnifiedMetricsBungeePlugin(this)
+
+ override val type: PlatformType
+ get() = PlatformType.BungeeCord
+
+ override val version: String
+ get() = description.version
+
+ override val serverBrand: String
+ get() = proxy.name
+
+ override val dataDirectory: Path
+ get() = dataFolder.toPath()
+
+ override val configDirectory: Path
+ get() = dataFolder.toPath()
+
+ override val logger = JavaLogger(getLogger())
+
+ override val dispatcher: CoroutineDispatcher = CurrentThreadDispatcher
+
+ override fun onEnable() {
+ plugin.enable()
+ }
+
+ override fun onDisable() {
+ plugin.disable()
+ }
+}
\ No newline at end of file
diff --git a/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/events/EventsCollection.kt b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/events/EventsCollection.kt
new file mode 100644
index 00000000..eeb7e0c1
--- /dev/null
+++ b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/events/EventsCollection.kt
@@ -0,0 +1,72 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bungee.metric.events
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Counter
+import dev.cubxity.plugins.metrics.api.metric.store.VolatileDoubleStore
+import dev.cubxity.plugins.metrics.bungee.bootstrap.UnifiedMetricsBungeeBootstrap
+import net.md_5.bungee.api.event.*
+import net.md_5.bungee.api.plugin.Listener
+import net.md_5.bungee.event.EventHandler
+
+@Suppress("UNUSED_PARAMETER")
+class EventsCollection(private val bootstrap: UnifiedMetricsBungeeBootstrap) : CollectorCollection, Listener {
+ private val loginCounter = Counter("minecraft_events_login_total")
+ private val joinCounter = Counter("minecraft_events_join_total", valueStoreFactory = VolatileDoubleStore)
+ private val quitCounter = Counter("minecraft_events_quit_total", valueStoreFactory = VolatileDoubleStore)
+ private val chatCounter = Counter("minecraft_events_chat_total", valueStoreFactory = VolatileDoubleStore)
+ private val pingCounter = Counter("minecraft_events_ping_total")
+
+ override val collectors: List =
+ listOf(loginCounter, joinCounter, quitCounter, chatCounter, pingCounter)
+
+ override fun initialize() {
+ bootstrap.proxy.pluginManager.registerListener(bootstrap, this)
+ }
+
+ override fun dispose() {
+ bootstrap.proxy.pluginManager.unregisterListener(this)
+ }
+
+ @EventHandler
+ fun onLogin(event: PreLoginEvent) {
+ loginCounter.inc()
+ }
+
+ @EventHandler
+ fun onJoin(event: PostLoginEvent) {
+ joinCounter.inc()
+ }
+
+ @EventHandler
+ fun onQuit(event: PlayerDisconnectEvent) {
+ quitCounter.inc()
+ }
+
+ @EventHandler
+ fun onChat(event: ChatEvent) {
+ chatCounter.inc()
+ }
+
+ @EventHandler
+ fun onPing(event: ProxyPingEvent) {
+ pingCounter.inc()
+ }
+}
\ No newline at end of file
diff --git a/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/server/ServerCollection.kt b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/server/ServerCollection.kt
new file mode 100644
index 00000000..544ecc0d
--- /dev/null
+++ b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/server/ServerCollection.kt
@@ -0,0 +1,26 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bungee.metric.server
+
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.bungee.bootstrap.UnifiedMetricsBungeeBootstrap
+
+class ServerCollection(bootstrap: UnifiedMetricsBungeeBootstrap) : CollectorCollection {
+ override val collectors: List = listOf(ServerCollector(bootstrap))
+}
\ No newline at end of file
diff --git a/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/server/ServerCollector.kt b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/server/ServerCollector.kt
new file mode 100644
index 00000000..2145a077
--- /dev/null
+++ b/platforms/bungee/bin/main/dev/cubxity/plugins/metrics/bungee/metric/server/ServerCollector.kt
@@ -0,0 +1,34 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.bungee.metric.server
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.bungee.bootstrap.UnifiedMetricsBungeeBootstrap
+
+class ServerCollector(private val bootstrap: UnifiedMetricsBungeeBootstrap) : Collector {
+ override fun collect(): List {
+ val proxy = bootstrap.proxy
+ return listOf(
+ GaugeMetric("minecraft_plugins", value = proxy.pluginManager.plugins.size),
+ GaugeMetric("minecraft_players_count", value = proxy.onlineCount),
+ GaugeMetric("minecraft_players_max", value = proxy.config.playerLimit)
+ )
+ }
+}
\ No newline at end of file
diff --git a/platforms/bungee/bin/main/plugin.yml b/platforms/bungee/bin/main/plugin.yml
new file mode 100644
index 00000000..be91f537
--- /dev/null
+++ b/platforms/bungee/bin/main/plugin.yml
@@ -0,0 +1,5 @@
+name: UnifiedMetrics
+main: dev.cubxity.plugins.metrics.bungee.bootstrap.UnifiedMetricsBungeeBootstrap
+description: "Fully-featured metrics plugin for Minecraft servers"
+author: Cubxity
+version: ${version}
\ No newline at end of file
diff --git a/platforms/bungee/build.gradle.kts b/platforms/bungee/build.gradle.kts
index 7e336d01..5d22ff8b 100644
--- a/platforms/bungee/build.gradle.kts
+++ b/platforms/bungee/build.gradle.kts
@@ -21,12 +21,13 @@ plugins {
repositories {
maven("https://oss.sonatype.org/content/repositories/snapshots/")
+ maven("https://libraries.minecraft.net")
}
dependencies {
api(project(":unifiedmetrics-core"))
- compileOnly("net.md-5", "bungeecord-api", "1.20-R0.1")
+ compileOnly("net.md-5", "bungeecord-api", "1.21-R0.1-SNAPSHOT")
}
tasks {
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/UnifiedMetricsFabricPlugin.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/UnifiedMetricsFabricPlugin.kt
new file mode 100644
index 00000000..39365f9c
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/UnifiedMetricsFabricPlugin.kt
@@ -0,0 +1,49 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.core.plugin.CoreUnifiedMetricsPlugin
+import dev.cubxity.plugins.metrics.fabric.bootstrap.UnifiedMetricsFabricBootstrap
+import dev.cubxity.plugins.metrics.fabric.metrics.events.EventsCollection
+import dev.cubxity.plugins.metrics.fabric.metrics.server.ServerCollection
+import dev.cubxity.plugins.metrics.fabric.metrics.tick.TickCollection
+import dev.cubxity.plugins.metrics.fabric.metrics.world.WorldCollection
+import java.util.concurrent.Executors
+
+class UnifiedMetricsFabricPlugin(
+ override val bootstrap: UnifiedMetricsFabricBootstrap
+): CoreUnifiedMetricsPlugin() {
+
+ override fun registerPlatformService(api: UnifiedMetrics) {
+
+ }
+
+ override fun registerPlatformMetrics() {
+ super.registerPlatformMetrics()
+
+ apiProvider.metricsManager.apply {
+ with(config.metrics.collectors) {
+ if (server) registerCollection(ServerCollection(bootstrap))
+ if (world) registerCollection(WorldCollection(bootstrap))
+ if (tick) registerCollection(TickCollection())
+ if (events) registerCollection(EventsCollection())
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/bootstrap/UnifiedMetricsFabricBootstrap.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/bootstrap/UnifiedMetricsFabricBootstrap.kt
new file mode 100644
index 00000000..a102dd92
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/bootstrap/UnifiedMetricsFabricBootstrap.kt
@@ -0,0 +1,66 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.bootstrap
+
+import dev.cubxity.plugins.metrics.api.platform.PlatformType
+import dev.cubxity.plugins.metrics.common.UnifiedMetricsBootstrap
+import dev.cubxity.plugins.metrics.common.plugin.dispatcher.CurrentThreadDispatcher
+import dev.cubxity.plugins.metrics.fabric.UnifiedMetricsFabricPlugin
+import dev.cubxity.plugins.metrics.fabric.logger.Log4jLogger
+import kotlinx.coroutines.CoroutineDispatcher
+import net.fabricmc.api.DedicatedServerModInitializer
+import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents
+import net.fabricmc.loader.api.FabricLoader
+import net.minecraft.server.MinecraftServer
+import org.apache.logging.log4j.LogManager
+import java.nio.file.Path
+import kotlin.jvm.optionals.getOrNull
+
+class UnifiedMetricsFabricBootstrap : DedicatedServerModInitializer, UnifiedMetricsBootstrap {
+ private val plugin = UnifiedMetricsFabricPlugin(this)
+ lateinit var server: MinecraftServer
+
+ override val type: PlatformType
+ get() = PlatformType.Fabric
+
+ override val version: String = FabricLoader.getInstance()
+ .getModContainer("unifiedmetrics").getOrNull()
+ ?.metadata?.version?.friendlyString ?: ""
+
+ override val serverBrand: String
+ get() = server.serverModName
+
+ override val dataDirectory: Path = FabricLoader.getInstance().configDir.resolve("unifiedmetrics")
+
+ override val configDirectory: Path = FabricLoader.getInstance().configDir.resolve("unifiedmetrics")
+
+ override val logger = Log4jLogger(LogManager.getLogger("UnifiedMetrics"))
+
+ override val dispatcher: CoroutineDispatcher = CurrentThreadDispatcher
+
+ override fun onInitializeServer() {
+ ServerLifecycleEvents.SERVER_STARTED.register {
+ server = it
+ plugin.enable()
+ }
+
+ ServerLifecycleEvents.SERVER_STOPPING.register {
+ plugin.disable()
+ }
+ }
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/ChatEvent.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/ChatEvent.kt
new file mode 100644
index 00000000..ac4d7c83
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/ChatEvent.kt
@@ -0,0 +1,35 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.events
+
+import net.fabricmc.fabric.api.event.Event
+import net.fabricmc.fabric.api.event.EventFactory
+
+fun interface ChatEvent {
+
+ fun onChat()
+
+ companion object {
+ val event: Event = EventFactory.createArrayBacked(ChatEvent::class.java) { events ->
+ ChatEvent {
+ events.forEach(ChatEvent::onChat)
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/PingEvent.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/PingEvent.kt
new file mode 100644
index 00000000..dad3b23d
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/PingEvent.kt
@@ -0,0 +1,35 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.events
+
+import net.fabricmc.fabric.api.event.Event
+import net.fabricmc.fabric.api.event.EventFactory
+
+fun interface PingEvent {
+
+ fun onPing()
+
+ companion object {
+ val event: Event = EventFactory.createArrayBacked(PingEvent::class.java) { events ->
+ PingEvent {
+ events.forEach(PingEvent::onPing)
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/TickEvent.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/TickEvent.kt
new file mode 100644
index 00000000..26ad7a03
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/events/TickEvent.kt
@@ -0,0 +1,37 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.events
+
+import net.fabricmc.fabric.api.event.Event
+import net.fabricmc.fabric.api.event.EventFactory
+
+fun interface TickEvent {
+
+ fun onTick(tickTime: Double)
+
+ companion object {
+
+ val event: Event = EventFactory.createArrayBacked(TickEvent::class.java) { events ->
+ TickEvent { tickTime ->
+ events.forEach { it.onTick(tickTime) }
+ }
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/logger/Log4jLogger.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/logger/Log4jLogger.kt
new file mode 100644
index 00000000..d15fb9d6
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/logger/Log4jLogger.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.logger
+
+import dev.cubxity.plugins.metrics.api.logging.Logger
+import org.apache.logging.log4j.Level
+
+class Log4jLogger(private val logger: org.apache.logging.log4j.Logger): Logger {
+ override fun info(message: String) {
+ logger.log(Level.INFO, message)
+ }
+
+ override fun warn(message: String) {
+ logger.log(Level.WARN, message)
+ }
+
+ override fun warn(message: String, error: Throwable) {
+ logger.log(Level.WARN, message, error)
+ }
+
+ override fun severe(message: String) {
+ logger.log(Level.ERROR, message)
+ }
+
+ override fun severe(message: String, error: Throwable) {
+ logger.log(Level.ERROR, message, error)
+ }
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/events/EventsCollection.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/events/EventsCollection.kt
new file mode 100644
index 00000000..7c7c7ef7
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/events/EventsCollection.kt
@@ -0,0 +1,57 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.metrics.events
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Counter
+import dev.cubxity.plugins.metrics.api.metric.store.VolatileDoubleStore
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+import dev.cubxity.plugins.metrics.fabric.events.ChatEvent
+import dev.cubxity.plugins.metrics.fabric.events.PingEvent
+import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents
+import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents
+
+class EventsCollection : CollectorCollection {
+ private val loginCounter = Counter(Metrics.Events.Login)
+ private val joinCounter = Counter(Metrics.Events.Join)
+ private val quitCounter = Counter(Metrics.Events.Quit)
+ private val chatCounter = Counter(Metrics.Events.Chat, valueStoreFactory = VolatileDoubleStore)
+ private val pingCounter = Counter(Metrics.Events.Ping)
+
+ override val collectors: List =
+ listOf(loginCounter, joinCounter, quitCounter, chatCounter, pingCounter)
+
+ override fun initialize() {
+ ServerLoginConnectionEvents.INIT.register { _, _ ->
+ loginCounter.inc()
+ }
+ ServerPlayConnectionEvents.JOIN.register { _, _, _ ->
+ joinCounter.inc()
+ }
+ ServerPlayConnectionEvents.DISCONNECT.register { _, _ ->
+ quitCounter.inc()
+ }
+ ChatEvent.event.register {
+ chatCounter.inc()
+ }
+ PingEvent.event.register {
+ pingCounter.inc()
+ }
+ }
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/server/ServerCollection.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/server/ServerCollection.kt
new file mode 100644
index 00000000..13257673
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/server/ServerCollection.kt
@@ -0,0 +1,26 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.metrics.server
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.fabric.bootstrap.UnifiedMetricsFabricBootstrap
+
+class ServerCollection(bootstrap: UnifiedMetricsFabricBootstrap) : CollectorCollection {
+ override val collectors: List = listOf(ServerCollector(bootstrap))
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/server/ServerCollector.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/server/ServerCollector.kt
new file mode 100644
index 00000000..84aa3a6c
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/server/ServerCollector.kt
@@ -0,0 +1,36 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.metrics.server
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+import dev.cubxity.plugins.metrics.fabric.bootstrap.UnifiedMetricsFabricBootstrap
+import net.fabricmc.loader.api.FabricLoader
+
+class ServerCollector(private val bootstrap: UnifiedMetricsFabricBootstrap): Collector {
+ override fun collect(): List {
+ val server = bootstrap.server
+ return listOf(
+ GaugeMetric(Metrics.Server.Plugins, value = FabricLoader.getInstance().allMods.size),
+ GaugeMetric(Metrics.Server.PlayersCount, value = server.currentPlayerCount),
+ GaugeMetric(Metrics.Server.PlayersMax, value = server.maxPlayerCount)
+ )
+ }
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/tick/TickCollection.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/tick/TickCollection.kt
new file mode 100644
index 00000000..af85d389
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/tick/TickCollection.kt
@@ -0,0 +1,48 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.metrics.tick
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Histogram
+import dev.cubxity.plugins.metrics.api.metric.collector.MILLISECONDS_PER_SECOND
+import dev.cubxity.plugins.metrics.api.metric.store.VolatileDoubleStore
+import dev.cubxity.plugins.metrics.api.metric.store.VolatileLongStore
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+import dev.cubxity.plugins.metrics.fabric.events.TickEvent
+
+class TickCollection : CollectorCollection {
+ private val tickDuration = Histogram(
+ Metrics.Server.TickDurationSeconds,
+ sumStoreFactory = VolatileDoubleStore,
+ countStoreFactory = VolatileLongStore
+ )
+
+ override val collectors: List = listOf(tickDuration)
+
+
+ override fun initialize() {
+ TickEvent.event.register { duration ->
+ onTick(duration / MILLISECONDS_PER_SECOND)
+ }
+ }
+
+ fun onTick(duration: Double) {
+ tickDuration += duration
+ }
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/world/WorldCollection.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/world/WorldCollection.kt
new file mode 100644
index 00000000..88ebde12
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/world/WorldCollection.kt
@@ -0,0 +1,26 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.metrics.world
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.fabric.bootstrap.UnifiedMetricsFabricBootstrap
+
+class WorldCollection(bootstrap: UnifiedMetricsFabricBootstrap) : CollectorCollection {
+ override val collectors: List = listOf(WorldCollector(bootstrap))
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/world/WorldCollector.kt b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/world/WorldCollector.kt
new file mode 100644
index 00000000..31af9020
--- /dev/null
+++ b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/metrics/world/WorldCollector.kt
@@ -0,0 +1,40 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.metrics.world
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.common.metric.Metrics
+import dev.cubxity.plugins.metrics.fabric.bootstrap.UnifiedMetricsFabricBootstrap
+
+class WorldCollector(private val bootstrap: UnifiedMetricsFabricBootstrap) : Collector {
+ override fun collect(): List {
+ val worlds = bootstrap.server.worlds
+ val samples = ArrayList(worlds.count() * 3)
+
+ worlds.forEach { world ->
+ val tags = mapOf("world" to world.registryKey.value.toString())
+ samples.add(GaugeMetric(Metrics.Server.WorldEntitiesCount, tags, world.iterateEntities().count()))
+ samples.add(GaugeMetric(Metrics.Server.WorldPlayersCount, tags, world.players.size))
+ samples.add(GaugeMetric(Metrics.Server.WorldLoadedChunks, tags, world.chunkManager.loadedChunkCount))
+ }
+
+ return samples
+ }
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/MinecraftServerMixin.class b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/MinecraftServerMixin.class
new file mode 100644
index 00000000..3d403889
Binary files /dev/null and b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/MinecraftServerMixin.class differ
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/ServerPlayNetworkHandlerMixin.class b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/ServerPlayNetworkHandlerMixin.class
new file mode 100644
index 00000000..043763a2
Binary files /dev/null and b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/ServerPlayNetworkHandlerMixin.class differ
diff --git a/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/ServerQueryNetworkHandlerMixin.class b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/ServerQueryNetworkHandlerMixin.class
new file mode 100644
index 00000000..043e45ad
Binary files /dev/null and b/platforms/fabric/bin/main/dev/cubxity/plugins/metrics/fabric/mixins/ServerQueryNetworkHandlerMixin.class differ
diff --git a/platforms/fabric/bin/main/fabric.mod.json b/platforms/fabric/bin/main/fabric.mod.json
new file mode 100644
index 00000000..3637b6eb
--- /dev/null
+++ b/platforms/fabric/bin/main/fabric.mod.json
@@ -0,0 +1,35 @@
+{
+ "schemaVersion": 1,
+ "id": "unifiedmetrics",
+ "version": "${version}",
+
+ "name": "UnifiedMetrics",
+ "description": "Fully-featured metrics plugin for Minecraft servers",
+ "authors": [
+ "Cubxity"
+ ],
+ "contact": {
+ "homepage": "https://github.com/Cubxity/UnifiedMetrics/",
+ "sources": "https://github.com/Cubxity/UnifiedMetrics/",
+ "issues": "https://github.com/Cubxity/UnifiedMetrics/issues"
+ },
+
+ "license": "LGPL-3.0",
+
+ "environment": "server",
+ "entrypoints": {
+ "server": [
+ "dev.cubxity.plugins.metrics.fabric.bootstrap.UnifiedMetricsFabricBootstrap"
+ ]
+ },
+ "mixins": [
+ "unifiedmetrics.mixins.json"
+ ],
+
+ "depends": {
+ "fabricloader": ">=0.11.3",
+ "fabric": "*",
+ "minecraft": ">=1.16",
+ "fabric-language-kotlin": ">=1.6.0+kotlin.1.5.0"
+ }
+}
\ No newline at end of file
diff --git a/platforms/fabric/bin/main/unifiedmetrics.mixins.json b/platforms/fabric/bin/main/unifiedmetrics.mixins.json
new file mode 100644
index 00000000..984a76fa
--- /dev/null
+++ b/platforms/fabric/bin/main/unifiedmetrics.mixins.json
@@ -0,0 +1,11 @@
+{
+ "required": true,
+ "minVersion": "0.8",
+ "package": "dev.cubxity.plugins.metrics.fabric.mixins",
+ "compatibilityLevel": "JAVA_8",
+ "mixins": [
+ "ServerPlayNetworkHandlerMixin",
+ "ServerQueryNetworkHandlerMixin",
+ "MinecraftServerMixin"
+ ]
+}
\ No newline at end of file
diff --git a/platforms/fabric/build.gradle.kts b/platforms/fabric/build.gradle.kts
index 8d2fc2a4..917f91ae 100644
--- a/platforms/fabric/build.gradle.kts
+++ b/platforms/fabric/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
/*
* This file is part of UnifiedMetrics.
*
@@ -16,8 +18,7 @@
*/
plugins {
- id("fabric-loom") version "1.4.1"
- id("net.kyori.blossom")
+ id("fabric-loom")
}
val transitiveInclude: Configuration by configurations.creating {
@@ -28,12 +29,12 @@ val transitiveInclude: Configuration by configurations.creating {
dependencies {
// https://fabricmc.net/versions.html
- minecraft("com.mojang:minecraft:1.17.1")
- mappings("net.fabricmc:yarn:1.17.1+build.65:v2")
- modImplementation("net.fabricmc:fabric-loader:0.14.23")
+ minecraft("com.mojang:minecraft:1.21.4")
+ mappings("net.fabricmc:yarn:1.21.4+build.4")
+ modImplementation("net.fabricmc:fabric-loader:0.16.9")
- modImplementation("net.fabricmc.fabric-api:fabric-api:0.46.1+1.17")
- modImplementation("net.fabricmc:fabric-language-kotlin:1.10.10+kotlin.1.9.10")
+ modImplementation("net.fabricmc.fabric-api:fabric-api:0.113.0+1.21.4")
+ modImplementation("net.fabricmc:fabric-language-kotlin:1.11.0+kotlin.2.0.0")
api(project(":unifiedmetrics-core"))
@@ -55,11 +56,12 @@ loom {
isIdeConfigGenerated = true
}
}
+ serverOnlyMinecraftJar()
}
tasks {
compileKotlin {
- kotlinOptions.jvmTarget = "16"
+ compilerOptions.jvmTarget.set(JvmTarget.JVM_21)
}
processResources {
filesMatching("fabric.mod.json") {
@@ -74,11 +76,6 @@ tasks {
}
java {
- sourceCompatibility = JavaVersion.VERSION_16
- targetCompatibility = JavaVersion.VERSION_16
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
}
-
-blossom {
- replaceTokenIn("src/main/kotlin/dev/cubxity/plugins/metrics/fabric/bootstrap/UnifiedMetricsFabricBootstrap.kt")
- replaceToken("@version@", version)
-}
\ No newline at end of file
diff --git a/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/MinecraftServerMixin.java b/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/MinecraftServerMixin.java
new file mode 100644
index 00000000..32ca3ef6
--- /dev/null
+++ b/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/MinecraftServerMixin.java
@@ -0,0 +1,69 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.mixins;
+
+import dev.cubxity.plugins.metrics.fabric.events.TickEvent;
+import net.minecraft.server.MinecraftServer;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import static dev.cubxity.plugins.metrics.api.metric.collector.CollectorKt.NANOSECONDS_PER_MILLISECOND;
+import static dev.cubxity.plugins.metrics.api.metric.collector.CollectorKt.NANOSECONDS_PER_SECOND;
+
+/**
+ * Designed to emulate paper's tick event as closely as possible
+ * however some changes had to be made to work with fabric-carpet
+ */
+@Mixin(MinecraftServer.class)
+public class MinecraftServerMixin {
+
+ private long lastTick = 0;
+
+ @Inject(
+ method = "runServer",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/server/MinecraftServer;setFavicon(Lnet/minecraft/server/ServerMetadata;)V"
+ )
+ )
+ private void onRunServerBeforeLoop(CallbackInfo ci) {
+ lastTick = System.nanoTime() - ((long) NANOSECONDS_PER_SECOND / 20);
+ }
+
+ @Inject(
+ method = "tick",
+ at = @At("HEAD")
+ )
+ private void onTickStart(CallbackInfo ci) {
+ lastTick = System.nanoTime();
+ }
+
+ @Inject(
+ method = "tick",
+ at = @At(
+ value = "CONSTANT",
+ args = "stringValue=tallying"
+ )
+ )
+ private void onTickEnd(CallbackInfo ci) {
+ TickEvent.Companion.getEvent().invoker().onTick((double)(System.nanoTime() - lastTick) / NANOSECONDS_PER_MILLISECOND);
+ }
+
+}
diff --git a/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/ServerPlayNetworkHandlerMixin.java b/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/ServerPlayNetworkHandlerMixin.java
new file mode 100644
index 00000000..39cfb248
--- /dev/null
+++ b/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/ServerPlayNetworkHandlerMixin.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.mixins;
+
+import dev.cubxity.plugins.metrics.fabric.events.ChatEvent;
+import net.minecraft.server.network.ServerPlayNetworkHandler;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(ServerPlayNetworkHandler.class)
+public class ServerPlayNetworkHandlerMixin {
+
+ @Inject(method = "handleMessage", at = @At("HEAD"))
+ private void onHandleMessage(CallbackInfo ci) {
+ ChatEvent.Companion.getEvent().invoker().onChat();
+ }
+
+}
diff --git a/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/ServerQueryNetworkHandlerMixin.java b/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/ServerQueryNetworkHandlerMixin.java
new file mode 100644
index 00000000..ae99e618
--- /dev/null
+++ b/platforms/fabric/remappedSrc/dev/cubxity/plugins/metrics/fabric/mixins/ServerQueryNetworkHandlerMixin.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.fabric.mixins;
+
+import dev.cubxity.plugins.metrics.fabric.events.PingEvent;
+import net.minecraft.server.network.ServerQueryNetworkHandler;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(ServerQueryNetworkHandler.class)
+public class ServerQueryNetworkHandlerMixin {
+
+ @Inject(method = "onRequest", at = @At("HEAD"))
+ private void handleOnRequest(CallbackInfo ci) {
+ PingEvent.Companion.getEvent().invoker().onPing();
+ }
+
+}
diff --git a/platforms/minestom/build.gradle.kts b/platforms/minestom/build.gradle.kts
index 669620cc..ff1a8524 100644
--- a/platforms/minestom/build.gradle.kts
+++ b/platforms/minestom/build.gradle.kts
@@ -42,10 +42,10 @@ tasks {
relocate("io.prometheus", "dev.cubxity.plugins.metrics.libs.io.prometheus")
}
compileKotlin {
- kotlinOptions.jvmTarget = "17"
+ kotlinOptions.jvmTarget = "21"
}
compileTestKotlin {
- kotlinOptions.jvmTarget = "17"
+ kotlinOptions.jvmTarget = "21"
}
processResources {
filesMatching("extension.json") {
@@ -57,5 +57,5 @@ tasks {
}
java {
- targetCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_21
}
diff --git a/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/UnifiedMetricsVelocityPlugin.kt b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/UnifiedMetricsVelocityPlugin.kt
new file mode 100644
index 00000000..19e2fb63
--- /dev/null
+++ b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/UnifiedMetricsVelocityPlugin.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.velocity
+
+import dev.cubxity.plugins.metrics.api.UnifiedMetrics
+import dev.cubxity.plugins.metrics.core.plugin.CoreUnifiedMetricsPlugin
+import dev.cubxity.plugins.metrics.velocity.bootstrap.UnifiedMetricsVelocityBootstrap
+import dev.cubxity.plugins.metrics.velocity.metric.events.EventsCollection
+import dev.cubxity.plugins.metrics.velocity.metric.server.ServerCollection
+
+class UnifiedMetricsVelocityPlugin(
+ override val bootstrap: UnifiedMetricsVelocityBootstrap
+) : CoreUnifiedMetricsPlugin() {
+ override fun registerPlatformService(api: UnifiedMetrics) {
+ // Velocity doesn't have a service manager
+ }
+
+ override fun registerPlatformMetrics() {
+ super.registerPlatformMetrics()
+
+ apiProvider.metricsManager.apply {
+ with(config.metrics.collectors) {
+ if (server) registerCollection(ServerCollection(bootstrap))
+ if (events) registerCollection(EventsCollection(bootstrap))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/bootstrap/UnifiedMetricsVelocityBootstrap.kt b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/bootstrap/UnifiedMetricsVelocityBootstrap.kt
new file mode 100644
index 00000000..91a3df82
--- /dev/null
+++ b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/bootstrap/UnifiedMetricsVelocityBootstrap.kt
@@ -0,0 +1,78 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.velocity.bootstrap
+
+import com.google.inject.Inject
+import com.velocitypowered.api.event.PostOrder
+import com.velocitypowered.api.event.Subscribe
+import com.velocitypowered.api.event.proxy.ProxyInitializeEvent
+import com.velocitypowered.api.event.proxy.ProxyShutdownEvent
+import com.velocitypowered.api.plugin.Plugin
+import com.velocitypowered.api.plugin.PluginDescription
+import com.velocitypowered.api.plugin.annotation.DataDirectory
+import com.velocitypowered.api.proxy.ProxyServer
+import dev.cubxity.plugins.metrics.api.platform.PlatformType
+import dev.cubxity.plugins.metrics.common.UnifiedMetricsBootstrap
+import dev.cubxity.plugins.metrics.common.plugin.dispatcher.CurrentThreadDispatcher
+import dev.cubxity.plugins.metrics.velocity.UnifiedMetricsVelocityPlugin
+import dev.cubxity.plugins.metrics.velocity.logger.Slf4jLogger
+import kotlinx.coroutines.CoroutineDispatcher
+import java.nio.file.Path
+import kotlin.jvm.optionals.getOrDefault
+
+@Plugin(
+ id = "unifiedmetrics",
+ name = "UnifiedMetrics",
+ description = "Fully-featured metrics plugin for Minecraft servers",
+ authors = ["Cubxity"]
+)
+class UnifiedMetricsVelocityBootstrap @Inject constructor(
+ @DataDirectory
+ override val dataDirectory: Path,
+ val server: ProxyServer,
+ pluginLogger: org.slf4j.Logger,
+ private val description: PluginDescription,
+) : UnifiedMetricsBootstrap {
+ private val plugin = UnifiedMetricsVelocityPlugin(this)
+
+ override val type: PlatformType
+ get() = PlatformType.Velocity
+
+ override val version: String
+ get() = description.version.getOrDefault("")
+
+ override val serverBrand: String
+ get() = server.version.name
+
+ override val configDirectory: Path
+ get() = dataDirectory
+
+ override val logger = Slf4jLogger(pluginLogger)
+
+ override val dispatcher: CoroutineDispatcher = CurrentThreadDispatcher
+
+ @Subscribe(order = PostOrder.FIRST)
+ fun onEnable(event: ProxyInitializeEvent) {
+ plugin.enable()
+ }
+
+ @Subscribe(order = PostOrder.LAST)
+ fun onDisable(event: ProxyShutdownEvent) {
+ plugin.disable()
+ }
+}
\ No newline at end of file
diff --git a/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/logger/Slf4jLogger.kt b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/logger/Slf4jLogger.kt
new file mode 100644
index 00000000..b7bd3f5b
--- /dev/null
+++ b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/logger/Slf4jLogger.kt
@@ -0,0 +1,42 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.velocity.logger
+
+import dev.cubxity.plugins.metrics.api.logging.Logger
+
+class Slf4jLogger(private val logger: org.slf4j.Logger) : Logger {
+ override fun info(message: String) {
+ logger.info(message)
+ }
+
+ override fun warn(message: String) {
+ logger.warn(message)
+ }
+
+ override fun warn(message: String, error: Throwable) {
+ logger.warn(message, error)
+ }
+
+ override fun severe(message: String) {
+ logger.error(message)
+ }
+
+ override fun severe(message: String, error: Throwable) {
+ logger.error(message, error)
+ }
+}
\ No newline at end of file
diff --git a/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/events/EventsCollection.kt b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/events/EventsCollection.kt
new file mode 100644
index 00000000..703272ae
--- /dev/null
+++ b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/events/EventsCollection.kt
@@ -0,0 +1,75 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.velocity.metric.events
+
+import com.velocitypowered.api.event.Subscribe
+import com.velocitypowered.api.event.connection.DisconnectEvent
+import com.velocitypowered.api.event.connection.PreLoginEvent
+import com.velocitypowered.api.event.player.PlayerChatEvent
+import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent
+import com.velocitypowered.api.event.proxy.ProxyPingEvent
+import dev.cubxity.plugins.metrics.api.metric.collector.Counter
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.velocity.bootstrap.UnifiedMetricsVelocityBootstrap
+
+@Suppress("UNUSED_PARAMETER")
+class EventsCollection(private val bootstrap: UnifiedMetricsVelocityBootstrap) : CollectorCollection {
+ private val loginCounter = Counter("minecraft_events_login_total")
+ private val joinCounter = Counter("minecraft_events_join_total")
+ private val quitCounter = Counter("minecraft_events_quit_total")
+ private val chatCounter = Counter("minecraft_events_chat_total")
+ private val pingCounter = Counter("minecraft_events_ping_total")
+
+ override val collectors: List =
+ listOf(loginCounter, joinCounter, quitCounter, chatCounter, pingCounter)
+
+ override fun initialize() {
+ bootstrap.server.eventManager.register(bootstrap, this)
+ }
+
+ override fun dispose() {
+ bootstrap.server.eventManager.unregisterListener(bootstrap, this)
+ }
+
+
+ @Subscribe
+ fun onLogin(event: PreLoginEvent) {
+ loginCounter.inc()
+ }
+
+ @Subscribe
+ fun onConnect(event: PlayerChooseInitialServerEvent) {
+ joinCounter.inc()
+ }
+
+ @Subscribe
+ fun onDisconnect(event: DisconnectEvent) {
+ quitCounter.inc()
+ }
+
+ @Subscribe
+ fun onChat(event: PlayerChatEvent) {
+ chatCounter.inc()
+ }
+
+ @Subscribe
+ fun onPing(event: ProxyPingEvent) {
+ pingCounter.inc()
+ }
+}
\ No newline at end of file
diff --git a/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/server/ServerCollection.kt b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/server/ServerCollection.kt
new file mode 100644
index 00000000..9c8ee54b
--- /dev/null
+++ b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/server/ServerCollection.kt
@@ -0,0 +1,26 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.velocity.metric.server
+
+import dev.cubxity.plugins.metrics.api.metric.collector.CollectorCollection
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.velocity.bootstrap.UnifiedMetricsVelocityBootstrap
+
+class ServerCollection(bootstrap: UnifiedMetricsVelocityBootstrap) : CollectorCollection {
+ override val collectors: List = listOf(ServerCollector(bootstrap))
+}
\ No newline at end of file
diff --git a/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/server/ServerCollector.kt b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/server/ServerCollector.kt
new file mode 100644
index 00000000..cd404a80
--- /dev/null
+++ b/platforms/velocity/bin/main/dev/cubxity/plugins/metrics/velocity/metric/server/ServerCollector.kt
@@ -0,0 +1,34 @@
+/*
+ * This file is part of UnifiedMetrics.
+ *
+ * UnifiedMetrics is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * UnifiedMetrics is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with UnifiedMetrics. If not, see .
+ */
+
+package dev.cubxity.plugins.metrics.velocity.metric.server
+
+import dev.cubxity.plugins.metrics.api.metric.collector.Collector
+import dev.cubxity.plugins.metrics.api.metric.data.GaugeMetric
+import dev.cubxity.plugins.metrics.api.metric.data.Metric
+import dev.cubxity.plugins.metrics.velocity.bootstrap.UnifiedMetricsVelocityBootstrap
+
+class ServerCollector(private val bootstrap: UnifiedMetricsVelocityBootstrap) : Collector {
+ override fun collect(): List {
+ val server = bootstrap.server
+ return listOf(
+ GaugeMetric("minecraft_plugins", value = server.pluginManager.plugins.size),
+ GaugeMetric("minecraft_players_count", value = server.playerCount),
+ GaugeMetric("minecraft_players_max", value = server.configuration.showMaxPlayers)
+ )
+ }
+}
\ No newline at end of file
diff --git a/platforms/velocity/bin/main/velocity-plugin.json b/platforms/velocity/bin/main/velocity-plugin.json
new file mode 100644
index 00000000..2811a9b1
--- /dev/null
+++ b/platforms/velocity/bin/main/velocity-plugin.json
@@ -0,0 +1,11 @@
+{
+ "id": "unifiedmetrics",
+ "name": "UnifiedMetrics",
+ "version": "${version}",
+ "description": "Fully-featured metrics plugin for Minecraft servers",
+ "authors": [
+ "Cubxity"
+ ],
+ "dependencies": [],
+ "main": "dev.cubxity.plugins.metrics.velocity.bootstrap.UnifiedMetricsVelocityBootstrap"
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 3daa9cf9..8d91924d 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -26,7 +26,7 @@ include(modulePrefix + "common")
include(modulePrefix + "core")
include(modulePrefix + platformPrefix + "bukkit")
-include(modulePrefix + platformPrefix + "minestom")
+//include(modulePrefix + platformPrefix + "minestom")
include(modulePrefix + platformPrefix + "velocity")
include(modulePrefix + platformPrefix + "bungee")
include(modulePrefix + platformPrefix + "fabric")
@@ -40,7 +40,7 @@ project(modulePrefix + "core").projectDir = File(rootDir, "core")
val platformsDir = File(rootDir, "platforms")
project(modulePrefix + platformPrefix + "bukkit").projectDir = File(platformsDir, "bukkit")
-project(modulePrefix + platformPrefix + "minestom").projectDir = File(platformsDir, "minestom")
+//project(modulePrefix + platformPrefix + "minestom").projectDir = File(platformsDir, "minestom")
project(modulePrefix + platformPrefix + "velocity").projectDir = File(platformsDir, "velocity")
project(modulePrefix + platformPrefix + "bungee").projectDir = File(platformsDir, "bungee")
project(modulePrefix + platformPrefix + "fabric").projectDir = File(platformsDir, "fabric")
@@ -58,3 +58,10 @@ pluginManagement {
}
}
}
+
+
+
+plugins {
+ id("org.gradle.toolchains.foojay-resolver-convention") version("0.8.0")
+}
+