/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gobblin.metrics;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import gobblin.metrics.reporter.OutputStreamReporter;
@Test(groups = { "gobblin.metrics" })
public class OutputStreamReporterTest {
private ByteArrayOutputStream stream = new ByteArrayOutputStream();
@Test
public void testReporter() throws IOException {
MetricContext metricContext = MetricContext.builder(this.getClass().getCanonicalName()).build();
Counter counter = metricContext.counter("com.linkedin.example.counter");
Meter meter = metricContext.meter("com.linkedin.example.meter");
Histogram histogram = metricContext.histogram("com.linkedin.example.histogram");
OutputStreamReporter reporter =
OutputStreamReporter.Factory.newBuilder().outputTo(this.stream).build(new Properties());
counter.inc();
meter.mark(2);
histogram.update(1);
histogram.update(1);
histogram.update(2);
reporter.report();
String[] lines = this.stream.toString().split("\n");
Map<String, Set<String>> expected = new HashMap<>();
Set<String> counterSubMetrics = new HashSet<>();
counterSubMetrics.add("count");
expected.put("com.linkedin.example.counter", counterSubMetrics);
Set<String> histogramSubMetrics = new HashSet<>();
histogramSubMetrics.add("count");
histogramSubMetrics.add("min");
histogramSubMetrics.add("max");
histogramSubMetrics.add("mean");
histogramSubMetrics.add("stddev");
histogramSubMetrics.add("median");
histogramSubMetrics.add("75% <");
histogramSubMetrics.add("95% <");
expected.put("com.linkedin.example.histogram", histogramSubMetrics);
Set<String> meterSubmetrics = new HashSet<>();
meterSubmetrics.add("count");
meterSubmetrics.add("mean rate");
meterSubmetrics.add("1-minute rate");
meterSubmetrics.add("5-minute rate");
meterSubmetrics.add("15-minute rate");
expected.put("com.linkedin.example.meter", meterSubmetrics);
expectMetrics(expected, lines);
reporter.close();
}
@Test
public void testTags() throws IOException {
MetricContext metricContext = MetricContext.builder(this.getClass().getCanonicalName()).build();
Counter counter = metricContext.counter("com.linkedin.example.counter");
Map<String, String> tags = new HashMap<>();
tags.put("testKey", "testValue");
tags.put("key2", "value2");
OutputStreamReporter reporter =
OutputStreamReporter.Factory.newBuilder().withTags(tags).outputTo(this.stream).build(new Properties());
counter.inc();
reporter.report();
Assert.assertTrue(this.stream.toString().contains("key2=value2"));
Assert.assertTrue(this.stream.toString().contains("testKey=testValue"));
String[] lines = this.stream.toString().split("\n");
Map<String, Set<String>> expected = new HashMap<>();
expectMetrics(expected, lines);
Set<String> counterSubMetrics = new HashSet<>();
counterSubMetrics.add("count");
expected.put("com.linkedin.example.counter", counterSubMetrics);
reporter.close();
}
@Test
public void testTagsFromContext() throws IOException {
Tag<?> tag1 = new Tag<>("tag1", "value1");
MetricContext context = MetricContext.builder("context").addTag(tag1).build();
Counter counter = context.counter("com.linkedin.example.counter");
OutputStreamReporter reporter =
OutputStreamReporter.Factory.newBuilder().outputTo(this.stream).build(new Properties());
counter.inc();
reporter.report();
Assert.assertTrue(this.stream.toString().contains("tag1=value1"));
String[] lines = this.stream.toString().split("\n");
Map<String, Set<String>> expected = new HashMap<>();
expectMetrics(expected, lines);
Set<String> counterSubMetrics = new HashSet<>();
counterSubMetrics.add("count");
expected.put("com.linkedin.example.counter", counterSubMetrics);
reporter.close();
}
@BeforeMethod
public void before() {
this.stream.reset();
}
private void expectMetrics(Map<String, Set<String>> metrics, String[] lines) {
Set<String> activeSet = new HashSet<>();
String activeTopLevel = "";
for (String line : lines) {
System.out.println(line);
if (line.contains("com.linkedin.example")) {
Assert.assertTrue(activeSet.isEmpty(), String.format("%s does not contain all expected submetrics. Missing: %s",
activeTopLevel, Arrays.toString(activeSet.toArray())));
activeTopLevel = line.trim();
if (metrics.containsKey(activeTopLevel)) {
activeSet = metrics.get(activeTopLevel);
metrics.remove(activeTopLevel);
} else {
activeSet = new HashSet<>();
}
} else if (line.contains("=")) {
String submetric = line.split("=")[0].trim();
activeSet.remove(submetric);
}
}
Assert.assertTrue(activeSet.isEmpty(), String.format("%s does not contain all expected submetrics. Missing: %s",
activeTopLevel, Arrays.toString(activeSet.toArray())));
Assert.assertTrue(metrics.isEmpty(),
String.format("Output does not contain all expected top level metrics. Missing: %s",
Arrays.toString(metrics.keySet().toArray())));
}
}