/** * Create a MetricName with the given name, group and tags, plus default tags specified in the metric * configuration. Tag in tags takes precedence if the same tag key is specified in the default metric configuration. * * @param name The name of the metric * @param group logical group name of the metrics to which this metric belongs * @param tags key/value attributes of the metric */ public MetricName metricName(String name, String group, Map<String, String> tags) { return metricName(name, group, "", tags); }
private static MetricName metricName(Metrics metrics, String name) { return metrics.metricName(name, "app-info", "Metric indicating " + name); }
/** * Create a MetricName with the given name, group, description, and default tags * specified in the metric configuration. * * @param name The name of the metric * @param group logical group name of the metrics to which this metric belongs * @param description A human-readable description to include in the metric */ public MetricName metricName(String name, String group, String description) { return metricName(name, group, description, new HashMap<String, String>()); }
/** * Create a MetricName with the given name, group and default tags specified in the metric configuration. * * @param name The name of the metric * @param group logical group name of the metrics to which this metric belongs */ public MetricName metricName(String name, String group) { return metricName(name, group, "", new HashMap<String, String>()); }
private Meter createIOThreadRatioMeter(Metrics metrics, String groupName, Map<String, String> metricTags, String baseName, String action) { MetricName rateMetricName = metrics.metricName(baseName + "-ratio", groupName, String.format("The fraction of time the I/O thread spent %s", action), metricTags); MetricName totalMetricName = metrics.metricName(baseName + "time-total", groupName, String.format("The total time the I/O thread spent %s", action), metricTags); return new Meter(TimeUnit.NANOSECONDS, rateMetricName, totalMetricName); }
/** * Create a MetricName with the given name, group, description, and keyValue as tags, plus default tags specified in the metric * configuration. Tag in keyValue takes precedence if the same tag key is specified in the default metric configuration. * * @param name The name of the metric * @param group logical group name of the metrics to which this metric belongs * @param description A human-readable description to include in the metric * @param keyValue additional key/value attributes of the metric (must come in pairs) */ public MetricName metricName(String name, String group, String description, String... keyValue) { return metricName(name, group, description, getTags(keyValue)); }
private Meter createMeter(Metrics metrics, String groupName, Map<String, String> metricTags, SampledStat stat, String baseName, String descriptiveName) { MetricName rateMetricName = metrics.metricName(baseName + "-rate", groupName, String.format("The number of %s per second", descriptiveName), metricTags); MetricName totalMetricName = metrics.metricName(baseName + "-total", groupName, String.format("The total number of %s", descriptiveName), metricTags); if (stat == null) return new Meter(rateMetricName, totalMetricName); else return new Meter(stat, rateMetricName, totalMetricName); }
protected Meter createMeter(Metrics metrics, String groupName, String baseName, String descriptiveName) { return new Meter(new Count(), metrics.metricName(baseName + "-rate", groupName, String.format("The number of %s per second", descriptiveName)), metrics.metricName(baseName + "-total", groupName, String.format("The total number of %s", descriptiveName))); }
/** * Create a new buffer pool * * @param memory The maximum amount of memory that this buffer pool can allocate * @param poolableSize The buffer size to cache in the free list rather than deallocating * @param metrics instance of Metrics * @param time time instance * @param metricGrpName logical group name for metrics */ public BufferPool(long memory, int poolableSize, Metrics metrics, Time time, String metricGrpName) { this.poolableSize = poolableSize; this.lock = new ReentrantLock(); this.free = new ArrayDeque<>(); this.waiters = new ArrayDeque<>(); this.totalMemory = memory; this.nonPooledAvailableMemory = memory; this.metrics = metrics; this.time = time; this.waitTime = this.metrics.sensor(WAIT_TIME_SENSOR_NAME); MetricName rateMetricName = metrics.metricName("bufferpool-wait-ratio", metricGrpName, "The fraction of time an appender waits for space allocation."); MetricName totalMetricName = metrics.metricName("bufferpool-wait-time-total", metricGrpName, "The total time an appender waits for space allocation."); this.waitTime.add(new Meter(TimeUnit.NANOSECONDS, rateMetricName, totalMetricName)); }
public MetricName metricInstance(MetricNameTemplate template, Map<String, String> tags) { // check to make sure that the runtime defined tags contain all the template tags. Set<String> runtimeTagKeys = new HashSet<>(tags.keySet()); runtimeTagKeys.addAll(config().tags().keySet()); Set<String> templateTagKeys = template.tags(); if (!runtimeTagKeys.equals(templateTagKeys)) { throw new IllegalArgumentException("For '" + template.name() + "', runtime-defined metric tags do not match the tags in the template. " + "Runtime = " + runtimeTagKeys.toString() + " Template = " + templateTagKeys.toString()); } return this.metricName(template.name(), template.group(), template.description(), tags); }
@Test public void testMetricName() { MetricName n1 = metrics.metricName("name", "group", "description", "key1", "value1", "key2", "value2"); Map<String, String> tags = new HashMap<String, String>(); tags.put("key1", "value1"); tags.put("key2", "value2"); MetricName n2 = metrics.metricName("name", "group", "description", tags); assertEquals("metric names created in two different ways should be equal", n1, n2); try { metrics.metricName("name", "group", "description", "key1"); fail("Creating MetricName with an odd number of keyValue should fail"); } catch (IllegalArgumentException e) { // this is expected } }
private ConsumerCoordinatorMetrics(Metrics metrics, String metricGrpPrefix) { this.metricGrpName = metricGrpPrefix + "-coordinator-metrics"; this.commitLatency = metrics.sensor("commit-latency"); this.commitLatency.add(metrics.metricName("commit-latency-avg", this.metricGrpName, "The average time taken for a commit request"), new Avg()); this.commitLatency.add(metrics.metricName("commit-latency-max", this.metricGrpName, "The max time taken for a commit request"), new Max()); this.commitLatency.add(createMeter(metrics, metricGrpName, "commit", "commit calls")); Measurable numParts = new Measurable() { public double measure(MetricConfig config, long now) { // Get the number of assigned partitions in a thread safe manner return subscriptions.numAssignedPartitions(); } }; metrics.addMetric(metrics.metricName("assigned-partitions", this.metricGrpName, "The number of partitions currently assigned to this consumer"), numParts); } }
@Test public void testRemoveMetric() { int size = metrics.metrics().size(); metrics.addMetric(metrics.metricName("test1", "grp1"), new Count()); metrics.addMetric(metrics.metricName("test2", "grp1"), new Count()); assertNotNull(metrics.removeMetric(metrics.metricName("test1", "grp1"))); assertNull(metrics.metrics().get(metrics.metricName("test1", "grp1"))); assertNotNull(metrics.metrics().get(metrics.metricName("test2", "grp1"))); assertNotNull(metrics.removeMetric(metrics.metricName("test2", "grp1"))); assertNull(metrics.metrics().get(metrics.metricName("test2", "grp1"))); assertEquals(size, metrics.metrics().size()); }
@Test(expected = IllegalArgumentException.class) public void testDuplicateMetricName() { metrics.sensor("test").add(metrics.metricName("test", "grp1"), new Avg()); metrics.sensor("test2").add(metrics.metricName("test", "grp1"), new Total()); }
@Before public void setup() throws Exception { metrics = new Metrics(); metrics.addReporter(new JmxReporter()); sensor = metrics.sensor("kafka.requests"); countMetricName = metrics.metricName("pack.bean1.count", "grp1"); sensor.add(countMetricName, new Count()); sumMetricName = metrics.metricName("pack.bean1.sum", "grp1"); sensor.add(sumMetricName, new Sum()); }
public static void main(String[] args) { long iters = Long.parseLong(args[0]); Metrics metrics = new Metrics(); try { Sensor parent = metrics.sensor("parent"); Sensor child = metrics.sensor("child", parent); for (Sensor sensor : Arrays.asList(parent, child)) { sensor.add(metrics.metricName(sensor.name() + ".avg", "grp1"), new Avg()); sensor.add(metrics.metricName(sensor.name() + ".count", "grp1"), new Count()); sensor.add(metrics.metricName(sensor.name() + ".max", "grp1"), new Max()); sensor.add(new Percentiles(1024, 0.0, iters, BucketSizing.CONSTANT, new Percentile(metrics.metricName(sensor.name() + ".median", "grp1"), 50.0), new Percentile(metrics.metricName(sensor.name() + ".p_99", "grp1"), 99.0))); } long start = System.nanoTime(); for (int i = 0; i < iters; i++) parent.record(i); double ellapsed = (System.nanoTime() - start) / (double) iters; System.out.println(String.format("%.2f ns per metric recording.", ellapsed)); } finally { metrics.close(); } } }
@Test public void testIdempotentAdd() { final Metrics metrics = new Metrics(); final Sensor sensor = metrics.sensor("sensor"); assertTrue(sensor.add(metrics.metricName("test-metric", "test-group"), new Avg())); // adding the same metric to the same sensor is a no-op assertTrue(sensor.add(metrics.metricName("test-metric", "test-group"), new Avg())); // but adding the same metric to a DIFFERENT sensor is an error final Sensor anotherSensor = metrics.sensor("another-sensor"); try { anotherSensor.add(metrics.metricName("test-metric", "test-group"), new Avg()); fail("should have thrown"); } catch (final IllegalArgumentException ignored) { // pass } // note that adding a different metric with the same name is also a no-op assertTrue(sensor.add(metrics.metricName("test-metric", "test-group"), new Sum())); // so after all this, we still just have the original metric registered assertEquals(1, sensor.metrics().size()); assertEquals(org.apache.kafka.common.metrics.stats.Avg.class, sensor.metrics().get(0).measurable().getClass()); }
@Test public void testFetcherMetrics() { subscriptions.assignFromUser(singleton(tp0)); subscriptions.seek(tp0, 0); MetricName maxLagMetric = metrics.metricInstance(metricsRegistry.recordsLagMax); Map<String, String> tags = new HashMap<>(); tags.put("topic", tp0.topic()); tags.put("partition", String.valueOf(tp0.partition())); MetricName partitionLagMetric = metrics.metricName("records-lag", metricGroup, tags); Map<MetricName, KafkaMetric> allMetrics = metrics.metrics(); KafkaMetric recordsFetchLagMax = allMetrics.get(maxLagMetric); // recordsFetchLagMax should be initialized to NaN assertEquals(Double.NaN, (Double) recordsFetchLagMax.metricValue(), EPSILON); // recordsFetchLagMax should be hw - fetchOffset after receiving an empty FetchResponse fetchRecords(tp0, MemoryRecords.EMPTY, Errors.NONE, 100L, 0); assertEquals(100, (Double) recordsFetchLagMax.metricValue(), EPSILON); KafkaMetric partitionLag = allMetrics.get(partitionLagMetric); assertEquals(100, (Double) partitionLag.metricValue(), EPSILON); // recordsFetchLagMax should be hw - offset of the last message after receiving a non-empty FetchResponse MemoryRecordsBuilder builder = MemoryRecords.builder(ByteBuffer.allocate(1024), CompressionType.NONE, TimestampType.CREATE_TIME, 0L); for (int v = 0; v < 3; v++) builder.appendWithOffset(v, RecordBatch.NO_TIMESTAMP, "key".getBytes(), ("value-" + v).getBytes()); fetchRecords(tp0, builder.build(), Errors.NONE, 200L, 0); assertEquals(197, (Double) recordsFetchLagMax.metricValue(), EPSILON); assertEquals(197, (Double) partitionLag.metricValue(), EPSILON); // verify de-registration of partition lag subscriptions.unsubscribe(); assertFalse(allMetrics.containsKey(partitionLagMetric)); }
@Test public void testQuotas() { Sensor sensor = metrics.sensor("test"); sensor.add(metrics.metricName("test1.total", "grp1"), new Total(), new MetricConfig().quota(Quota.upperBound(5.0))); sensor.add(metrics.metricName("test2.total", "grp1"), new Total(), new MetricConfig().quota(Quota.lowerBound(0.0))); sensor.record(5.0); try { sensor.record(1.0); fail("Should have gotten a quota violation."); } catch (QuotaViolationException e) { // this is good } assertEquals(6.0, (Double) metrics.metrics().get(metrics.metricName("test1.total", "grp1")).metricValue(), EPS); sensor.record(-6.0); try { sensor.record(-1.0); fail("Should have gotten a quota violation."); } catch (QuotaViolationException e) { // this is good } }
@Test public void testExpiredSensor() { MetricConfig config = new MetricConfig(); Time mockTime = new MockTime(); Metrics metrics = new Metrics(config, Arrays.asList((MetricsReporter) new JmxReporter()), mockTime, true); long inactiveSensorExpirationTimeSeconds = 60L; Sensor sensor = new Sensor(metrics, "sensor", null, config, mockTime, inactiveSensorExpirationTimeSeconds, Sensor.RecordingLevel.INFO); assertTrue(sensor.add(metrics.metricName("test1", "grp1"), new Avg())); Map<String, String> emptyTags = Collections.emptyMap(); MetricName rateMetricName = new MetricName("rate", "test", "", emptyTags); MetricName totalMetricName = new MetricName("total", "test", "", emptyTags); Meter meter = new Meter(rateMetricName, totalMetricName); assertTrue(sensor.add(meter)); mockTime.sleep(TimeUnit.SECONDS.toMillis(inactiveSensorExpirationTimeSeconds + 1)); assertFalse(sensor.add(metrics.metricName("test3", "grp1"), new Avg())); assertFalse(sensor.add(meter)); metrics.close(); }