Skip to content

Commit

Permalink
Docs: copy example src from integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ebullient committed Aug 4, 2022
1 parent 08bdd4a commit d29f687
Show file tree
Hide file tree
Showing 10 changed files with 480 additions and 101 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/doc-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
22 changes: 21 additions & 1 deletion docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<quarkus-home-url>https://quarkus.io</quarkus-home-url>
<quarkus-base-url>https://github.com/quarkusio/quarkus</quarkus-base-url>
<quickstarts-base-url>https://github.com/quarkusio/quarkus-quickstarts</quickstarts-base-url>
<code-example-dir>${project.basedir}/../target/asciidoc/examples</code-example-dir>
</properties>

<name>Quarkus - Documentation</name>
Expand Down Expand Up @@ -2794,6 +2795,24 @@
</environmentVariables>
</configuration>
</execution>
<execution>
<id>copy-tagged-java-source</id>
<phase>process-classes</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<skip>${skipDocs}</skip>
<mainClass>io.quarkus.docs.generation.CopyJavaExamples</mainClass>
<arguments>
<argument>${code-example-dir}</argument>
<argument>${project.basedir}/../integration-tests</argument>
</arguments>
<environmentVariables>
<MAVEN_CMD_LINE_ARGS>${env.MAVEN_CMD_LINE_ARGS}</MAVEN_CMD_LINE_ARGS>
</environmentVariables>
</configuration>
</execution>
<execution>
<id>generate-doc-manifests</id>
<phase>prepare-package</phase>
Expand Down Expand Up @@ -2830,6 +2849,7 @@
<preserveDirectories>true</preserveDirectories>
<attributes>
<generated-dir>${project.basedir}/../target/asciidoc/generated</generated-dir>
<code-examples>${code-example-dir}</code-examples>
<imagesdir>./images</imagesdir>
<icons>font</icons>
<sectanchors>true</sectanchors>
Expand Down Expand Up @@ -2912,7 +2932,7 @@
<neo4j-guide>https://quarkiverse.github.io/quarkiverse-docs/quarkus-neo4j/dev/index.html</neo4j-guide>
<vault-guide>https://quarkiverse.github.io/quarkiverse-docs/quarkus-vault/dev/index.html</vault-guide>
<vault-datasource-guide>https://quarkiverse.github.io/quarkiverse-docs/quarkus-vault/dev/vault-datasource.html</vault-datasource-guide>
<micrometer-registry-gulde>https://quarkiverse.github.io/quarkiverse-docs/quarkus-micrometer-registry/dev/</micrometer-registry-gulde>
<micrometer-registry-guide>https://quarkiverse.github.io/quarkiverse-docs/quarkus-micrometer-registry/dev/</micrometer-registry-guide>
</attributes>
</configuration>
<executions>
Expand Down
3 changes: 2 additions & 1 deletion docs/src/main/asciidoc/_examples/attributes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
:idprefix:
:idseparator: -
:icons: font
:code-examples: ../../../../../target/asciidoc/examples
:doc-guides: ..
:doc-examples: .
:imagesdir: ./images
:includes: ../includes
:root: ../../asciidoc

4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/_templates/attributes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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/
4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/attributes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
67 changes: 54 additions & 13 deletions docs/src/main/asciidoc/doc-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -144,10 +144,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="<m,<2",options="header"]
|===
|Attribute|Description
|\{code-examples}|Relative path to directory containing collected example source files
|\{doc-guides}|Relative path to documentation adoc files (e.g. doc-concepts.adoc)
|\{doc-examples}|Relative path to source examples for documentation guides
|\{generated-dir}|Relative path to generated configuration `*.adoc` files
|\{imagesdir}|Relative path to directory containing images
|\{includes}|Relative path to directory containing partial/reusable content (`*.adoc` files)
|===

When cross-referencing content, always use the inter-document `xref:` syntax and supply a human-readable label to your link.

Expand All @@ -156,13 +162,47 @@ When cross-referencing content, always use the inter-document `xref:` syntax and
----
xref:{doc-guides}/doc-concepts.adoc[Quarkus Documentation concepts] <1>
----
<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]`.

=== Referencing source code

There are many ways to include source examples in documentation.

The simplest way is to write it directly in the file, like this:

[source,asciidoc]
-----
[source,java]
----
System.out.println("Hello, World!");
----
-----

For tutorials, you may want to reference code that you know is being built and tested regularly.
As of 2.11, the Quarkus documentation module build will look for source files in `integration-tests` modules that are in the `documentaton.examples` package.
It will copy those files into a flattened structure in the `target/asciidoc/examples` directory (from the project root).
Copied content can then be referenced using the `\{code-examples}` source attribute

.Micrometer example
- Integration test source:
+
`integration-tests/micrometer-prometheus/src/main/java/documentation/example/telemetry/micrometer/tutorial/ExampleResource.java`

- Copy for inclusion in docs (flattened file structure):
+
`target/asciidoc/examples/telemetry-micrometer-tutorial-ExampleResource.java`.

- Content is referenced using the following:
+
`\{code-examples}/telemetry-micrometer-tutorial-ExampleResource.java`.


=== Variables for use in documents

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:
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="<m,<m,<2",options="header"]
Expand Down Expand Up @@ -193,4 +233,5 @@ complete list of externalized variables for use is given in the following table:

|\{graalvm-version}|{graalvm-version}| Recommended GraalVM version to use.
|\{graalvm-flavor}|{graalvm-flavor}| The full flavor of GraalVM to use e.g. `19.3.1-java11`. Make sure to use a `java11` version.
|===
|===

200 changes: 200 additions & 0 deletions docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
////
This guide is maintained in the main Quarkus repository
and pull requests should be submitted there:
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
////
[id="tutorial-micrometer"]
= Collect metrics using Micrometer
include::./attributes.adoc[]

Create an application that uses the Micrometer metrics library to collect runtime, extension and application metrics and expose them as a Prometheus (OpenMetrics) endpoint.

== Prerequisites

include::{includes}/prerequisites.adoc[]

== Solution

We recommend that you follow the instructions to create the application step by step, but you can skip right to the solution if you prefer. Either:

* Clone the git repository: `git clone {quickstarts-clone-url}`, or
* Download an {quickstarts-archive-url}[archive].

The solution is located in the `micrometer-quickstart` {quickstarts-tree-url}/micrometer-quickstart[directory].

:sectnums:
:sectnumlevels: 3
== Creating the Maven Project

Create a new project with the following command:

:create-app-artifact-id: micrometer-quickstart
:create-app-extensions: resteasy-reactive,micrometer-registry-prometheus
include::{includes}/devtools/create-app.adoc[]

This command generates a Maven project, that imports the `micrometer-registry-prometheus` extension as a dependency.
This extension will load the core `micrometer` extension as well as additional library dependencies required to support prometheus.

== Writing the application

Let's first add a simple endpoint that calculates prime numbers.

[source,java]
----
include::{code-examples}/telemetry-micrometer-tutorial-ExampleResource.java[tags=example;!ignore;!registry;!gauge;!counter;!timer]
----

Start your application in dev mode:

include::{includes}/devtools/dev.adoc[]

=== Review automatically generated metrics

The Micrometer extension automatically times HTTP server requests.

Let's use `curl` (or a browser) to visit our endpoint a few times:

[source,shell]
----
curl http://localhost:8080/example/prime/256
curl http://localhost:8080/example/prime/7919
----

The Micrometer Prometheus MeterRegistry extension creates an endpoint we can use to observe collected metrics. Let's take a look at the metrics that have been collected:

[source,shell]
----
curl http://localhost:8080/q/metrics
----

Look for `http_server_requests_seconds_count`, `http_server_requests_seconds_sum`, and
`http_server_requests_seconds_max` in the output.

Dimensional labels are added for the request uri, the HTTP method
(GET, POST, etc.), the status code (200, 302, 404, etc.), and a more general outcome field. You should find something like this:

[source,text]
----
# HELP http_server_requests_seconds
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 2.0
http_server_requests_seconds_sum{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 0.017385896
# HELP http_server_requests_seconds_max
# TYPE http_server_requests_seconds_max gauge
http_server_requests_seconds_max{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 0.017385896
#
----

NOTE: Metrics appear lazily, you often won't see any data for your endpoint until it is accessed.

== Inject the MeterRegistry

To register meters, you need a reference to the `MeterRegistry` that is configured and maintained by the Micrometer extension.

The `MeterRegistry` can be injected into your application as follows:

[source,java]
----
include::{code-examples}/telemetry-micrometer-tutorial-ExampleResource.java[tags=registry;!gauge]
----

== Add a Counter

Counters are used to measure values that only increase.

Let's add a counter that tracks how often we test a number to see if it is prime.
We'll add a dimensional label (also called an attribute or a tag) that will allow us to aggregate this counter value in different ways.

[source,java]
----
include::{code-examples}/telemetry-micrometer-tutorial-ExampleResource.java[tags=counted;!ignore;!timer]
----

<1> 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-ExampleResource.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.



Loading

0 comments on commit d29f687

Please sign in to comment.