Skip to content

Commit 3c964fa

Browse files
committed
parse topmetrics
1 parent 356ebbb commit 3c964fa

2 files changed

Lines changed: 154 additions & 3 deletions

File tree

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/sink/PrometheusMetricsSink.java

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
*/
1818
package org.apache.hadoop.metrics2.sink;
1919

20+
import java.util.ArrayList;
21+
import java.util.List;
22+
import java.util.regex.Matcher;
2023
import org.apache.commons.configuration2.SubsetConfiguration;
2124
import org.apache.hadoop.metrics2.AbstractMetric;
2225
import org.apache.hadoop.metrics2.MetricType;
@@ -52,6 +55,13 @@ public class PrometheusMetricsSink implements MetricsSink {
5255
Pattern.compile("(?<!(^|[A-Z_]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])");
5356
private static final Pattern DELIMITERS = Pattern.compile("[^a-zA-Z0-9]+");
5457

58+
private static final Pattern NN_TOPMETRICS_PATTERN =
59+
Pattern.compile(
60+
"^(nn_top_user_op_counts_window_ms_\\d+)_op_.*?(total_count|count)$");
61+
private static final Pattern NN_TOPMETRICS_TAGS_PATTERN =
62+
Pattern
63+
.compile("^op=(?<op>\\w+)(.user=(?<user>.*)|)\\.(TotalCount|count)$");
64+
5565
public PrometheusMetricsSink() {
5666
}
5767

@@ -98,22 +108,25 @@ public void writeMetrics(Writer writer) throws IOException {
98108
for (Map.Entry<String, Map<Collection<MetricsTag>, AbstractMetric>> promMetric :
99109
promMetrics.entrySet()) {
100110
AbstractMetric firstMetric = promMetric.getValue().values().iterator().next();
111+
List<String> customTags = new ArrayList<>();
112+
String metricKey = getMetricKey(promMetric.getKey(), firstMetric,
113+
customTags);
101114

102115
StringBuilder builder = new StringBuilder();
103116
builder.append("# HELP ")
104-
.append(promMetric.getKey())
117+
.append(metricKey)
105118
.append(" ")
106119
.append(firstMetric.description())
107120
.append("\n")
108121
.append("# TYPE ")
109-
.append(promMetric.getKey())
122+
.append(metricKey)
110123
.append(" ")
111124
.append(firstMetric.type().toString().toLowerCase())
112125
.append("\n");
113126

114127
for (Map.Entry<Collection<MetricsTag>, AbstractMetric> metric :
115128
promMetric.getValue().entrySet()) {
116-
builder.append(promMetric.getKey())
129+
builder.append(metricKey)
117130
.append("{");
118131

119132
String sep = "";
@@ -129,6 +142,12 @@ public void writeMetrics(Writer writer) throws IOException {
129142
sep = ",";
130143
}
131144
}
145+
if (customTags.size() > 0) {
146+
//add custom tags
147+
for (String tagStr : customTags) {
148+
builder.append(sep).append(tagStr);
149+
}
150+
}
132151
builder.append("} ");
133152
builder.append(metric.getValue().value());
134153
builder.append("\n");
@@ -137,4 +156,39 @@ public void writeMetrics(Writer writer) throws IOException {
137156
writer.write(builder.toString());
138157
}
139158
}
159+
160+
private String getMetricKey(String promMetricKey, AbstractMetric metric,
161+
List<String> customTags) {
162+
Matcher matcher = NN_TOPMETRICS_PATTERN.matcher(promMetricKey);
163+
if (matcher.find() && matcher.groupCount() == 2) {
164+
customTags.addAll(parseTopMetricsTags(metric.name()));
165+
return String.format("%s_%s",
166+
matcher.group(1), matcher.group(2));
167+
}
168+
return promMetricKey;
169+
}
170+
171+
/**
172+
* Parse Custom tags for TopMetrics.
173+
*
174+
* @param metricName metricName
175+
* @return Tags for TopMetrics
176+
*/
177+
private List<String> parseTopMetricsTags(String metricName) {
178+
List<String> topMetricsTags = new ArrayList<>();
179+
Matcher matcher = NN_TOPMETRICS_TAGS_PATTERN.matcher(metricName);
180+
if (matcher.find()) {
181+
String op = matcher.group("op");
182+
String user = matcher.group("user");
183+
// add tag op = "$op"
184+
topMetricsTags.add(String
185+
.format("op=\"%s\"", op));
186+
if (StringUtils.isNoneEmpty(user)) {
187+
// add tag op = "$op"
188+
topMetricsTags.add(String
189+
.format("user=\"%s\"", user));
190+
}
191+
}
192+
return topMetricsTags;
193+
}
140194
}

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/sink/TestPrometheusMetricsSink.java

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,18 @@
2121
import java.io.IOException;
2222
import java.io.OutputStreamWriter;
2323

24+
import java.util.ArrayList;
25+
import java.util.List;
26+
import org.apache.commons.lang3.StringUtils;
27+
import org.apache.hadoop.metrics2.MetricsCollector;
28+
import org.apache.hadoop.metrics2.MetricsRecordBuilder;
29+
import org.apache.hadoop.metrics2.MetricsSource;
2430
import org.apache.hadoop.metrics2.MetricsSystem;
2531
import org.apache.hadoop.metrics2.annotation.Metric;
2632
import org.apache.hadoop.metrics2.annotation.Metrics;
2733
import org.apache.hadoop.metrics2.annotation.Metric.Type;
2834
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
35+
import org.apache.hadoop.metrics2.lib.Interns;
2936
import org.apache.hadoop.metrics2.lib.MutableCounterLong;
3037

3138
import org.junit.Assert;
@@ -219,6 +226,62 @@ public void testNamingWhitespaces() {
219226
sink.prometheusName(recordName, metricName));
220227
}
221228

229+
/**
230+
* testTopMetricsPublish.
231+
*/
232+
@Test
233+
public void testTopMetricsPublish() throws IOException {
234+
MetricsSystem metrics = DefaultMetricsSystem.instance();
235+
236+
metrics.init("test");
237+
238+
//GIVEN
239+
PrometheusMetricsSink sink = new PrometheusMetricsSink();
240+
241+
metrics.register("prometheus", "prometheus", sink);
242+
TestTopMetrics topMetrics = new TestTopMetrics();
243+
topMetrics.add("60000");
244+
topMetrics.add("1500000");
245+
metrics.register(TestTopMetrics.TOPMETRICS_METRICS_SOURCE_NAME,
246+
"Top N operations by user", topMetrics);
247+
248+
metrics.start();
249+
250+
metrics.publishMetricsNow();
251+
ByteArrayOutputStream stream = new ByteArrayOutputStream();
252+
OutputStreamWriter writer = new OutputStreamWriter(stream, UTF_8);
253+
254+
//WHEN
255+
sink.writeMetrics(writer);
256+
writer.flush();
257+
258+
//THEN
259+
String writtenMetrics = stream.toString(UTF_8.name());
260+
System.out.println(writtenMetrics);
261+
Assert.assertTrue(
262+
"The expected metric line is missing from prometheus metrics output",
263+
writtenMetrics.contains(
264+
"nn_top_user_op_counts_window_ms_60000_total_count{context=\"dfs\"")
265+
);
266+
Assert.assertTrue(
267+
"The expected metric line is missing from prometheus metrics output",
268+
writtenMetrics.contains(
269+
"nn_top_user_op_counts_window_ms_60000_count{"));
270+
271+
Assert.assertTrue(
272+
"The expected metric line is missing from prometheus metrics output",
273+
writtenMetrics.contains(
274+
"nn_top_user_op_counts_window_ms_1500000_count{"));
275+
276+
Assert.assertTrue(
277+
"The expected metric line is missing from prometheus metrics output",
278+
writtenMetrics.contains(
279+
"op=\"rename\",user=\"hadoop/[email protected]\""));
280+
281+
metrics.stop();
282+
metrics.shutdown();
283+
}
284+
222285
/**
223286
* Example metric pojo.
224287
*/
@@ -242,4 +305,38 @@ String testTag1() {
242305
@Metric
243306
private MutableCounterLong numBucketCreateFails;
244307
}
308+
309+
/**
310+
* Example metric TopMetrics.
311+
*/
312+
private class TestTopMetrics implements MetricsSource {
313+
314+
public static final String TOPMETRICS_METRICS_SOURCE_NAME =
315+
"NNTopUserOpCounts";
316+
private final List<String> windowMsNames = new ArrayList<>();
317+
318+
public void add(String windowMs) {
319+
windowMsNames.add(String.format(".windowMs=%s", windowMs));
320+
}
321+
322+
@Override
323+
public void getMetrics(MetricsCollector collector, boolean all) {
324+
for (String windowMs : windowMsNames) {
325+
MetricsRecordBuilder rb = collector
326+
.addRecord(TOPMETRICS_METRICS_SOURCE_NAME + windowMs)
327+
.setContext("dfs");
328+
rb.addCounter(
329+
Interns.info("op=" + StringUtils.deleteWhitespace("rename")
330+
+ ".TotalCount", "Total operation count"), 2);
331+
rb.addCounter(
332+
Interns.info("op=" + StringUtils.deleteWhitespace("rename")
333+
+ ".user=" + "hadoop/[email protected]"
334+
+ ".count", "Total operations performed by user"), 3);
335+
rb.addCounter(
336+
Interns.info("op=" + StringUtils.deleteWhitespace("delete")
337+
+ ".user=" + "test_user2"
338+
+ ".count", "Total operations performed by user"), 4);
339+
}
340+
}
341+
}
245342
}

0 commit comments

Comments
 (0)