Skip to content

Commit fd22502

Browse files
Add dropwizard based java client fo custom metrics
1 parent 5653275 commit fd22502

File tree

29 files changed

+1437
-5
lines changed

29 files changed

+1437
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.sap.cloud.cf.monitoring.client.configuration;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.concurrent.TimeUnit;
7+
8+
public class CustomMetricsConfiguration {
9+
10+
static final long DEFAULT_INTERVAL = TimeUnit.MINUTES.toMillis(1);
11+
private long interval = DEFAULT_INTERVAL;
12+
private boolean enabled = true;
13+
private List<String> metrics;
14+
private boolean metricsAggregation = false;
15+
16+
public long getInterval() {
17+
return interval;
18+
}
19+
20+
public boolean isEnabled() {
21+
return enabled;
22+
}
23+
24+
public List<String> getMetrics() {
25+
if (this.metrics == null) {
26+
return Collections.emptyList();
27+
}
28+
return new ArrayList<>(metrics);
29+
}
30+
31+
public boolean isMetricsAggregation() {
32+
return metricsAggregation;
33+
}
34+
35+
@Override
36+
public String toString() {
37+
return new StringBuilder("CustomMetricsConfiguration[").append("interval=")
38+
.append(interval)
39+
.append(", enabled=")
40+
.append(enabled)
41+
.append(", metrics=")
42+
.append(metrics)
43+
.append("]")
44+
.append(", metricsAggregation=")
45+
.append(metricsAggregation)
46+
.toString();
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.sap.cloud.cf.monitoring.client.configuration;
2+
3+
import java.util.Map;
4+
5+
import com.google.gson.Gson;
6+
import com.google.gson.GsonBuilder;
7+
8+
public class CustomMetricsConfigurationFactory {
9+
10+
private static final String CUSTOM_METRICS_KEY = "CUSTOM_METRICS";
11+
private static final Gson gson =
12+
new GsonBuilder().registerTypeAdapter(long.class, new LongIntervalGsonTypeAdapter()).create();
13+
14+
public static CustomMetricsConfiguration create() {
15+
return create(System.getenv());
16+
}
17+
18+
public static CustomMetricsConfiguration create(Map<String, String> env) {
19+
String customMetricsString = env.get(CUSTOM_METRICS_KEY);
20+
if (customMetricsString == null || customMetricsString.isEmpty()) {
21+
return new CustomMetricsConfiguration();
22+
}
23+
return gson.fromJson(customMetricsString, CustomMetricsConfiguration.class);
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.sap.cloud.cf.monitoring.client.configuration;
2+
3+
import static com.sap.cloud.cf.monitoring.client.configuration.CustomMetricsConfiguration.DEFAULT_INTERVAL;
4+
5+
import java.lang.reflect.Type;
6+
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import com.google.gson.JsonDeserializationContext;
11+
import com.google.gson.JsonDeserializer;
12+
import com.google.gson.JsonElement;
13+
import com.google.gson.JsonParseException;
14+
15+
final class LongIntervalGsonTypeAdapter implements JsonDeserializer<Long> {
16+
private static final Logger LOGGER = LoggerFactory.getLogger(LongIntervalGsonTypeAdapter.class);
17+
private static final long MINIMAL_INTERVAL = 20000L;
18+
19+
@Override
20+
public Long deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
21+
long value = Long.parseLong(json.getAsString());
22+
if (value < MINIMAL_INTERVAL) {
23+
LOGGER.warn(String.format(
24+
"The value of 'interval' property could not be less than %s. The default value %s will be used.",
25+
MINIMAL_INTERVAL, DEFAULT_INTERVAL));
26+
return DEFAULT_INTERVAL;
27+
}
28+
return value;
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.sap.cloud.cf.monitoring.client.configuration;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertFalse;
5+
import static org.junit.Assert.assertNotNull;
6+
import static org.junit.Assert.assertTrue;
7+
8+
import java.util.List;
9+
10+
import org.junit.Test;
11+
12+
public class CustomMetricsConfigurationFactoryTest {
13+
14+
@Test
15+
public void testMatches_WithoutEnv() throws Exception {
16+
EnvUtils.setEnvs(new String[][] {});
17+
18+
testDefault();
19+
}
20+
21+
@Test
22+
public void testMatches_WithEmptyEnv() throws Exception {
23+
String[] CUSTOM_METRICS_ENV = new String[] { "CUSTOM_METRICS", "" };
24+
EnvUtils.setEnvs(new String[][] { CUSTOM_METRICS_ENV });
25+
26+
testDefault();
27+
}
28+
29+
private void testDefault() {
30+
CustomMetricsConfiguration config = CustomMetricsConfigurationFactory.create();
31+
32+
assertTrue(config.isEnabled());
33+
assertEquals(CustomMetricsConfiguration.DEFAULT_INTERVAL, config.getInterval());
34+
assertNotNull(config.getMetrics());
35+
assertTrue(config.getMetrics().isEmpty());
36+
assertFalse(config.isMetricsAggregation());
37+
}
38+
39+
@Test
40+
public void testMatches_WithEnv() throws Exception {
41+
EnvUtils.setEnvs(new String[][] { getCustomMetricsEnv("20000") });
42+
43+
CustomMetricsConfiguration config = CustomMetricsConfigurationFactory.create();
44+
45+
assertFalse(config.isEnabled());
46+
assertEquals(20_000, config.getInterval());
47+
List<String> metrics = config.getMetrics();
48+
assertEquals(2, metrics.size());
49+
assertTrue(metrics.contains("timer"));
50+
assertTrue(metrics.contains("summary"));
51+
assertTrue(config.isMetricsAggregation());
52+
}
53+
54+
@Test
55+
public void testMatches_WithShortIntervalEnv() throws Exception {
56+
EnvUtils.setEnvs(new String[][] { getCustomMetricsEnv("1000") });
57+
58+
CustomMetricsConfiguration config = CustomMetricsConfigurationFactory.create();
59+
60+
assertFalse(config.isEnabled());
61+
assertEquals(CustomMetricsConfiguration.DEFAULT_INTERVAL, config.getInterval());
62+
List<String> metrics = config.getMetrics();
63+
assertEquals(2, metrics.size());
64+
assertTrue(metrics.contains("timer"));
65+
assertTrue(metrics.contains("summary"));
66+
}
67+
68+
@Test(expected = NumberFormatException.class)
69+
public void testMatches_WrongIntervalFormat() throws Exception {
70+
EnvUtils.setEnvs(new String[][] { getCustomMetricsEnv("wronginterval") });
71+
72+
CustomMetricsConfigurationFactory.create();
73+
}
74+
75+
private static String[] getCustomMetricsEnv(String interval) {
76+
return new String[] { "CUSTOM_METRICS", getJson(interval) };
77+
}
78+
79+
private static String getJson(String interval) {
80+
return "{\n" + //
81+
" \"interval\": \"" + interval + "\",\n" + //
82+
" \"enabled\": \"false\",\n" + //
83+
" \"metrics\": [\"timer\", \"summary\"],\n" + //
84+
" \"metricsAggregation\": \"true\"\n" + //
85+
"}";
86+
}
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.sap.cloud.cf.monitoring.client.configuration;
2+
3+
import java.lang.reflect.Field;
4+
import java.util.Collections;
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
8+
public class EnvUtils {
9+
10+
public static void setEnvs(String[][] envs) throws Exception {
11+
Map<String, String> envMap = new HashMap<>();
12+
for (String[] env : envs) {
13+
envMap.put(env[0], env[1]);
14+
}
15+
16+
setNewEnvs(envMap);
17+
}
18+
19+
@SuppressWarnings({ "rawtypes", "unchecked" })
20+
private static void setNewEnvs(Map<String, String> newenv) throws Exception {
21+
Class[] classes = Collections.class.getDeclaredClasses();
22+
Map<String, String> env = System.getenv();
23+
for (Class cl : classes) {
24+
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
25+
Field field = cl.getDeclaredField("m");
26+
field.setAccessible(true);
27+
Object obj = field.get(env);
28+
Map<String, String> map = (Map<String, String>) obj;
29+
map.clear();
30+
map.putAll(newenv);
31+
}
32+
}
33+
}
34+
35+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>com.sap.hcp.cf.logging</groupId>
7+
<artifactId>cf-java-monitoring-custom-metrics-clients</artifactId>
8+
<version>3.0.0</version>
9+
</parent>
10+
11+
<artifactId>cf-custom-metrics-clients-java</artifactId>
12+
<packaging>jar</packaging>
13+
<name>cf-java-monitoring-custom-metrics-clients-dropwizard-java</name>
14+
15+
<properties>
16+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
17+
<dropwizard.version>3.2.6</dropwizard.version>
18+
</properties>
19+
20+
<build>
21+
<plugins>
22+
<plugin>
23+
<groupId>org.apache.maven.plugins</groupId>
24+
<artifactId>maven-compiler-plugin</artifactId>
25+
<configuration>
26+
<source>1.7</source>
27+
<target>1.7</target>
28+
</configuration>
29+
</plugin>
30+
</plugins>
31+
</build>
32+
33+
<dependencies>
34+
<dependency>
35+
<groupId>com.sap.hcp.cf.logging</groupId>
36+
<artifactId>cf-custom-metrics-clients-core</artifactId>
37+
<version>${project.version}</version>
38+
</dependency>
39+
<dependency>
40+
<groupId>io.dropwizard.metrics</groupId>
41+
<artifactId>metrics-core</artifactId>
42+
<version>${dropwizard.version}</version>
43+
</dependency>
44+
<dependency>
45+
<groupId>org.slf4j</groupId>
46+
<artifactId>slf4j-api</artifactId>
47+
<scope>provided</scope>
48+
</dependency>
49+
<!-- Test dependencies -->
50+
<dependency>
51+
<groupId>junit</groupId>
52+
<artifactId>junit</artifactId>
53+
<scope>test</scope>
54+
</dependency>
55+
<dependency>
56+
<groupId>org.mockito</groupId>
57+
<artifactId>mockito-all</artifactId>
58+
<scope>test</scope>
59+
</dependency>
60+
</dependencies>
61+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.sap.cloud.cf.monitoring.java;
2+
3+
import java.util.concurrent.TimeUnit;
4+
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
8+
import com.codahale.metrics.MetricRegistry;
9+
import com.sap.cloud.cf.monitoring.client.MonitoringClient;
10+
import com.sap.cloud.cf.monitoring.client.MonitoringClientBuilder;
11+
import com.sap.cloud.cf.monitoring.client.configuration.CFConfigurationProvider;
12+
import com.sap.cloud.cf.monitoring.client.configuration.ConfigurationProvider;
13+
import com.sap.cloud.cf.monitoring.client.configuration.CustomMetricsConfiguration;
14+
import com.sap.cloud.cf.monitoring.client.configuration.CustomMetricsConfigurationFactory;
15+
16+
public class CustomMetricRegistry extends MetricRegistry {
17+
private static final Logger LOGGER = LoggerFactory.getLogger(CustomMetricRegistry.class);
18+
private static volatile CustomMetricRegistry instance = null;
19+
20+
private ConfigurationProvider configProvider;
21+
private CustomMetricsConfiguration customMetricsConfig;
22+
private CustomMetricsReporter reporter;
23+
24+
public static MetricRegistry get() {
25+
if (instance == null) {
26+
synchronized (CustomMetricRegistry.class) {
27+
if (instance == null) {
28+
instance = new CustomMetricRegistry();
29+
}
30+
}
31+
}
32+
return instance;
33+
}
34+
35+
protected CustomMetricsReporter getReporter() {
36+
return reporter;
37+
}
38+
39+
private CustomMetricRegistry() {
40+
configProvider = getConfigProvider();
41+
customMetricsConfig = CustomMetricsConfigurationFactory.create();
42+
initializeAndStartReporter();
43+
}
44+
45+
private CFConfigurationProvider getConfigProvider() {
46+
try {
47+
return new CFConfigurationProvider();
48+
} catch (IllegalArgumentException e) {
49+
LOGGER.error("Required ENVs are missing: {}", e);
50+
return null;
51+
}
52+
}
53+
54+
private void initializeAndStartReporter() {
55+
if (configProvider == null || customMetricsConfig == null || !customMetricsConfig.isEnabled()) {
56+
LOGGER.error(
57+
"Custom Metrics reporter will not start since required ENVs are missing or environment variable 'enable' is false.");
58+
return;
59+
}
60+
MonitoringClient client = new MonitoringClientBuilder().setConfigurationProvider(configProvider).create();
61+
reporter = new CustomMetricsReporter(this, client, customMetricsConfig);
62+
reporter.start(customMetricsConfig.getInterval(), TimeUnit.MILLISECONDS);
63+
}
64+
}

0 commit comments

Comments
 (0)