Skip to content

Commit 458988d

Browse files
committed
Merge branch 'develop' for issue #16
2 parents 3ce9c3b + ed31d6f commit 458988d

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

streams-metric-exporter/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ streams_operator_myCustomMetric
265265
| **streams_operator_ip_**|streams operator input port metrics|
266266
| **streams_operator_op_**|streams operatore output port metrics|
267267
268+
### Sanitization
269+
Metric names are sanitized (fixed) to meet Prometheus naming conventions. This is usually not required for 99% of IBM Streams metrics, however, since IBM Streams allows special characters and white space in metric names the following conversion rules are implemented:
270+
271+
* Replace series of one or more whitespaces with underscore (_)
272+
* Remove any special characters
273+
274+
An example would be the metric "streams_operator_nItemsQueued (port 2)" would become "streams_operator_nItemsQueued_port_2"
275+
268276
## Metric Labels
269277
The prometheus metric names are not specific to streams objects (e.g. a specific job), rather, they are for an object type (e.g. operator input port). The labels are used to identify the individual instances (e.g. job: job_1, operator: myBeacon, input port: StockTickersIn).
270278
Note: the streams-metric-exporter resolves operator input and output ports to names rather than indexes. This is easier for use in queries.

streams-metric-exporter/src/main/java/streams/metric/exporter/prometheus/PrometheusMetricsExporter.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.List;
2424
import java.util.Set;
2525
import java.util.Map;
26+
import java.util.regex.Pattern;
2627

2728
import io.prometheus.client.Gauge;
2829
import streams.metric.exporter.metrics.MetricsExporter;
@@ -44,17 +45,35 @@ static public MetricsExporter getInstance() {
4445
}
4546

4647
final Map<String, Gauge> gaugeMap = new HashMap<String, Gauge>();
48+
49+
// Prometheus has some rules for valid metric names
50+
// We will pre-sanitize metric names before using Promethus version
51+
// so that we can do the following:
52+
// - Replace all series of 1 or more white-space with underscore
53+
// - Remove all special characters except for underscore
54+
// Streams 4.3 had a metric name "nItemsQueued (Port 2)" that failed.
55+
private static final Pattern SPACES_PATTERN = Pattern.compile("\\s+");
56+
private static final Pattern NON_SPECIAL_OR_UNDERSCORE = Pattern.compile("(\\W|^_)*");
57+
58+
private String sanitizeMetricName(String metricName) {
59+
return Gauge.sanitizeMetricName(
60+
NON_SPECIAL_OR_UNDERSCORE.matcher(
61+
SPACES_PATTERN.matcher(metricName).replaceAll("_")
62+
).replaceAll(""));
63+
}
4764

4865
public void createStreamsMetric(String metricName, StreamsObjectType type, String description) {
49-
String metricFullName = getStreamsMetricFullName(metricName, type);
66+
String sanitizedName = sanitizeMetricName(metricName);
67+
String metricFullName = getStreamsMetricFullName(sanitizedName, type);
5068
if (!gaugeMap.containsKey(metricFullName)) {
5169
gaugeMap.put(metricFullName,
5270
Gauge.build().name(metricFullName).help(description).labelNames(type.metricLabelNames()).register());
5371
}
5472
}
5573

5674
public Metric getStreamsMetric(String metricName, StreamsObjectType type, String... labelValues) {
57-
String metricFullName = getStreamsMetricFullName(metricName, type);
75+
String sanitizedName = sanitizeMetricName(metricName);
76+
String metricFullName = getStreamsMetricFullName(sanitizedName, type);
5877
if (!gaugeMap.containsKey(metricFullName)) {
5978
// Create with default help text
6079
createStreamsMetric(metricName, type, type.metricDescriptionPrefix() + ": " + metricName);
@@ -80,7 +99,8 @@ public void removeAllChildStreamsMetrics(String... labelValues) {
8099
}
81100

82101
public void removeStreamsMetric(String metricName, StreamsObjectType type, String... labelValues) {
83-
String metricFullName = getStreamsMetricFullName(metricName, type);
102+
String sanitizedName = sanitizeMetricName(metricName);
103+
String metricFullName = getStreamsMetricFullName(sanitizedName, type);
84104
if (gaugeMap.containsKey(metricFullName)) {
85105
Gauge g = gaugeMap.get(metricFullName);
86106
g.remove(labelValues);

0 commit comments

Comments
 (0)