diff --git a/spec/src/main/asciidoc/app-programming-model.adoc b/spec/src/main/asciidoc/app-programming-model.adoc index 34d54f01..d879669a 100644 --- a/spec/src/main/asciidoc/app-programming-model.adoc +++ b/spec/src/main/asciidoc/app-programming-model.adoc @@ -62,7 +62,9 @@ in <>. and throw an `IllegalArgumentException` if such duplicate exists ** See <> for more details. * The implementation must flag and reject metrics upon registration if the metadata information being registered is not equivalent to the metadata information that has already been registered under the given metric name (if it already exists). -** All metrics of a given metric name must be associated with the same metadata information +** All metrics of a given metric name must be associated with the same metadata information. +** The implementation must throw an `IllegalArgumentException` when the metric is rejected. +* The implementation must flag and reject metrics upon registration if the names of the tags is not equivalent to those already registered under the given metric name (if it already exists). The values of the tag may differ, but the name/key of the tags must be the same. ** The implementation must throw an `IllegalArgumentException` when the metric is rejected. * The implementation must throw an `IllegalStateException` if an annotated metric is invoked, but the metric no longer exists in the MetricRegistry. This applies to the following annotations : @Timed, @Counted * The implementation must make sure that metric registries are thread-safe, in other words, concurrent calls to methods of `MetricRegistry` must not leave the registry in an inconsistent state. diff --git a/spec/src/main/asciidoc/architecture.adoc b/spec/src/main/asciidoc/architecture.adoc index 421ff59a..aee1b8e5 100644 --- a/spec/src/main/asciidoc/architecture.adoc +++ b/spec/src/main/asciidoc/architecture.adoc @@ -195,7 +195,7 @@ There is one `MetricRegistry` instance for each of the predefined scopes listed Metrics can be added to or retrieved from the registry either using the `@Metric` annotation (see <>) or using the `MetricRegistry` object directly. -A metric is uniquely identified by the `MetricRegistry` if the `MetricID` associated with the metric is unique. That is to say, there are no other metrics with the same combination of metric name and tags. However, all metrics of the same name must be of the same type otherwise an `IllegalArgumentException` will be thrown. This exception will be thrown during registration. +A metric is uniquely identified by the `MetricRegistry` if the `MetricID` associated with the metric is unique. That is to say, there are no other metrics with the same combination of metric name and tags. However, all metrics of the same name must be of the same type and contain the same set of tag names otherwise an `IllegalArgumentException` will be thrown. This exception will be thrown during registration. The metadata information is registered under a unique metric name and is immutable. All metrics of the same name must be registered with the same metadata information otherwise an "IllegalArgumentException" will be thrown. This exception will be thrown during registration. diff --git a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/MetricIDTest.java b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/MetricIDTest.java index ab5edc93..c347ac1f 100644 --- a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/MetricIDTest.java +++ b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/MetricIDTest.java @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (c) 2019 Contributors to the Eclipse Foundation + * Copyright (c) 2019, 2022 Contributors to the Eclipse Foundation * * See the NOTICES file(s) distributed with this work for additional * information regarding copyright ownership. @@ -63,24 +63,25 @@ public void removalTest() { Tag tagBlue = new Tag("colour", "blue"); String counterName = "org.eclipse.microprofile.metrics.tck.MetricIDTest.counterColour"; + String counterNameNoTag = "org.eclipse.microprofile.metrics.tck.MetricIDTest.counter"; - Counter counterColour = registry.counter(counterName); + Counter counter = registry.counter(counterNameNoTag); Counter counterRed = registry.counter(counterName, tagEarth, tagRed); Counter counterBlue = registry.counter(counterName, tagEarth, tagBlue); - MetricID counterColourMID = new MetricID(counterName); + MetricID counterMID = new MetricID(counterNameNoTag); MetricID counterRedMID = new MetricID(counterName, tagEarth, tagRed); MetricID counterBlueMID = new MetricID(counterName, tagEarth, tagRed); // check multi-dimensional metrics are registered - assertThat("Counter is not registered correctly", registry.getCounter(counterColourMID), notNullValue()); + assertThat("Counter is not registered correctly", registry.getCounter(counterMID), notNullValue()); assertThat("Counter is not registered correctly", registry.getCounter(counterRedMID), notNullValue()); assertThat("Counter is not registered correctly", registry.getCounter(counterBlueMID), notNullValue()); // remove one metric - registry.remove(counterColourMID); + registry.remove(counterMID); assertThat("Registry did not remove metric", registry.getCounters().size(), equalTo(2)); - assertThat("Counter is not registered correctly", registry.getCounter(counterColourMID), nullValue()); + assertThat("Counter is not registered correctly", registry.getCounter(counterMID), nullValue()); // remove all metrics with the given name registry.remove(counterName); diff --git a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/MetricRegistryTest.java b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/MetricRegistryTest.java index dd490111..02531c06 100644 --- a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/MetricRegistryTest.java +++ b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/MetricRegistryTest.java @@ -92,16 +92,18 @@ public void removeTest() { public void useExistingMetaDataTest() { String metricName = "counterFoo"; + Tag orangeTag = new Tag("colour", "orange"); + Tag purpleTag = new Tag("colour", "purple"); + // first to register a "complex" metadata metrics.counter(Metadata.builder().withName(metricName) - .withType(MetricType.COUNTER).build()); + .withType(MetricType.COUNTER).build(), orangeTag); - Tag purpleTag = new Tag("colour", "purple"); // creates with a simple/template metadata or uses an existing one. metrics.counter(metricName, purpleTag); // check both counters have been registered - assertExists(Counter.class, new MetricID(metricName)); + assertExists(Counter.class, new MetricID(metricName, orangeTag)); assertExists(Counter.class, new MetricID(metricName, purpleTag)); } diff --git a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/tags/TagsTest.java b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/tags/TagsTest.java index bea16d7d..8a3bbed9 100644 --- a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/tags/TagsTest.java +++ b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/tags/TagsTest.java @@ -24,8 +24,10 @@ import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.hasValue; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import org.eclipse.microprofile.metrics.Counter; import org.eclipse.microprofile.metrics.Histogram; @@ -33,6 +35,7 @@ import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.Tag; import org.eclipse.microprofile.metrics.Timer; +import org.hamcrest.Matchers; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.junit.InSequence; @@ -76,7 +79,7 @@ public void lastTagValueTest() { Tag tagColour = new Tag("colour", "red"); Tag tagColourTwo = new Tag("colour", "blue"); - String counterName = "org.eclipse.microprofile.metrics.tck.TagTest.counter"; + String counterName = "org.eclipse.microprofile.metrics.tck.TagTest.counter.lastTag"; Counter counter = registry.counter(counterName, tagColour, tagColourTwo); // MetricID that only has colour=blue... the last tag value to be passed in @@ -95,12 +98,13 @@ public void counterTagsTest() { Tag tagBlue = new Tag("colour", "blue"); String counterName = "org.eclipse.microprofile.metrics.tck.TagTest.counterColour"; + String counterNameNoTag = "org.eclipse.microprofile.metrics.tck.TagTest.counter"; - Counter counterColour = registry.counter(counterName); + Counter counter = registry.counter(counterNameNoTag); Counter counterRed = registry.counter(counterName, tagEarth, tagRed); Counter counterBlue = registry.counter(counterName, tagEarth, tagBlue); - MetricID counterColourMID = new MetricID(counterName); + MetricID counterColourMID = new MetricID(counterNameNoTag); MetricID counterRedMID = new MetricID(counterName, tagEarth, tagRed); MetricID counterBlueMID = new MetricID(counterName, tagEarth, tagBlue); @@ -119,12 +123,13 @@ public void timerTagsTest() { Tag tagBlue = new Tag("colour", "blue"); String timerName = "org.eclipse.microprofile.metrics.tck.TagTest.timerColour"; + String timerNameNoTag = "org.eclipse.microprofile.metrics.tck.TagTest.timer"; - Timer timerColour = registry.timer(timerName); + Timer timerColour = registry.timer(timerNameNoTag); Timer timerRed = registry.timer(timerName, tagEarth, tagRed); Timer timerBlue = registry.timer(timerName, tagEarth, tagBlue); - MetricID timerColourMID = new MetricID(timerName); + MetricID timerColourMID = new MetricID(timerNameNoTag); MetricID timerRedMID = new MetricID(timerName, tagEarth, tagRed); MetricID timerBlueMID = new MetricID(timerName, tagEarth, tagBlue); @@ -143,12 +148,13 @@ public void histogramTagsTest() { Tag tagBlue = new Tag("colour", "blue"); String histogramName = "org.eclipse.microprofile.metrics.tck.TagTest.histogramColour"; + String histogramNameNoTag = "org.eclipse.microprofile.metrics.tck.TagTest.histogram"; - Histogram histogramColour = registry.histogram(histogramName); + Histogram histogramColour = registry.histogram(histogramNameNoTag); Histogram histogramRed = registry.histogram(histogramName, tagEarth, tagRed); Histogram histogramBlue = registry.histogram(histogramName, tagEarth, tagBlue); - MetricID histogramColourMID = new MetricID(histogramName); + MetricID histogramColourMID = new MetricID(histogramNameNoTag); MetricID histogramRedMID = new MetricID(histogramName, tagEarth, tagRed); MetricID histogramBlueMID = new MetricID(histogramName, tagEarth, tagBlue); @@ -157,4 +163,69 @@ public void histogramTagsTest() { assertThat("Histogram is not registered correctly", registry.getHistogram(histogramRedMID), notNullValue()); assertThat("Histogram is not registered correctly", registry.getHistogram(histogramBlueMID), notNullValue()); } + + @Test + @InSequence(6) + public void nonMatchingTagTest() { + Tag tagForNames = new Tag("name", "Bill"); + + String counterName = "org.eclipse.microprofile.metrics.tck.TagTest.counter.mismatch.tags"; + + Counter counter = registry.counter(counterName); + + try { + registry.counter(counterName, tagForNames); + + } catch (Exception cause) { + assertThat(cause, is(Matchers.instanceOf(IllegalArgumentException.class))); + return; + } + + fail("No exception was caught"); + + } + + @Test + @InSequence(7) + public void nonMatchingTagTest2() { + Tag tagForNames = new Tag("name", "Bill"); + Tag tagForAnimals = new Tag("animal", "dog"); + + String timerName = "org.eclipse.microprofile.metrics.tck.TagTest.timer.mismatch.tags"; + + Timer timer = registry.timer(timerName, tagForNames); + + try { + registry.timer(timerName, tagForAnimals); + + } catch (Exception cause) { + assertThat(cause, is(Matchers.instanceOf(IllegalArgumentException.class))); + return; + } + + fail("No exception was caught"); + + } + + @Test + @InSequence(8) + public void nonMatchingTagTest3() { + Tag tagForNames = new Tag("name", "Bill"); + Tag tagForAnimals = new Tag("animal", "dog"); + + String histogramName = "org.eclipse.microprofile.metrics.tck.TagTest.histogram.mismatch.tags"; + + Histogram histogram = registry.histogram(histogramName, tagForNames); + + try { + registry.histogram(histogramName, tagForAnimals); + + } catch (Exception cause) { + assertThat(cause, is(Matchers.instanceOf(IllegalArgumentException.class))); + return; + } + + fail("No exception was caught"); + + } }