forked from quarkusio/quarkus
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Configs, logging attributes, tests and docs
- Loading branch information
Showing
11 changed files
with
627 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
//// | ||
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 | ||
//// | ||
= Using OpenTelemetry Logging | ||
include::_attributes.adoc[] | ||
:categories: observability | ||
:summary: This guide explains how your Quarkus application can utilize OpenTelemetry Logging to provide distributed logging for interactive web applications. | ||
:topics: observability,opentelemetry,logging | ||
:extensions: io.quarkus:quarkus-opentelemetry | ||
|
||
This guide explains how your Quarkus application can utilize https://opentelemetry.io/[OpenTelemetry] (OTel) to provide | ||
distributed logging for interactive web applications. | ||
|
||
[NOTE] | ||
==== | ||
- OpenTelemetry Logging is disabled by default. | ||
- The xref:opentelemetry.adoc[OpenTelemetry Guide] is available with signal independent information about the OpenTelemetry extension. | ||
==== | ||
|
||
== Prerequisites | ||
|
||
:prerequisites-docker-compose: | ||
include::{includes}/prerequisites.adoc[] | ||
|
||
== Architecture | ||
|
||
In this guide, we create a straightforward REST application to demonstrate distributed logging, similar to the other OpenTelemetry guides. | ||
|
||
== Solution | ||
|
||
We recommend that you follow the instructions in the next sections and create the application step by step. | ||
However, you can skip right to the completed example. | ||
|
||
Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive]. | ||
|
||
The solution is located in the `opentelemetry-quickstart` link:{quickstarts-tree-url}/opentelemetry-quickstart[directory]. | ||
|
||
== Creating the Maven project | ||
|
||
First, we need a new project. Create a new project with the following command: | ||
|
||
:create-app-artifact-id: opentelemetry-quickstart | ||
:create-app-extensions: rest,quarkus-opentelemetry | ||
include::{includes}/devtools/create-app.adoc[] | ||
|
||
This command generates the Maven project and imports the `quarkus-opentelemetry` extension, | ||
which includes the default OpenTelemetry support, | ||
and a gRPC span exporter for https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md[OTLP]. | ||
|
||
If you already have your Quarkus project configured, you can add the `quarkus-opentelemetry` extension | ||
to your project by running the following command in your project base directory: | ||
|
||
:add-extension-extensions: opentelemetry | ||
include::{includes}/devtools/extension-add.adoc[] | ||
|
||
This will add the following to your build file: | ||
|
||
[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] | ||
.pom.xml | ||
---- | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-opentelemetry</artifactId> | ||
</dependency> | ||
---- | ||
|
||
[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] | ||
.build.gradle | ||
---- | ||
implementation("io.quarkus:quarkus-opentelemetry") | ||
---- | ||
|
||
=== Examine the Jakarta REST resource | ||
|
||
Create a `src/main/java/org/acme/opentelemetry/TracedResource.java` file with the following content: | ||
|
||
[source,java] | ||
---- | ||
package org.acme.opentelemetry; | ||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.core.MediaType; | ||
import org.jboss.logging.Logger; | ||
@Path("/hello") | ||
public class TracedResource { | ||
private static final Logger LOG = Logger.getLogger(TracedResource.class); | ||
@GET | ||
@Produces(MediaType.TEXT_PLAIN) | ||
public String hello() { | ||
LOG.info("hello"); | ||
return "hello"; | ||
} | ||
} | ||
---- | ||
|
||
If you have followed the tracing guide, this class will seem familiar. The main difference is that now, the `hello` message logged with `org.jboss.logging.Logger` will end up in the OpenTelemetry logs. | ||
|
||
=== Create the configuration | ||
|
||
=== Create the configuration | ||
|
||
The only mandatory configuration for OpenTelemetry Logging is the one enabling it: | ||
[source,properties] | ||
---- | ||
quarkus.otel.logs.enabled=true | ||
---- | ||
|
||
To change any of the default property values, here is an example on how to configure the default OTLP gRPC Exporter within the application, using the `src/main/resources/application.properties` file: | ||
|
||
[source,properties] | ||
---- | ||
quarkus.application.name=myservice // <1> | ||
quarkus.otel.logs.enabled=true // <2> | ||
quarkus.otel.exporter.otlp.logs.endpoint=http://localhost:4317 // <3> | ||
quarkus.otel.exporter.otlp.logs.headers=authorization=Bearer my_secret // <4> | ||
---- | ||
|
||
<1> All logs created from the application will include an OpenTelemetry `Resource` indicating the logs were created by the `myservice` application. | ||
If not set, it will default to the artifact id. | ||
<2> Enable the OpenTelemetry logging. | ||
Must be set at build time. | ||
<3> gRPC endpoint to send the logs. | ||
If not set, it will default to `http://localhost:4317`. | ||
<4> Optional gRPC headers commonly used for authentication. | ||
|
||
To configure the connection using the same properties for all signals, please check the base xref:opentelemetry.adoc#create-the-configuration[configuration section of the OpenTelemetry guide]. | ||
|
||
== Run the application | ||
|
||
First we need to start a system to visualise the OpenTelemetry data. | ||
We have 2 options: | ||
|
||
* Start an all-in-one Grafana OTel LGTM system for traces, metrics and logs. | ||
|
||
=== See the data | ||
|
||
==== Grafana OTel LGTM option | ||
|
||
* Take a look at: xref:observability-devservices-lgtm.adoc[Getting Started with Grafana-OTel-LGTM]. | ||
|
||
This features a Quarkus Dev service including a Grafana for visualizing data, Loki to store logs, Tempo to store traces and Prometheus to store metrics. Also provides and OTel collector to receive the data. | ||
|
||
==== Logging exporter | ||
|
||
You can output all metrics to the console by setting the exporter to `logging` in the `application.properties` file: | ||
[source, properties] | ||
---- | ||
quarkus.otel.metrics.exporter=logging <1> | ||
---- | ||
|
||
<1> Set the exporter to `logging`. | ||
Normally you don't need to set this. | ||
The default is `cdi`. | ||
|
||
|
||
Also add this dependency to your project: | ||
[source,xml] | ||
---- | ||
<dependency> | ||
<groupId>io.opentelemetry</groupId> | ||
<artifactId>opentelemetry-exporter-logging</artifactId> | ||
</dependency> | ||
---- | ||
|
||
[[configuration-reference]] | ||
== OpenTelemetry Configuration Reference | ||
|
||
See the main xref:opentelemetry.adoc#configuration-reference[OpenTelemetry Guide configuration] reference. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
...eployment/src/test/java/io/quarkus/opentelemetry/deployment/logs/OtelLoggingFileTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package io.quarkus.opentelemetry.deployment.logs; | ||
|
||
import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_TYPE; | ||
import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION; | ||
import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_LINENO; | ||
import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE; | ||
import static io.opentelemetry.semconv.incubating.LogIncubatingAttributes.LOG_FILE_PATH; | ||
import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_ID; | ||
import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_NAME; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.inject.Inject; | ||
|
||
import org.jboss.logging.Logger; | ||
import org.jboss.shrinkwrap.api.ShrinkWrap; | ||
import org.jboss.shrinkwrap.api.asset.StringAsset; | ||
import org.jboss.shrinkwrap.api.spec.JavaArchive; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.RegisterExtension; | ||
|
||
import io.opentelemetry.api.common.AttributeKey; | ||
import io.opentelemetry.api.logs.Severity; | ||
import io.opentelemetry.sdk.logs.data.LogRecordData; | ||
import io.quarkus.opentelemetry.deployment.common.exporter.InMemoryLogRecordExporter; | ||
import io.quarkus.opentelemetry.deployment.common.exporter.InMemoryLogRecordExporterProvider; | ||
import io.quarkus.test.QuarkusUnitTest; | ||
|
||
public class OtelLoggingFileTest { | ||
|
||
@RegisterExtension | ||
static final QuarkusUnitTest TEST = new QuarkusUnitTest() | ||
.setArchiveProducer( | ||
() -> ShrinkWrap.create(JavaArchive.class) | ||
.addClasses(JBossLoggingBean.class) | ||
.addClasses(InMemoryLogRecordExporter.class, InMemoryLogRecordExporterProvider.class) | ||
.addAsResource(new StringAsset(InMemoryLogRecordExporterProvider.class.getCanonicalName()), | ||
"META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider") | ||
.add(new StringAsset( | ||
"quarkus.otel.logs.enabled=true\n" + | ||
"quarkus.log.file.enable=true\n" + // enable log file | ||
"quarkus.otel.traces.enabled=false\n"), | ||
"application.properties")); | ||
|
||
@Inject | ||
InMemoryLogRecordExporter logRecordExporter; | ||
|
||
@Inject | ||
JBossLoggingBean jBossLoggingBean; | ||
|
||
@BeforeEach | ||
void setup() { | ||
logRecordExporter.reset(); | ||
} | ||
|
||
@Test | ||
public void testLoggingData() { | ||
final String message = "Logging message to test the different logging attributes"; | ||
assertEquals("hello", jBossLoggingBean.hello(message)); | ||
|
||
List<LogRecordData> finishedLogRecordItems = logRecordExporter.getFinishedLogRecordItemsAtLeast(1); | ||
LogRecordData last = finishedLogRecordItems.get(finishedLogRecordItems.size() - 1); | ||
|
||
assertThat(last.getTimestampEpochNanos()).isNotNull().isLessThan(System.currentTimeMillis() * 1_000_000); | ||
assertThat(last.getSeverityText()).isEqualTo("INFO"); | ||
assertThat(last.getSeverity()).isEqualTo(Severity.INFO); | ||
assertThat(last.getBody().asString()).isEqualTo(message); | ||
|
||
Map<AttributeKey<?>, Object> attributesMap = last.getAttributes().asMap(); | ||
assertThat(attributesMap.get(CODE_NAMESPACE)) | ||
.isEqualTo("io.quarkus.opentelemetry.deployment.logs.OtelLoggingFileTest$JBossLoggingBean"); | ||
assertThat(attributesMap.get(CODE_FUNCTION)).isEqualTo("hello"); | ||
assertThat((Long) attributesMap.get(CODE_LINENO)).isGreaterThan(0); | ||
assertThat(attributesMap.get(THREAD_NAME)).isEqualTo(Thread.currentThread().getName()); | ||
assertThat(attributesMap.get(THREAD_ID)).isEqualTo(Thread.currentThread().getId()); | ||
assertThat(attributesMap.get(AttributeKey.stringKey("log.logger.namespace"))).isEqualTo("org.jboss.logging.Logger"); | ||
assertThat(attributesMap.get(EXCEPTION_TYPE)).isNull(); | ||
// using the default location for the log file | ||
assertThat(attributesMap.get(LOG_FILE_PATH)).isEqualTo("target/quarkus.log"); | ||
Check failure on line 84 in extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/logs/OtelLoggingFileTest.java GitHub Actions / Build summary for a3230436e31dca7ccada21f1ed20d67816c0489fJVM Tests - JDK 17 Windows
Raw output
|
||
} | ||
|
||
@ApplicationScoped | ||
public static class JBossLoggingBean { | ||
private static final Logger LOG = Logger.getLogger(JBossLoggingBean.class.getName()); | ||
|
||
public String hello(final String message) { | ||
LOG.info(message); | ||
return "hello"; | ||
} | ||
|
||
public boolean logException(final Throwable throwable) { | ||
LOG.error("logging an exception", throwable); | ||
return true; | ||
} | ||
} | ||
} |
Oops, something went wrong.