add basic metrics impl
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m32s
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m32s
This commit is contained in:
121
src/main/java/xyz/mcutils/backend/service/MetricService.java
Normal file
121
src/main/java/xyz/mcutils/backend/service/MetricService.java
Normal file
@ -0,0 +1,121 @@
|
||||
package xyz.mcutils.backend.service;
|
||||
|
||||
import com.influxdb.client.WriteApiBlocking;
|
||||
import com.influxdb.spring.influx.InfluxDB2AutoConfiguration;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import xyz.mcutils.backend.common.Timer;
|
||||
import xyz.mcutils.backend.repository.MetricsRepository;
|
||||
import xyz.mcutils.backend.service.metric.Metric;
|
||||
import xyz.mcutils.backend.service.metric.metrics.RequestsPerRouteMetric;
|
||||
import xyz.mcutils.backend.service.metric.metrics.TotalRequestsMetric;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service @Log4j2
|
||||
public class MetricService {
|
||||
/**
|
||||
* The metrics that are registered.
|
||||
*/
|
||||
private final Map<Class<?>, Metric<?>> metrics = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The interval in which the metrics are saved.
|
||||
*/
|
||||
private final long saveInterval = TimeUnit.MINUTES.toMillis(1);
|
||||
|
||||
/**
|
||||
* The interval in which the metrics are written to InfluxDB.
|
||||
*/
|
||||
private final long writeInfluxInterval = TimeUnit.SECONDS.toMillis(30);
|
||||
|
||||
private final WriteApiBlocking influxWriteApi;
|
||||
private final MetricsRepository metricsRepository;
|
||||
|
||||
@Autowired
|
||||
public MetricService(InfluxDB2AutoConfiguration influxAutoConfiguration, MetricsRepository metricsRepository) {
|
||||
this.influxWriteApi = influxAutoConfiguration.influxDBClient().getWriteApiBlocking();
|
||||
this.metricsRepository = metricsRepository;
|
||||
|
||||
// Register the metrics
|
||||
registerMetric(new TotalRequestsMetric());
|
||||
registerMetric(new RequestsPerRouteMetric());
|
||||
|
||||
// Load the metrics from Redis
|
||||
loadMetrics();
|
||||
|
||||
Timer.scheduleRepeating(this::saveMetrics, saveInterval, saveInterval);
|
||||
Timer.scheduleRepeating(this::writeToInflux, writeInfluxInterval, writeInfluxInterval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a metric.
|
||||
*
|
||||
* @param metric the metric to register
|
||||
*/
|
||||
public void registerMetric(Metric<?> metric) {
|
||||
if (metrics.containsKey(metric.getClass())) {
|
||||
throw new IllegalArgumentException("A metric with the class " + metric.getClass().getName() + " is already registered");
|
||||
}
|
||||
metrics.put(metric.getClass(), metric);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a metric by its class.
|
||||
*
|
||||
* @param clazz the class of the metric
|
||||
* @return the metric
|
||||
* @throws IllegalArgumentException if there is no metric with the class registered
|
||||
*/
|
||||
public Metric<?> getMetric(Class<?> clazz) throws IllegalArgumentException {
|
||||
if (!metrics.containsKey(clazz)) {
|
||||
throw new IllegalArgumentException("No metric with the class " + clazz.getName() + " is registered");
|
||||
}
|
||||
return metrics.get(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all metrics from Redis.
|
||||
*/
|
||||
public void loadMetrics() {
|
||||
log.info("Loading metrics");
|
||||
for (Metric<?> metric : metricsRepository.findAll()) {
|
||||
metrics.put(metric.getClass(), metric);
|
||||
}
|
||||
log.info("Loaded {} metrics", metrics.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all metrics to Redis.
|
||||
*/
|
||||
private void saveMetrics() {
|
||||
log.info("Saving metrics to Redis");
|
||||
for (Metric<?> metric : metrics.values()) {
|
||||
saveMetric(metric);
|
||||
}
|
||||
log.info("Saved {} metrics", metrics.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a metric to Redis.
|
||||
*
|
||||
* @param metric the metric to save
|
||||
*/
|
||||
private void saveMetric(Metric<?> metric) {
|
||||
metricsRepository.save(metric); // Save the metric to the repository
|
||||
}
|
||||
|
||||
/**
|
||||
* Push all metrics to InfluxDB.
|
||||
*/
|
||||
private void writeToInflux() {
|
||||
log.info("Writing metrics to InfluxDB");
|
||||
for (Metric<?> metric : metrics.values()) {
|
||||
influxWriteApi.writePoint(metric.toPoint());
|
||||
}
|
||||
log.info("Wrote {} metrics", metrics.size());
|
||||
}
|
||||
}
|
32
src/main/java/xyz/mcutils/backend/service/metric/Metric.java
Normal file
32
src/main/java/xyz/mcutils/backend/service/metric/Metric.java
Normal file
@ -0,0 +1,32 @@
|
||||
package xyz.mcutils.backend.service.metric;
|
||||
|
||||
import com.influxdb.annotations.Measurement;
|
||||
import com.influxdb.client.write.Point;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.redis.core.RedisHash;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter @Setter
|
||||
@RedisHash(value = "metric")
|
||||
@Measurement(name = "metric")
|
||||
public abstract class Metric<T> {
|
||||
/**
|
||||
* The id of the metric.
|
||||
*/
|
||||
@Id private String id;
|
||||
|
||||
/**
|
||||
* The value of the metric.
|
||||
*/
|
||||
private T value;
|
||||
|
||||
/**
|
||||
* Gets this point as a {@link Point}.
|
||||
*
|
||||
* @return the point
|
||||
*/
|
||||
public abstract Point toPoint();
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package xyz.mcutils.backend.service.metric.impl;
|
||||
|
||||
import com.influxdb.client.write.Point;
|
||||
import xyz.mcutils.backend.service.metric.Metric;
|
||||
|
||||
public class IntegerMetric extends Metric<Integer> {
|
||||
|
||||
public IntegerMetric(String id) {
|
||||
super(id, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the value of this metric.
|
||||
*
|
||||
* @param amount the amount to increment by
|
||||
*/
|
||||
public void increment(int amount) {
|
||||
setValue(getValue() + amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the value of this metric by 1.
|
||||
*/
|
||||
public void increment() {
|
||||
increment(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the value of this metric.
|
||||
*
|
||||
* @param amount the amount to decrement by
|
||||
*/
|
||||
public void decrement(int amount) {
|
||||
setValue(getValue() - amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the value of this metric by 1.
|
||||
*/
|
||||
public void decrement() {
|
||||
decrement(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point toPoint() {
|
||||
return Point.measurement(getId())
|
||||
.addField("value", getValue());
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package xyz.mcutils.backend.service.metric.impl;
|
||||
|
||||
import com.influxdb.client.write.Point;
|
||||
import xyz.mcutils.backend.service.metric.Metric;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MapMetric <A, B> extends Metric<Map<A, B>> {
|
||||
|
||||
public MapMetric(String id) {
|
||||
super(id, new HashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point toPoint() {
|
||||
Point point = Point.measurement(getId());
|
||||
for (Map.Entry<A, B> entry : getValue().entrySet()) {
|
||||
point.addField(entry.getKey().toString(), entry.getValue().toString());
|
||||
}
|
||||
return point;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package xyz.mcutils.backend.service.metric.metrics;
|
||||
|
||||
import xyz.mcutils.backend.service.metric.impl.MapMetric;
|
||||
|
||||
public class RequestsPerRouteMetric extends MapMetric<String, Integer> {
|
||||
|
||||
public RequestsPerRouteMetric() {
|
||||
super("requests_per_route");
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the value for this route.
|
||||
*
|
||||
* @param route the route to increment
|
||||
*/
|
||||
public void increment(String route) {
|
||||
getValue().put(route, getValue().getOrDefault(route, 0) + 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package xyz.mcutils.backend.service.metric.metrics;
|
||||
|
||||
import xyz.mcutils.backend.service.metric.impl.IntegerMetric;
|
||||
|
||||
public class TotalRequestsMetric extends IntegerMetric {
|
||||
|
||||
public TotalRequestsMetric() {
|
||||
super("total_requests");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user