Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Logging OpenTelemetry extension #38239

Merged
merged 12 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/_includes/opentelemetry-config.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
There are no mandatory configurations for the extension to work.

By default, the exporters will send out data in batches, using the gRPC protocol and endpoint `http://localhost:4317`.

If you need 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:
Expand Down Expand Up @@ -31,6 +29,8 @@ If you need different configurations for each signal, you can use the specific p
----
quarkus.otel.exporter.otlp.traces.endpoint=http://trace-uri:4317 // <1>
quarkus.otel.exporter.otlp.metrics.endpoint=http://metrics-uri:4317 // <2>
quarkus.otel.exporter.otlp.logs.endpoint=http://logs-uri:4317 // <3>
----
<1> The endpoint for the traces exporter.
<2> The endpoint for the metrics exporter.
<3> The endpoint for the logs exporter.
5 changes: 5 additions & 0 deletions docs/src/main/asciidoc/logging.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,11 @@ Use a centralized location to efficiently collect, store, and analyze log data f
To send logs to a centralized tool such as Graylog, Logstash, or Fluentd, see the Quarkus xref:centralized-log-management.adoc[Centralized log management] guide.


=== OpenTelemetry logging
Logging entries from all appenders can be sent using OpenTelemetry Logging.

For details, see the Quarkus xref:opentelemetry-logging.adoc[OpenTelemetry Logging] guide.

== Configure logging for `@QuarkusTest`

Enable proper logging for `@QuarkusTest` by setting the `java.util.logging.manager` system property to `org.jboss.logmanager.LogManager`.
Expand Down
173 changes: 173 additions & 0 deletions docs/src/main/asciidoc/opentelemetry-logging.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
////
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

Check warning on line 6 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Headings] Use sentence-style capitalization in 'Using OpenTelemetry Logging'. Raw Output: {"message": "[Quarkus.Headings] Use sentence-style capitalization in 'Using OpenTelemetry Logging'.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 6, "column": 3}}}, "severity": "INFO"}
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.

Check warning on line 9 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'use' rather than 'utilize' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'use' rather than 'utilize' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 9, "column": 64}}}, "severity": "WARNING"}
: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.

Check warning on line 33 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'using more direct instructions' rather than 'recommend'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'using more direct instructions' rather than 'recommend'.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 33, "column": 4}}}, "severity": "INFO"}
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

Check warning on line 70 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.CaseSensitiveTerms] Use 'Gradle' rather than 'gradle'. Raw Output: {"message": "[Quarkus.CaseSensitiveTerms] Use 'Gradle' rather than 'gradle'.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 70, "column": 8}}}, "severity": "INFO"}
----
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

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].

Check warning on line 131 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsSuggestions] Depending on the context, consider using 'by using' or 'that uses' rather than 'using'. Raw Output: {"message": "[Quarkus.TermsSuggestions] Depending on the context, consider using 'by using' or 'that uses' rather than 'using'.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 131, "column": 28}}}, "severity": "INFO"}

== Run the application

Check warning on line 133 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 133, "column": 23}}}, "severity": "INFO"}

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

Check warning on line 142 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Headings] Use sentence-style capitalization in 'Grafana OTel LGTM option'. Raw Output: {"message": "[Quarkus.Headings] Use sentence-style capitalization in 'Grafana OTel LGTM option'.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 142, "column": 6}}}, "severity": "INFO"}

* Take a look at: xref:observability-devservices-lgtm.adoc[Getting Started with Grafana-OTel-LGTM].

Check warning on line 144 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'examine' rather than 'look at' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'examine' rather than 'look at' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 144, "column": 10}}}, "severity": "WARNING"}

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 logs to the console by setting the exporter to `logging` in the `application.properties` file:
[source, properties]
----
quarkus.otel.logs.exporter=logging <1>
----

<1> Set the exporter to `logging`.
Normally you don't need to set this.

Check warning on line 157 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 157, "column": 9}}}, "severity": "INFO"}
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

Check warning on line 171 in docs/src/main/asciidoc/opentelemetry-logging.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Headings] Use sentence-style capitalization in 'OpenTelemetry Configuration Reference'. Raw Output: {"message": "[Quarkus.Headings] Use sentence-style capitalization in 'OpenTelemetry Configuration Reference'.", "location": {"path": "docs/src/main/asciidoc/opentelemetry-logging.adoc", "range": {"start": {"line": 171, "column": 4}}}, "severity": "INFO"}

See the main xref:opentelemetry.adoc#configuration-reference[OpenTelemetry Guide configuration] reference.
18 changes: 16 additions & 2 deletions docs/src/main/asciidoc/opentelemetry-metrics.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ metrics for interactive web applications.

[NOTE]
====
- OpenTelemetry Metrics is disabled by default and Quarkus does not produce automatic metrics for it.
- The xref:opentelemetry.adoc[OpenTelemetry Guide] is available with signal independent information about the OpenTelemetry extension.
- If you search more information about OpenTelemetry Tracing, please refer to the xref:opentelemetry-tracing.adoc[OpenTelemetry Tracing Guide].
====
Expand Down Expand Up @@ -123,9 +124,13 @@ Here we are creating a counter for the number of invocations of the `hello()` me

=== Create the configuration

There are no mandatory configurations for the extension to work.
The only mandatory configuration for OpenTelemetry Metrics is the one enabling it:
[source,properties]
----
quarkus.otel.metrics.enabled=true
----

If you need 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:
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]
----
Expand Down Expand Up @@ -174,6 +179,15 @@ The default is `cdi`.
<2> Set the interval to export the metrics.
The default is `1m`, which is too long for debugging.

Also add this dependency to your project:
[source,xml]
----
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-logging</artifactId>
</dependency>
----

=== Start the application

Now we are ready to run our application.
Expand Down
11 changes: 11 additions & 0 deletions docs/src/main/asciidoc/opentelemetry.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ For now only manual instrumentation is supported. You can use the OpenTelemetry

In the future, we plan to bridge current Micrometer metrics to OpenTelemetry and maintain compatibility when possible.

=== xref:opentelemetry-logging.adoc[OpenTelemetry Logging Guide]

==== Enable Logs
The logging functionality is experimental and *off* by default. You will need to activate it by setting:

[source,properties]
----
quarkus.otel.logs.enabled=true
----
At build time on your `application.properties` file.

== Using the extension

If you already have your Quarkus project, you can add the `quarkus-opentelemetry` extension
Expand Down
15 changes: 15 additions & 0 deletions extensions/opentelemetry/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,21 @@
<artifactId>quarkus-security-deployment</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-testing</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.slf4j</groupId>
<artifactId>slf4j-jboss-logmanager</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>log4j2-jboss-logmanager</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@
import org.jboss.jandex.Type;

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.exporter.otlp.internal.OtlpLogRecordExporterProvider;
import io.opentelemetry.exporter.otlp.internal.OtlpMetricExporterProvider;
import io.opentelemetry.exporter.otlp.internal.OtlpSpanExporterProvider;
import io.opentelemetry.instrumentation.annotations.AddingSpanAttributes;
import io.opentelemetry.instrumentation.annotations.WithSpan;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurablePropagatorProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
Expand Down Expand Up @@ -86,7 +87,6 @@ public boolean test(AnnotationInstance annotationInstance) {
return annotationInstance.name().equals(ADD_SPAN_ATTRIBUTES);
}
};
private static final DotName SPAN_KIND = DotName.createSimple(SpanKind.class.getName());
private static final DotName WITH_SPAN_INTERCEPTOR = DotName.createSimple(WithSpanInterceptor.class.getName());
private static final DotName ADD_SPAN_ATTRIBUTES_INTERCEPTOR = DotName
.createSimple(AddingSpanAttributesInterceptor.class.getName());
Expand Down Expand Up @@ -163,10 +163,31 @@ void handleServices(OTelBuildConfig config,
Set.of("META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider")));
}

final List<String> logRecordExporterProviders = ServiceUtil.classNamesNamedIn(
Thread.currentThread().getContextClassLoader(),
SPI_ROOT + ConfigurableLogRecordExporterProvider.class.getName())
.stream()
.filter(p -> !OtlpLogRecordExporterProvider.class.getName().equals(p))
.collect(toList()); // filter out OtlpLogRecordExporterProvider since it depends on OkHttp
if (!logRecordExporterProviders.isEmpty()) {
services.produce(
new ServiceProviderBuildItem(ConfigurableLogRecordExporterProvider.class.getName(),
logRecordExporterProviders));
}
if (config.logs().exporter().stream().noneMatch(ExporterType.Constants.OTLP_VALUE::equals)) {
removedResources.produce(new RemovedResourceBuildItem(
ArtifactKey.fromString("io.opentelemetry:opentelemetry-exporter-otlp"),
Set.of("META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider")));
}

runtimeReinitialized.produce(
new RuntimeReinitializedClassBuildItem("io.opentelemetry.sdk.autoconfigure.TracerProviderConfiguration"));
runtimeReinitialized.produce(
new RuntimeReinitializedClassBuildItem("io.opentelemetry.sdk.autoconfigure.MeterProviderConfiguration"));
runtimeReinitialized.produce(
new RuntimeReinitializedClassBuildItem("io.opentelemetry.sdk.autoconfigure.LoggerProviderConfiguration"));
runtimeReinitialized.produce(
new RuntimeReinitializedClassBuildItem("io.quarkus.opentelemetry.runtime.logs.OpenTelemetryLogHandler"));

services.produce(ServiceProviderBuildItem.allProvidersFromClassPath(
ConfigurableSamplerProvider.class.getName()));
Expand Down
Loading
Loading