Skip to content

Commit

Permalink
[PLM-Jersey-Monitoring] Adding new metrics: Grizzly, HikariDB
Browse files Browse the repository at this point in the history
  • Loading branch information
wlatif authored and Wail-LT committed Oct 14, 2024
1 parent 543465e commit 1ef1d28
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.coreoz.plume.db.transaction;

import com.typesafe.config.Config;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.inject.Singleton;

import javax.sql.DataSource;

/**
Expand All @@ -11,16 +14,20 @@
@Singleton
public class DataSourceProvider implements Provider<DataSource> {

private final DataSource dataSource;
private final HikariDataSource dataSource;

@Inject
public DataSourceProvider(Config config) {
this(config, "db");
}

@Inject
public DataSourceProvider(TransactionManager transactionManager) {
this.dataSource = transactionManager.dataSource();
}
public DataSourceProvider(Config config, String prefix) {
this.dataSource = HikariDataSources.fromConfig(config, prefix + ".hikari");
}

@Override
public DataSource get() {
return dataSource;
}
@Override
public DataSource get() {
return dataSource;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
public class HikariDataSources {

public static DataSource fromConfig(Config config, String prefix) {
public static HikariDataSource fromConfig(Config config, String prefix) {
return new HikariDataSource(createHikariConfig(config, prefix));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ public class TransactionManager {

private final DataSource dataSource;

@Inject
@Inject
public TransactionManager(DataSource dataSource) {
this.dataSource = dataSource;
}

public TransactionManager(Config config) {
this(config, "db");
}
Expand All @@ -29,10 +33,6 @@ public TransactionManager(Config config, String prefix) {
this(HikariDataSources.fromConfig(config, prefix + ".hikari"));
}

public TransactionManager(DataSource dataSource) {
this.dataSource = dataSource;
}

// API

public DataSource dataSource() {
Expand Down
18 changes: 18 additions & 0 deletions plume-web-jersey-monitoring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
<groupId>com.coreoz</groupId>
<artifactId>plume-web-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.coreoz</groupId>
<artifactId>plume-db</artifactId>
Expand Down Expand Up @@ -84,6 +89,19 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<!-- Tests -->
<dependency>
<groupId>com.coreoz</groupId>
<artifactId>plume-db-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.14.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.coreoz.plume.jersey.monitoring.utils.metrics;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.MetricSet;
import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
import com.codahale.metrics.jvm.ThreadStatesGaugeSet;
import com.coreoz.plume.jersey.grizzly.GrizzlyThreadPoolProbe;
import com.zaxxer.hikari.HikariDataSource;

import jakarta.inject.Provider;
import java.util.Map;
Expand All @@ -27,6 +30,20 @@ public MetricsCheckBuilder registerJvmMetrics() {
return this;
}

public MetricsCheckBuilder registerGrizzlyMetrics(GrizzlyThreadPoolProbe grizzlyThreadPoolProbe) {
this.metricRegistry.register("http-pool.max-size", (Gauge<Integer>) grizzlyThreadPoolProbe::getPoolMaxSize);
this.metricRegistry.register("http-pool.current-size", (Gauge<Integer>) grizzlyThreadPoolProbe::getTasksWaitingSize);
this.metricRegistry.register("http-pool.waiting-size", (Gauge<Integer>) grizzlyThreadPoolProbe::getTasksWaitingSize);
this.metricRegistry.register("http-pool.usage-size", (Gauge<Integer>) grizzlyThreadPoolProbe::getPoolUsageSize);
this.metricRegistry.register("http-pool.usage", (Gauge<Float>) () -> ((float) grizzlyThreadPoolProbe.getPoolUsageSize()) / ((float)grizzlyThreadPoolProbe.getPoolMaxSize()));
return this;
}

public MetricsCheckBuilder registerHikariMetrics(HikariDataSource hikariDataSource) {
hikariDataSource.setMetricRegistry(this.metricRegistry);
return this;
}

public Provider<Map<String, Metric>> build() {
return this::getMetrics;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
db.hikari."dataSourceClassName"="org.h2.jdbcx.JdbcDataSource"
db.hikari."dataSource.url"="jdbc:h2:mem:test"
db.hikari."dataSource.user"=sa
db.hikari."dataSource.password"=sa
db.hikari.minimumIdle=1
db.hikari.maximumPoolSize=1
13 changes: 13 additions & 0 deletions plume-web-jersey-monitoring/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="STDOUT" />
</root>

</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.coreoz.plume.jersey.monitoring.utils.metrics;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.MetricSet;
import com.coreoz.plume.jersey.grizzly.GrizzlyThreadPoolProbe;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Map;

class MetricsCheckBuilderTest {

private MetricsCheckBuilder metricsCheckBuilder;

@BeforeEach
void setUp() {
metricsCheckBuilder = new MetricsCheckBuilder();
}

@Test
void registerMetric_should_registerSingleMetric() {
Metric mockMetric = mock(Metric.class);

metricsCheckBuilder.registerMetric("custom-metric", mockMetric);

Map<String, Metric> registeredMetrics = metricsCheckBuilder.build().get();
assertTrue(registeredMetrics.containsKey("custom-metric"));
assertEquals(mockMetric, registeredMetrics.get("custom-metric"));
}

@Test
void registerMetric_should_registerMetricSet() {
MetricSet mockMetricSet = mock(MetricSet.class);
Map<String, Metric> mockMetrics = Map.of("metric1", mock(Metric.class), "metric2", mock(Metric.class));
when(mockMetricSet.getMetrics()).thenReturn(mockMetrics);

metricsCheckBuilder.registerMetric("custom-metric-set", mockMetricSet);

Map<String, Metric> registeredMetrics = metricsCheckBuilder.build().get();
assertTrue(registeredMetrics.containsKey("custom-metric-set.metric1"));
assertTrue(registeredMetrics.containsKey("custom-metric-set.metric2"));
}

@Test
void registerJvmMetrics_should_registerJvmMetricsCorrectly() {
metricsCheckBuilder.registerJvmMetrics();

Map<String, Metric> registeredMetrics = metricsCheckBuilder.build().get();
assertTrue(registeredMetrics.containsKey("memory-usage.heap.max"));
assertTrue(registeredMetrics.containsKey("thread-states.runnable.count"));
}

@Test
void registerGrizzlyMetrics_should_registerGrizzlyMetricsCorrectly() {
GrizzlyThreadPoolProbe mockProbe = mock(GrizzlyThreadPoolProbe.class);
when(mockProbe.getPoolMaxSize()).thenReturn(100);
when(mockProbe.getTasksWaitingSize()).thenReturn(10);
when(mockProbe.getPoolUsageSize()).thenReturn(50);

metricsCheckBuilder.registerGrizzlyMetrics(mockProbe);

Map<String, Metric> registeredMetrics = metricsCheckBuilder.build().get();
assertTrue(registeredMetrics.containsKey("http-pool.max-size"));
assertTrue(registeredMetrics.containsKey("http-pool.current-size"));
assertTrue(registeredMetrics.containsKey("http-pool.waiting-size"));
assertTrue(registeredMetrics.containsKey("http-pool.usage-size"));
assertTrue(registeredMetrics.containsKey("http-pool.usage"));

Gauge<Integer> maxSizeGauge = (Gauge<Integer>) registeredMetrics.get("http-pool.max-size");
assertEquals(100, maxSizeGauge.getValue());

Gauge<Integer> waitingSizeGauge = (Gauge<Integer>) registeredMetrics.get("http-pool.waiting-size");
assertEquals(10, waitingSizeGauge.getValue());

Gauge<Float> usageGauge = (Gauge<Float>) registeredMetrics.get("http-pool.usage");
assertEquals(0.5f, usageGauge.getValue(), 0.01);
}

@Test
void registerHikariMetrics_should_registerHikariMetricsCorrectly() {
HikariDataSource mockDataSource = mock(HikariDataSource.class);

metricsCheckBuilder.registerHikariMetrics(mockDataSource);

verify(mockDataSource).setMetricRegistry(any(MetricRegistry.class));
}

@Test
void build_should_returnAllRegisteredMetrics() {
Metric mockMetric1 = mock(Metric.class);
Metric mockMetric2 = mock(Metric.class);

metricsCheckBuilder
.registerMetric("metric1", mockMetric1)
.registerMetric("metric2", mockMetric2);

Map<String, Metric> registeredMetrics = metricsCheckBuilder.build().get();
assertEquals(2, registeredMetrics.size());
assertTrue(registeredMetrics.containsKey("metric1"));
assertTrue(registeredMetrics.containsKey("metric2"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.coreoz.plume.jersey.grizzly;

import org.glassfish.grizzly.threadpool.AbstractThreadPool;
import org.glassfish.grizzly.threadpool.ThreadPoolProbe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Singleton;
import java.util.concurrent.atomic.AtomicInteger;

@Singleton
public class GrizzlyThreadPoolProbe implements ThreadPoolProbe {
private static final Logger logger = LoggerFactory.getLogger(GrizzlyThreadPoolProbe.class);

private final AtomicInteger tasksWaitingSize = new AtomicInteger(0);
private final AtomicInteger poolUsageSize = new AtomicInteger(0);

private int poolMaxSize = 0;
private int poolCurrentSize = 0;

/* Stats accessors */

public int getPoolMaxSize() {
return poolMaxSize;
}

public int getPoolCurrentSize() {
return poolCurrentSize;
}

public int getPoolUsageSize() {
return poolUsageSize.get();
}

public int getTasksWaitingSize() {
return tasksWaitingSize.get();
}

/* Implements ThreadPoolProbe */

@Override
public void onThreadPoolStartEvent(AbstractThreadPool threadPool) {
poolMaxSize = threadPool.getConfig().getMaxPoolSize();
poolCurrentSize = threadPool.getSize();
}

@Override
public void onThreadPoolStopEvent(AbstractThreadPool threadPool) {
// Not used
}

@Override
public void onThreadAllocateEvent(AbstractThreadPool threadPool, Thread thread) {
poolCurrentSize = threadPool.getSize();
}

@Override
public void onThreadReleaseEvent(AbstractThreadPool threadPool, Thread thread) {
poolCurrentSize = threadPool.getSize();
}

@Override
public void onMaxNumberOfThreadsEvent(AbstractThreadPool threadPool, int maxNumberOfThreads) {
// Not used
}

@Override
public void onTaskQueueEvent(AbstractThreadPool threadPool, Runnable task) {
tasksWaitingSize.incrementAndGet();
}

@Override
public void onTaskDequeueEvent(AbstractThreadPool threadPool, Runnable task) {
tasksWaitingSize.decrementAndGet();
poolUsageSize.incrementAndGet();
}

@Override
public void onTaskCancelEvent(AbstractThreadPool threadPool, Runnable task) {
tasksWaitingSize.decrementAndGet();
}

@Override
public void onTaskCompleteEvent(AbstractThreadPool threadPool, Runnable task) {
poolUsageSize.decrementAndGet();
}

@Override
public void onTaskQueueOverflowEvent(AbstractThreadPool threadPool) {
logger.error("Grizzly queue overflow");
}
}

0 comments on commit 1ef1d28

Please sign in to comment.