diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml
index 555944bd55789..475721a14fd4c 100644
--- a/.github/workflows/doc-build.yml
+++ b/.github/workflows/doc-build.yml
@@ -52,7 +52,8 @@ jobs:
key: q2maven-doc-${{ steps.get-date.outputs.date }}
- name: Build
run: |
- ./mvnw -Dquickly-ci -B --settings .github/mvn-settings.xml install
+ ./mvnw -Dquickly-ci -B -DskipDocs=false --settings .github/mvn-settings.xml install
+
- name: Build Docs
run: |
./mvnw -e -B --settings .github/mvn-settings.xml clean org.asciidoctor:asciidoctor-maven-plugin:process-asciidoc -pl docs -Ddocumentation-pdf
diff --git a/docs/pom.xml b/docs/pom.xml
index 9b40ac0c59e36..a22583d71d58d 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -23,6 +23,7 @@
https://quarkus.io
https://github.com/quarkusio/quarkus
https://github.com/quarkusio/quarkus-quickstarts
+ ${project.basedir}/../target/asciidoc/examples
Quarkus - Documentation
@@ -2794,6 +2795,25 @@
+
+ copy-tagged-java-source
+ process-classes
+
+ java
+
+
+ ${skipDocs}
+ io.quarkus.docs.generation.CopyExampleSource
+
+ ${code-example-dir}
+ ${project.basedir}/..
+ ${project.basedir}/src/main/asciidoc
+
+
+ ${env.MAVEN_CMD_LINE_ARGS}
+
+
+
generate-doc-manifests
prepare-package
@@ -2830,6 +2850,7 @@
true
${project.basedir}/../target/asciidoc/generated
+ ${code-example-dir}
./images
font
true
@@ -2912,7 +2933,7 @@
https://quarkiverse.github.io/quarkiverse-docs/quarkus-neo4j/dev/index.html
https://quarkiverse.github.io/quarkiverse-docs/quarkus-vault/dev/index.html
https://quarkiverse.github.io/quarkiverse-docs/quarkus-vault/dev/vault-datasource.html
- https://quarkiverse.github.io/quarkiverse-docs/quarkus-micrometer-registry/dev/
+ https://quarkiverse.github.io/quarkiverse-docs/quarkus-micrometer-registry/dev/
diff --git a/docs/src/main/asciidoc/_examples/attributes.adoc b/docs/src/main/asciidoc/_examples/attributes.adoc
index 601d8289973a4..03eff399e165a 100644
--- a/docs/src/main/asciidoc/_examples/attributes.adoc
+++ b/docs/src/main/asciidoc/_examples/attributes.adoc
@@ -3,8 +3,9 @@
:idprefix:
:idseparator: -
:icons: font
+:code-examples: ../../../../../target/asciidoc/examples
:doc-guides: ..
:doc-examples: .
:imagesdir: ./images
:includes: ../includes
-:root: ../../asciidoc
+
diff --git a/docs/src/main/asciidoc/_templates/attributes.adoc b/docs/src/main/asciidoc/_templates/attributes.adoc
index 7b330a696f2b0..f7d6d8046196d 100644
--- a/docs/src/main/asciidoc/_templates/attributes.adoc
+++ b/docs/src/main/asciidoc/_templates/attributes.adoc
@@ -3,8 +3,8 @@
:idprefix:
:idseparator: -
:icons: font
+:code-examples: ../../../../../target/asciidoc/examples
:doc-guides: ..
:doc-examples: ../_examples
-:imagesdir: ../../asciidoc/images
+:imagesdir: ../images
:includes: ../includes
-:root: ../../asciidoc/
diff --git a/docs/src/main/asciidoc/attributes.adoc b/docs/src/main/asciidoc/attributes.adoc
index 36a0d40806710..efa26032c201f 100644
--- a/docs/src/main/asciidoc/attributes.adoc
+++ b/docs/src/main/asciidoc/attributes.adoc
@@ -4,8 +4,8 @@
:idprefix:
:idseparator: -
:icons: font
-// tag::xref-attributes[]
+:code-examples: ../../../../target/asciidoc/examples
+:doc-guides: ./
:doc-examples: ./_examples
:imagesdir: ./images
:includes: ./includes
-// end::xref-attributes[]
diff --git a/docs/src/main/asciidoc/doc-reference.adoc b/docs/src/main/asciidoc/doc-reference.adoc
index cbd77b52c10e1..bc434590ce30e 100644
--- a/docs/src/main/asciidoc/doc-reference.adoc
+++ b/docs/src/main/asciidoc/doc-reference.adoc
@@ -23,10 +23,10 @@ The Asciidoc files can be found in the `src/main/asciidoc` directory within the
Create new documentation files using the appropriate template for the content type:
-Concepts:: Use `src/main/asciidoc/_templates/template-concepts.adoc`
-How-To Guides:: Use `src/main/asciidoc/_templates/template-howto.adoc`
-Reference:: Use `src/main/asciidoc/_templates/template-reference.adoc`
-Tutorials:: Use `src/main/asciidoc/_templates/template-tutorial.adoc`
+Concepts:: Use `docs/src/main/asciidoc/_templates/template-concepts.adoc`
+How-To Guides:: Use `docs/src/main/asciidoc/_templates/template-howto.adoc`
+Reference:: Use `docs/src/main/asciidoc/_templates/template-reference.adoc`
+Tutorials:: Use `docs/src/main/asciidoc/_templates/template-tutorial.adoc`
== Output locations
@@ -183,10 +183,16 @@ Quarkus documentation is built from source in a few different environments.
We use attributes in our cross-references to ensure our docs can be built across these environments.
.Cross-reference source attributes
-[source,asciidoc]
-----
-include::attributes.adoc[tag=xref-attributes]
-----
+[cols="
----
-<1> The cross reference starts with `xref:`, uses a cross-reference source attribute(`\{doc-guides}`), and provides a readable description: `[Quarkus Documentation concepts]`
+<1> The cross reference starts with `xref:`, uses a cross-reference source attribute(`\{doc-guides}`), and provides a readable description: `[Quarkus Documentation concepts]`.
+
+=== Reference source code
+
+There are many ways to include source code and examples in documentation.
+
+The simplest is to write it directly in the file, like this:
+
+[source,asciidoc]
+-----
+[source,java]
+----
+System.out.println("Hello, World!");
+----
+-----
+
+In documents like tutorials, you may want to reference source code that is built and tested regularly.
+The Quarkus documentation module build will copy source files enumerated in `*-examples/yaml` files into a flattened structure in the `target/asciidoc/examples` directory (from the project root).
+
+[source,yaml]
+----
+examples:
+- source: path/to/source/file/SomeClassFile.java <1>
+ target: prefix-simplified-unique-filename.java <2>
+----
-=== Variables for use in documents
+<1> define the path of source to be copied
+<2> define the simplified target file name to use when copying the file into the `target/asciidoc/examples` directory. We recommend using the same prefix as the related/consuming documentation in the file name.
-The following variables externalize key information that can change over time, and so references
-to such information should be done by using the variable inside of {} curly brackets. The
-complete list of externalized variables for use is given in the following table:
+Content copied in this way is referenced using the `\{code-examples}` source attribute. If a copied file contains the literal string `{{source}}`, that literal value is replaced with the path of the source file.
+
+.Micrometer example
+* The source file to be copied is:
++
+`integration-tests/micrometer-prometheus/src/main/java/documentation/example/telemetry/micrometer/tutorial/ExampleResource.java`
+
+* The target file name we want to use in docs is:
++
+`telemetry-micrometer-tutorial-example-resource.java`.
+
+* The source and target file names are declared in `docs/src/main/asciidoc/telemetry-examples.yaml`:
++
+[source,yaml]
+----
+examples:
+- source: integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java
+ target: telemetry-micrometer-tutorial-example-resource.java
+----
+
+* Snippets from this source file are then included using the following path:
++
+`\{code-examples}/telemetry-micrometer-tutorial-example-resource.java`.
+* The source file contains the following comment:
+[source,java]
+----
+// Source: {{source}}
+----
+* The copied file contains this comment instead:
+[source,java]
+----
+// Source: integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java
+----
+
+=== Quarkus documentation variables
+
+The following variables externalize key information that can change over time. References
+to such information should use the variable inside of curly brackets, `{}`.
+
+The complete list of externalized variables for use is given in the following table:
.Variables
[cols=" Find or create a counter called `example.prime.number` that has a `type` label with the specified value.
+<2> Increment that counter.
+
+=== Review collected metrics
+
+If you did not leave Quarkus running in dev mode, start it again:
+
+include::{includes}/devtools/dev.adoc[]
+
+Try the following sequence and look for `example_prime_number_total` in the plain text
+output.
+
+Note that the `_total` suffix is added when Micrometer applies Prometheus naming conventions to
+`example.prime.number`, the originally specified counter name.
+
+[source,shell]
+----
+curl http://localhost:8080/example/prime/-1
+curl http://localhost:8080/example/prime/0
+curl http://localhost:8080/example/prime/1
+curl http://localhost:8080/example/prime/2
+curl http://localhost:8080/example/prime/3
+curl http://localhost:8080/example/prime/15
+curl http://localhost:8080/q/metrics
+----
+
+Notice that there is one measured value for each unique combination of `example_prime_number_total` and `type` value.
+
+Looking at the dimensional data produced by this counter, you can count:
+
+- how often a negative number was checked: `type="not-natural"`
+- how often the number one was checked: `type="one"`
+- how often an even number was checked: `type="even"`
+- how often a prime number was checked: `type="prime"`
+- how often a non-prime number was checked: `type="not-prime"`
+
+You can also count how often a number was checked (generally) by aggregating all of these values together.
+
+== Add a Timer
+
+Timers are a specialized abstraction for measuring duration. Let's add a timer to measure how long it takes to determine if a number is prime.
+
+[source,java]
+----
+include::{code-examples}/telemetry-micrometer-tutorial-example-resource.java[tags=timed;!ignore;!default]
+----
+
+<1> Find or create a counter called `example.prime.number` that has a `type` label with the specified value.
+<2> Increment that counter.
+<3> Call a method that wraps the original `testPrimeNumber` method.
+<4> Create a `Timer.Sample` that tracks the start time
+<5> Call the method to be timed and store the boolean result
+<6> Find or create a `Timer` using the specified id and a `prime` label with the result value, and record the duration captured by the `Timer.Sample`.
+
+=== Review collected metrics
+
+If you did not leave Quarkus running in dev mode, start it again:
+
+include::{includes}/devtools/dev.adoc[]
+
+Micrometer will apply Prometheus conventions when emitting metrics for this timer.
+Specifically, measured durations are converted into seconds and this unit is included in the metric name.
+
+Try the following sequence and look for the following entries in the plain text output:
+
+- `example_prime_number_test_seconds_count` -- how many times the method was called
+- `example_prime_number_test_seconds_sum` -- the total duration of all method calls
+- `example_prime_number_test_seconds_max` -- the maximum observed duration within a decaying interval. This value will return to 0 if the method is not invoked frequently.
+
+[source,shell]
+----
+curl http://localhost:8080/example/prime/256
+curl http://localhost:8080/q/metrics
+curl http://localhost:8080/example/prime/7919
+curl http://localhost:8080/q/metrics
+----
+
+Looking at the dimensional data produced by this counter, you can use the sum and the count to calculate how long (on average) it takes to determine if a number is prime. Using the dimensional label, you might be able to understand if there is a significant difference in duration for numbers that are prime when compared with numbers that are not.
+
+:sectnums!:
+== Summary
+
+Congratulations!
+
+You have created a project that uses the Micrometer and Prometheus Meter Registry extensions to collect metrics. You've observed some of the metrics that Quarkus captures automatically, and have added a `Counter` and `Timer` that are unique to the application. You've also added dimensional labels to metrics, and have observed how those labels shape the data emitted by the prometheus endpoint.
+
+
+
diff --git a/docs/src/main/java/io/quarkus/docs/generation/CopyExampleSource.java b/docs/src/main/java/io/quarkus/docs/generation/CopyExampleSource.java
new file mode 100755
index 0000000000000..e8ccbb845fada
--- /dev/null
+++ b/docs/src/main/java/io/quarkus/docs/generation/CopyExampleSource.java
@@ -0,0 +1,171 @@
+package io.quarkus.docs.generation;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
+
+public class CopyExampleSource {
+
+ static Path docsDir() {
+ Path path = Paths.get(System.getProperty("user.dir"));
+ if (path.endsWith("docs")) {
+ return path;
+ }
+ return path.resolve("docs");
+ }
+
+ public Path outputPath;
+ public Path rootPath;
+ public List srcPaths;
+ Map allTargets = new HashMap<>();
+
+ // Two arguments:
+ // ${project.basedir}/../target/asciidoc/generated/examples ${project.basedir}/.. ${project.basedir}/src/main/asciidoc
+ public static void main(String[] args) throws Exception {
+ CopyExampleSource copyExamples = new CopyExampleSource();
+
+ // Required first parameter: Target output directory
+ if (args.length < 1) {
+ System.err.println("Must specify target output directory");
+ System.exit(1);
+ }
+ copyExamples.outputPath = Path.of(args[0]).normalize();
+ System.out.println("[INFO] Output directory: " + copyExamples.outputPath);
+
+ // Optional second parameter: Project root directory
+ if (args.length > 1) {
+ copyExamples.rootPath = Path.of(args[1]).normalize();
+ } else {
+ copyExamples.rootPath = docsDir().resolve("..").normalize();
+ }
+ System.out.println("[INFO] Project root: " + copyExamples.rootPath);
+
+ // third parameter and on .. source paths
+ if (args.length > 2) {
+ copyExamples.srcPaths = Arrays.stream(args).skip(2)
+ .map(x -> Path.of(x).normalize())
+ .collect(Collectors.toList());
+ } else {
+ copyExamples.srcPaths = List.of(docsDir().resolve("src/main/asciidoc").normalize());
+ }
+
+ try {
+ copyExamples.run();
+ } catch (Exception e) {
+ System.err.println("Exception occurred while trying to copy examples");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ public void run() throws Exception {
+ Files.createDirectories(outputPath);
+ ObjectMapper om = new ObjectMapper(new YAMLFactory().enable(YAMLGenerator.Feature.MINIMIZE_QUOTES))
+ .setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
+
+ for (Path path : srcPaths) {
+ Files.walkFileTree(path, new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
+ if (path.toString().endsWith("-examples.yaml")) {
+ System.out.println("[INFO] Reading: " + path);
+
+ MappingList mapping = om.readValue(path.toFile(), MappingList.class);
+
+ // For each example:
+ for (Example example : mapping.examples) {
+
+ // Resolve the source path against the root directory
+ Path relativePath = Path.of(example.source);
+ Path sourcePath = rootPath.resolve(relativePath);
+ // Resolve the target path against the output directory
+ Path targetPath = outputPath.resolve(example.target);
+
+ if (Files.exists(sourcePath)) {
+ // Record an error if the target already exists
+ String former = allTargets.put(example.target, example.source);
+ if (former != null) {
+ System.err.printf(
+ "[ERROR] Duplicate target: %s%n Previous value: %s%n New value: %s%n",
+ example.target, former, example.source);
+
+ mapping.duplicateKey = true;
+ continue;
+ }
+
+ // Make sure required target directories exist
+ Files.createDirectories(targetPath.getParent());
+
+ // Copy the source file to the target file.
+ // Replace {{source}} in comment lines with the relative source path
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(Files.newInputStream(sourcePath, StandardOpenOption.READ),
+ "UTF-8"))) {
+ try (PrintWriter bw = new PrintWriter(new OutputStreamWriter(
+ Files.newOutputStream(targetPath, StandardOpenOption.CREATE,
+ StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (line.startsWith("// Source: {{source}}")) {
+ bw.println("// Source: " + relativePath);
+ } else if (line.startsWith("# Source: {{source}}")) {
+ bw.println("# Source: " + relativePath);
+ } else {
+ bw.println(line);
+ }
+ }
+ System.out.printf("[INFO] Copied %s %n to %s%n", relativePath, targetPath);
+ }
+ } catch (IOException ioe) {
+ System.err.printf("[ERROR] Error copying %s %n to %s%n", relativePath,
+ targetPath);
+ throw ioe;
+ }
+ } else {
+ System.err.println("[ERROR] Specified source file doesn't exist: " + sourcePath);
+ mapping.missingSource = true;
+ }
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+ }
+
+ static class MappingList {
+ List examples;
+
+ @JsonIgnore
+ boolean missingSource = false;
+
+ @JsonIgnore
+ boolean duplicateKey = false;
+ }
+
+ static class Example {
+ String source;
+ String target;
+ }
+}
diff --git a/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/ExampleResource.java b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java
similarity index 50%
rename from integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/ExampleResource.java
rename to integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java
index 627344ea7505d..f66df272b1d5e 100644
--- a/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/it/micrometer/prometheus/ExampleResource.java
+++ b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java
@@ -1,5 +1,15 @@
-package io.quarkus.it.micrometer.prometheus;
+// tag::example[]
+// tag::ignore[]
+// Source: {{source}}
+package io.quarkus.doc.micrometer;
+/*
+// end::ignore[]
+package org.acme.micrometer;
+
+// tag::ignore[]
+*/
+// end::ignore[]
import java.util.LinkedList;
import java.util.NoSuchElementException;
@@ -15,15 +25,18 @@
@Path("/example")
@Produces("text/plain")
public class ExampleResource {
-
+ private final LinkedList list = new LinkedList<>();
+ // tag::registry[]
private final MeterRegistry registry;
- LinkedList list = new LinkedList<>();
-
ExampleResource(MeterRegistry registry) {
this.registry = registry;
+ // tag::gauge[]
registry.gaugeCollectionSize("example.list.size", Tags.empty(), list);
+ // end::gauge[]
}
+ // end::registry[]
+ // tag::gauge[]
@GET
@Path("gauge/{number}")
@@ -41,41 +54,80 @@ public Long checkListSize(@PathParam("number") long number) {
}
return number;
}
+ // end::gauge[]
+ // tag::timed[]
+ // tag::counted[]
@GET
@Path("prime/{number}")
public String checkIfPrime(@PathParam("number") long number) {
if (number < 1) {
- registry.counter("example.prime.number", "type", "not-natural").increment();
+ // tag::counter[]
+ registry.counter("example.prime.number", "type", "not-natural") // <1>
+ .increment(); // <2>
+ // end::counter[]
return "Only natural numbers can be prime numbers.";
}
if (number == 1) {
- registry.counter("example.prime.number", "type", "one").increment();
+ // tag::counter[]
+ registry.counter("example.prime.number", "type", "one") // <1>
+ .increment(); // <2>
+ // end::counter[]
return number + " is not prime.";
}
if (number == 2 || number % 2 == 0) {
- registry.counter("example.prime.number", "type", "even").increment();
+ // tag::counter[]
+ registry.counter("example.prime.number", "type", "even") // <1>
+ .increment(); // <2>
+ // end::counter[]
return number + " is not prime.";
}
- if (testPrimeNumber(number)) {
- registry.counter("example.prime.number", "type", "prime").increment();
+ // tag::timer[]
+ if (timedTestPrimeNumber(number)) { // <3>
+ // end::timer[]
+ // tag::ignore[]
+ /*
+ * }
+ * // end::ignore[]
+ * // tag::default[]
+ * if (testPrimeNumber(number)) {
+ * // end::default[]
+ * // tag::ignore[]
+ */
+ // end::ignore[]
+ // tag::counter[]
+ registry.counter("example.prime.number", "type", "prime") // <1>
+ .increment(); // <2>
+ // end::counter[]
return number + " is prime.";
} else {
- registry.counter("example.prime.number", "type", "not-prime").increment();
+ // tag::counter[]
+ registry.counter("example.prime.number", "type", "not-prime") // <1>
+ .increment(); // <2>
+ // end::counter[]
return number + " is not prime.";
}
}
+ // end::counted[]
+ // tag::timer[]
+
+ protected boolean timedTestPrimeNumber(long number) {
+ Timer.Sample sample = Timer.start(registry); // <4>
+ boolean result = testPrimeNumber(number); // <5>
+ sample.stop(registry.timer("example.prime.number.test", "prime", result + "")); // <6>
+ return result;
+ }
+ // end::timer[]
+ // end::timed[]
protected boolean testPrimeNumber(long number) {
- Timer timer = registry.timer("example.prime.number.test");
- return timer.record(() -> {
- for (int i = 3; i < Math.floor(Math.sqrt(number)) + 1; i = i + 2) {
- if (number % i == 0) {
- return false;
- }
+ for (int i = 3; i < Math.floor(Math.sqrt(number)) + 1; i = i + 2) {
+ if (number % i == 0) {
+ return false;
}
- return true;
- });
+ }
+ return true;
}
}
+// end::example[]
diff --git a/integration-tests/micrometer-prometheus/src/test/java/io/quarkus/it/micrometer/prometheus/ExampleResourcesTest.java b/integration-tests/micrometer-prometheus/src/test/java/io/quarkus/it/micrometer/prometheus/ExampleResourcesTest.java
index 0cd5c7e874adb..814147eae4f1e 100644
--- a/integration-tests/micrometer-prometheus/src/test/java/io/quarkus/it/micrometer/prometheus/ExampleResourcesTest.java
+++ b/integration-tests/micrometer-prometheus/src/test/java/io/quarkus/it/micrometer/prometheus/ExampleResourcesTest.java
@@ -54,14 +54,14 @@ void testTimerExample() {
when().get("/example/prime/257").then().statusCode(200);
when().get("/q/metrics").then().statusCode(200)
.body(containsString(
- "example_prime_number_test_seconds_sum{env=\"test\",registry=\"prometheus\",}"))
+ "example_prime_number_test_seconds_sum{env=\"test\",prime=\"true\",registry=\"prometheus\",}"))
.body(containsString(
- "example_prime_number_test_seconds_max{env=\"test\",registry=\"prometheus\",}"))
+ "example_prime_number_test_seconds_max{env=\"test\",prime=\"true\",registry=\"prometheus\",}"))
.body(containsString(
- "example_prime_number_test_seconds_count{env=\"test\",registry=\"prometheus\",} 1.0"));
+ "example_prime_number_test_seconds_count{env=\"test\",prime=\"true\",registry=\"prometheus\",} 1.0"));
when().get("/example/prime/7919").then().statusCode(200);
when().get("/q/metrics").then().statusCode(200)
.body(containsString(
- "example_prime_number_test_seconds_count{env=\"test\",registry=\"prometheus\",} 2.0"));
+ "example_prime_number_test_seconds_count{env=\"test\",prime=\"true\",registry=\"prometheus\",} 2.0"));
}
}