Skip to content

Commit dd3e387

Browse files
cuihengchCui Heng, INI-NET-VNC-HCS
andauthored
Feature/update monitoring (#15)
* refactor monitoring metrics --------- Co-authored-by: Cui Heng, INI-NET-VNC-HCS <Heng.Cui@swisscom.com>
1 parent 9bb77b4 commit dd3e387

12 files changed

Lines changed: 225 additions & 78 deletions

candyfloss/build.gradle

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ dependencies {
3838
implementation libs.slf4j
3939
implementation libs.vavr
4040
implementation libs.json.path
41-
implementation libs.micrometer
41+
implementation libs.micrometer.prom
4242
implementation libs.logback
43+
implementation libs.prometheus.httpserver
4344
implementation project(":json-transformation")
4445
implementation project(":protobuf-decoder")
4546
implementation project(':test-utils')
@@ -67,11 +68,6 @@ jacocoTestReport {
6768
dependsOn test // tests are required to run before generating the report
6869
}
6970

70-
task downloadPrometheusExporter(type: Download) {
71-
src 'https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.16.1/jmx_prometheus_javaagent-0.16.1.jar'
72-
dest new File("${project.projectDir}/src/main/jib", 'jmx_prometheus_javaagent.jar')
73-
}
74-
7571

7672
jar {
7773
manifest {
@@ -101,15 +97,7 @@ jib {
10197
jvmFlags = [
10298
'-Xms2048m',
10399
'-Dconfig.override_with_env_vars=true',
104-
'-Dcom.sun.management.jmxremote.port=5555',
105-
'-Dcom.sun.management.jmxremote.local.only=true',
106-
'-Dcom.sun.management.jmxremote.authenticate=false',
107-
'-Dcom.sun.management.jmxremote.ssl=false',
108-
'-javaagent:/jmx_prometheus_javaagent.jar=8090:/jmx_prometheus_exporter.yaml',
109100
]
110101
mainClass = 'com.swisscom.daisy.cosmos.candyfloss.CandyflossKStreamsApplication'
111102
}
112103
}
113-
114-
tasks.jibDockerBuild.dependsOn tasks.downloadPrometheusExporter
115-
tasks.jib.dependsOn tasks.downloadPrometheusExporter

candyfloss/src/main/java/com/swisscom/daisy/cosmos/candyfloss/CandyflossKStreamsApplication.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.swisscom.daisy.cosmos.candyfloss;
22

33
import com.swisscom.daisy.cosmos.candyfloss.config.JsonKStreamApplicationConfig;
4+
import com.swisscom.daisy.cosmos.candyfloss.config.MetricRegistryConfig;
45
import com.swisscom.daisy.cosmos.candyfloss.config.exceptions.InvalidConfigurations;
56
import com.swisscom.daisy.cosmos.candyfloss.messages.ValueErrorMessage;
67
import com.swisscom.daisy.cosmos.candyfloss.processors.*;
@@ -10,10 +11,6 @@
1011
import com.typesafe.config.ConfigFactory;
1112
import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig;
1213
import io.confluent.kafka.streams.serdes.avro.GenericAvroSerde;
13-
import io.micrometer.core.instrument.Clock;
14-
import io.micrometer.core.instrument.Metrics;
15-
import io.micrometer.jmx.JmxConfig;
16-
import io.micrometer.jmx.JmxMeterRegistry;
1714
import java.io.ByteArrayOutputStream;
1815
import java.io.IOException;
1916
import java.time.Duration;
@@ -45,8 +42,8 @@ public CandyflossKStreamsApplication(JsonKStreamApplicationConfig config) {
4542
public static void main(String[] args)
4643
throws IOException, InvalidConfigurations, InvalidMatchConfiguration {
4744
// Setting up the metrics registry
48-
var jmxMeterRegistry = new JmxMeterRegistry(JmxConfig.DEFAULT, Clock.SYSTEM);
49-
Metrics.addRegistry(jmxMeterRegistry);
45+
MetricRegistryConfig prometheusRegistry = new MetricRegistryConfig();
46+
prometheusRegistry.bindJvm();
5047

5148
logger.info("Loading configurations");
5249
Config conf = ConfigFactory.load();
@@ -65,12 +62,14 @@ public static void main(String[] args)
6562
@Override
6663
public void run() {
6764
logger.info("Received shutdown signal, terminating Candyfloss");
65+
prometheusRegistry.close();
6866
kafkaStreams.close();
6967
latch.countDown();
7068
}
7169
});
7270

7371
try {
72+
prometheusRegistry.start();
7473
kafkaStreams.start();
7574
latch.await();
7675
logger.info("Cosmos Candyfloss gracefully shutdown");
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.swisscom.daisy.cosmos.candyfloss.config;
2+
3+
import io.micrometer.core.instrument.*;
4+
import java.util.List;
5+
import java.util.Map;
6+
import org.apache.kafka.common.MetricName;
7+
import org.apache.kafka.common.metrics.KafkaMetric;
8+
import org.apache.kafka.common.metrics.MetricsReporter;
9+
10+
public class CFMetricReporter implements MetricsReporter {
11+
@Override
12+
public void init(List<KafkaMetric> metricList) {
13+
metricList.forEach(this::metricChange);
14+
}
15+
16+
@Override
17+
public void metricChange(KafkaMetric metric) {
18+
MetricName metricName = metric.metricName();
19+
20+
if (metric.metricValue() instanceof Number) {
21+
Tags tags = tagsConvert(metricName);
22+
23+
if (isCounter(metricName)) {
24+
FunctionCounter.builder(
25+
cleanCounterName(metricName), metric, m -> ((Number) m.metricValue()).doubleValue())
26+
.tags(tags)
27+
.register(Metrics.globalRegistry);
28+
} else {
29+
Gauge.builder(metricName.name(), metric, m -> ((Number) m.metricValue()).doubleValue())
30+
.description(metricName.description())
31+
.tags(tags)
32+
.register(Metrics.globalRegistry);
33+
}
34+
}
35+
}
36+
37+
@Override
38+
public void metricRemoval(KafkaMetric metric) {
39+
MetricName metricName = metric.metricName();
40+
Tags tags = tagsConvert(metricName);
41+
42+
Metrics.globalRegistry
43+
.find(metricName.name())
44+
.tags(tags)
45+
.meters()
46+
.forEach(Metrics.globalRegistry::remove);
47+
}
48+
49+
@Override
50+
public void close() {}
51+
52+
@Override
53+
public void configure(Map<String, ?> config) {}
54+
55+
private boolean isCounter(MetricName metricName) {
56+
String name = metricName.name();
57+
return name.endsWith("-total") || name.endsWith("-count");
58+
}
59+
60+
private Tags tagsConvert(MetricName metricName) {
61+
return Tags.of(
62+
metricName.tags().entrySet().stream()
63+
.map(entry -> Tag.of(entry.getKey(), entry.getValue()))
64+
.toList());
65+
}
66+
67+
private String cleanCounterName(MetricName metricName) {
68+
return metricName.name().replace("-total", "").replace("-count", "");
69+
}
70+
}

candyfloss/src/main/java/com/swisscom/daisy/cosmos/candyfloss/config/JsonKStreamApplicationConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.Properties;
1212
import lombok.AllArgsConstructor;
1313
import lombok.Getter;
14+
import org.apache.kafka.streams.StreamsConfig;
1415

1516
/***
1617
* The main class to parse and represent the application configs read from `application.$env.conf`
@@ -45,6 +46,8 @@ public static JsonKStreamApplicationConfig fromConfig(Config config)
4546
for (var entry : kafkaConfig.entrySet()) {
4647
kafka.put(entry.getKey(), kafkaConfig.getString(entry.getKey()));
4748
}
49+
kafka.put(StreamsConfig.METRIC_REPORTER_CLASSES_CONFIG, CFMetricReporter.class.getName());
50+
4851
final String inputTopicName = config.getConfig("kstream").getString("input.topic.name");
4952
final InputType inputType;
5053
if (config.hasPath("kstream.input.type")) {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.swisscom.daisy.cosmos.candyfloss.config;
2+
3+
import io.micrometer.core.instrument.Metrics;
4+
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
5+
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
6+
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
7+
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
8+
import io.micrometer.prometheus.PrometheusConfig;
9+
import io.micrometer.prometheus.PrometheusMeterRegistry;
10+
import io.prometheus.client.exporter.HTTPServer;
11+
import java.io.IOException;
12+
import java.net.InetSocketAddress;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
public class MetricRegistryConfig {
17+
private final PrometheusMeterRegistry prometheusRegistry;
18+
19+
private JvmGcMetrics jvmGcMetrics;
20+
21+
private HTTPServer server;
22+
23+
private final Logger logger = LoggerFactory.getLogger(MetricRegistryConfig.class);
24+
25+
public MetricRegistryConfig() {
26+
prometheusRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
27+
}
28+
29+
public void bindJvm() {
30+
if (jvmGcMetrics == null) {
31+
jvmGcMetrics = new JvmGcMetrics();
32+
}
33+
jvmGcMetrics.bindTo(prometheusRegistry);
34+
new ProcessorMetrics().bindTo(prometheusRegistry);
35+
new JvmThreadMetrics().bindTo(prometheusRegistry);
36+
new JvmMemoryMetrics().bindTo(prometheusRegistry);
37+
}
38+
39+
public void start() {
40+
try {
41+
server =
42+
new HTTPServer(
43+
new InetSocketAddress(8090), prometheusRegistry.getPrometheusRegistry(), true);
44+
Metrics.addRegistry(prometheusRegistry);
45+
} catch (IOException e) {
46+
logger.error("Registry service is not properly started", e);
47+
}
48+
}
49+
50+
public void close() {
51+
jvmGcMetrics.close();
52+
server.close();
53+
}
54+
}

candyfloss/src/main/java/com/swisscom/daisy/cosmos/candyfloss/processors/CounterNormalizationProcessor.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@
99
import com.swisscom.daisy.cosmos.candyfloss.messages.ValueErrorMessage;
1010
import com.swisscom.daisy.cosmos.candyfloss.processors.exceptions.InvalidCounterKeysConfigurations;
1111
import com.swisscom.daisy.cosmos.candyfloss.processors.exceptions.InvalidCounterValue;
12-
import io.micrometer.core.instrument.Counter;
13-
import io.micrometer.core.instrument.Gauge;
14-
import io.micrometer.core.instrument.Metrics;
15-
import io.micrometer.core.instrument.Timer;
12+
import io.micrometer.core.instrument.*;
13+
import io.micrometer.core.instrument.Timer.Sample;
1614
import java.math.BigInteger;
1715
import java.nio.charset.StandardCharsets;
1816
import java.time.*;
@@ -32,6 +30,9 @@
3230

3331
public class CounterNormalizationProcessor
3432
implements Processor<String, FlattenedMessage, String, ValueErrorMessage<FlattenedMessage>> {
33+
private static final String metricTag = "pipeline";
34+
35+
private static final String timerMetric = "latency_normalization";
3536

3637
private final Logger logger = LoggerFactory.getLogger(CounterNormalizationProcessor.class);
3738

@@ -56,15 +57,6 @@ public class CounterNormalizationProcessor
5657
.register(Metrics.globalRegistry);
5758
private final AtomicInteger numKeysTotal = new AtomicInteger(0);
5859
private final AtomicInteger numKeysCleaned = new AtomicInteger(0);
59-
private final Gauge numKeysGauge =
60-
Gauge.builder("json_streams_old_counter_total_keys", () -> numKeysTotal)
61-
.description("Number of counter keys saved in the state store")
62-
.register(Metrics.globalRegistry);
63-
64-
private final Gauge numKeysGaugeCleaned =
65-
Gauge.builder("json_streams_old_counter_cleaned_keys", () -> numKeysCleaned)
66-
.description("Number of old counter keys deleted from the state store")
67-
.register(Metrics.globalRegistry);
6860

6961
private final Duration maxCounterAge;
7062
private final Duration scanFrequency;
@@ -395,12 +387,18 @@ private Bytes getCounterKey(DocumentContext context, NormalizeCounterConfig coun
395387

396388
@Override
397389
public void process(Record<String, FlattenedMessage> record) {
390+
Sample timer = Timer.start(Metrics.globalRegistry);
391+
398392
var key = record.key();
399393
var value = record.value();
400394
var ts = record.timestamp();
401395

402396
KeyValue<String, ValueErrorMessage<FlattenedMessage>> kv = handleRecord(key, value, ts);
403397

404398
context.forward(new Record<>(kv.key, kv.value, record.timestamp()));
399+
400+
timer.stop(
401+
Metrics.globalRegistry.timer(
402+
timerMetric, metricTag, value.getTag() == null ? "" : value.getTag()));
405403
}
406404
}

candyfloss/src/main/java/com/swisscom/daisy/cosmos/candyfloss/processors/FlattenProcessor.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import com.swisscom.daisy.cosmos.candyfloss.transformations.TransformedMessage;
77
import io.micrometer.core.instrument.Counter;
88
import io.micrometer.core.instrument.Metrics;
9+
import io.micrometer.core.instrument.Timer;
10+
import io.micrometer.core.instrument.Timer.Sample;
911
import java.util.List;
1012
import java.util.stream.Collectors;
1113
import org.apache.kafka.streams.KeyValue;
@@ -15,17 +17,14 @@
1517

1618
public class FlattenProcessor
1719
implements Processor<String, TransformedMessage, String, ValueErrorMessage<FlattenedMessage>> {
20+
private static final String metricTag = "pipeline";
21+
private static final String timerMetric = "latency_flatten";
22+
private static final String CounterOutMetric = "json_streams_flatten_out";
23+
1824
private final Counter counterIn =
1925
Counter.builder("json_streams_flatten_in")
2026
.description("Number of message incoming to the Json Flatten step")
2127
.register(Metrics.globalRegistry);
22-
private final Counter counterOut =
23-
Counter.builder("json_streams_flatten_out")
24-
.description(
25-
"Number of output messages after the flatten step. "
26-
+ "Note: json_streams_flatten_out/(json_streams_flatten_in-json_streams_flatten_error)"
27-
+ " is flatten message ration")
28-
.register(Metrics.globalRegistry);
2928
private final Counter counterError =
3029
Counter.builder("json_streams_flatten_error")
3130
.description("Number of error messages that are discarded to dlq topic")
@@ -40,17 +39,23 @@ public void init(ProcessorContext<String, ValueErrorMessage<FlattenedMessage>> c
4039

4140
@Override
4241
public void process(Record<String, TransformedMessage> record) {
42+
Sample timer = Timer.start(Metrics.globalRegistry);
43+
counterIn.increment();
44+
4345
var key = record.key();
4446
var value = record.value();
4547
var ts = record.timestamp();
4648

4749
handleRecord(key, value, ts).forEach(kv -> context.forward(new Record<>(kv.key, kv.value, ts)));
50+
51+
timer.stop(
52+
Metrics.globalRegistry.timer(
53+
timerMetric, metricTag, value.getTag() == null ? "" : value.getTag()));
4854
}
4955

5056
public Iterable<KeyValue<String, ValueErrorMessage<FlattenedMessage>>> handleRecord(
5157
String key, TransformedMessage value, long ts) {
5258
try {
53-
counterIn.increment();
5459
return flattenMessage(key, value);
5560
} catch (Exception e) {
5661
counterError.increment();
@@ -69,7 +74,14 @@ private List<KeyValue<String, ValueErrorMessage<FlattenedMessage>>> flattenMessa
6974
x ->
7075
KeyValue.pair(
7176
key, new ValueErrorMessage<>(new FlattenedMessage(x, value.getTag()))))
72-
.peek(x -> counterOut.increment())
77+
.peek(
78+
x -> {
79+
FlattenedMessage flatMsg = x.value.getValue();
80+
Counter.builder(CounterOutMetric)
81+
.tag(metricTag, flatMsg.getTag() == null ? "" : flatMsg.getTag())
82+
.register(Metrics.globalRegistry)
83+
.increment();
84+
})
7385
.collect(Collectors.toList());
7486
}
7587
}

0 commit comments

Comments
 (0)