diff --git a/docs/src/main/asciidoc/se/guides/logging.adoc b/docs/src/main/asciidoc/se/guides/logging.adoc new file mode 100644 index 00000000000..84f6cea623a --- /dev/null +++ b/docs/src/main/asciidoc/se/guides/logging.adoc @@ -0,0 +1,239 @@ +/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2025 Oracle and/or its affiliates. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +/////////////////////////////////////////////////////////////////////////////// + += Helidon SE Logging Guide +:description: Helidon logging guide +:keywords: helidon, logging, MDC, jul, log4j, logback, slf4j +:rootdir: {docdir}/../.. + +include::{rootdir}/includes/se.adoc[] + +This guide describes various aspects of logging support in Helidon. + +== Contents + +* <> +* <> +* <> +* <> +* <> + +== Helidon Logging + +Helidon modules use the Java Platform Logging API (`System.Logger`) for logging. Therefore, +Helidon applications will use Java Util Logging (JUL) as the default log framework. + +If you wish to use another logging framework such as log4j or slf4j, +then you can do so. See section <> + +== Customizing Logging with Java Util Logging + +Since by default Helidon uses the Java Util Logging framework, you will see a +`logging.properties` file in most Helidon examples. It will be similar to this: + +[source] +---- +handlers=io.helidon.logging.jul.HelidonConsoleHandler + +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$s %3$s !thread!: %5$s%6$s%n + +# Global logging level. Can be overridden by specific loggers +.level=FINE +---- + +`HelidonConsoleHandler` is similar to the JUL `ConsoleHandler` with these additional capabilities: + +1. Defaults the Handler log level to ALL so level filtering is performed only by the Logger +2. Uses `HelidonFormatter` which is compatible with JUL `SimpleFormatter` and adds support for MDC tags and the `!thread!` keyword + +Helidon's internal loggers are usually defined per-class. So to enable finer grained logging in a specific Helidon package, you can add entries like the following to `logging.properties`: + +[source] +---- +io.helidon.webserver.level=INFO +---- + +== log4j and slf4j support + +If you wish to use another log framework, such has log4j or slf4j, and you wish to consolidate Helidon logging +with that framework, then you have a couple options: + +1. Use the log framework's support for Java Platform Logging (such as `log4j-jp` or `slf4j-jdk-platform-logging`) +2. Use the log framework's bridge for Java Util Logging (such as `log4j-jul` or `jul-to-slf4j`) + +This section focuses on the second option as it aligns with what most Helidon examples use and leverages some of Helidon's JUL specific features. + +=== log4j + +To use `log4j` with your Helidon application add the following dependencies: + +[source] +---- + + io.helidon.logging + helidon-logging-log4j + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-jul + +---- + +This achieves four things: + +1. Makes the log4j API available to your application. +2. Bridges all of Helidon's Java Util Logging to log4j. +3. Enables the use of MDC with log4j (see <>). +4. Ensures GraalVM native-image support for log4j. + +For more information see link:{helidon-github-examples-url}/logging/log4j[Helidon log4j example] + +=== slf4j + +To use `slf4j` with your Helidon application add the following dependencies: + +[source] +---- + + io.helidon.logging + helidon-logging-slf4j + + + org.slf4j + slf4j-api + + + org.slf4j + jul-to-slf4j + + + ch.qos.logback + logback-classic + ${version.lib.logback} + +---- + +The above snippet uses logback as the slf4j logging provider. + +This achieves four things: + +1. Makes the slf4j API available to your application. +2. Bridges all of Helidon's Java Util Logging to slf4j +3. Enables the use of MDC with slf4j +4. Ensures GraalVM native-image support for slf4j + +For more information see link:{helidon-github-examples-url}/logging/slf4j[Helidon slf4j example] + +== Mapped Diagnostic Context (MDC) support + +The Mapped Diagnostic Context provides a mechanism for Helidon and application code to store +values in a context that can then be included in log output. These values could +be a tracing ID, the current user, or a similar contextual value, and they are +propagated by Helidon across threads. + +Some logging frameworks, such as slf4j and log4j, have support for MDC. But +Java Util Logging does not. Therefore, Helidon provides an API, `HelidonMdc`, +that you can use to store contextual values. `HelidonMdc` not only works with JUL +but also works with the other supported frameworks (slf4j or log4j). + +To use Helidon MDC, you need to do three things: + +1. Add a dependency on one of the supported logging frameworks. See previous sections. +2. Store values in the MDC in your code. +3. Configure logging to display the values in its output. + +=== MDC values provided by Helidon +If you include tracing in your project, Helidon automatically provides the MDC key `trace_id`. Logging inserts the trace ID of the current span (if there is one) or the string "none" if no span is active. + +=== Storing values in MDC + +To set your own values in the MDC you can use the `io.helidon.logging.common.HelidonMdc` class: + +[source,java] +---- +HelidonMdc.set("name", "Joe"); // <1> +HelidonMdc.set("otherName", () -> retrieveStringValue()); // <2> +---- +<1> Stores an attribute named "name" with the fixed value "Joe" in the MDC. +<2> Stores an attribute named "otherName" with the given `Supplier`. + +The `set()` method associates the name with a fixed value. The `set(, >)` form associates the name with a lambda or method reference. This second form might be useful if your code (or Helidon) maintains the value you want to log in some context that your code can access and if that value changes as the server runs. In both cases, when your logging format refers to the name logging extracts the corresponding fixed value or invokes the supplier to obtain the value, using the result in log output. + +`HelidonMdc` works with the supported logging frameworks. But if you prefer, you can +use a logging framework specific API. Such as `org.slf4j.MDC` or `org.apache.logging.log4j.ThreadContext` instead. + +=== MDC output with Java Util Logging + +You must use `HelidonConsoleHandler` or `HelidonFormatter` in order to reference MDC values in the +log format string. To reference MDC values in your format string using the token `%X{name}` where +`name` is the property used in MDC. For example: + +[source] +---- +handlers=io.helidon.logging.jul.HelidonConsoleHandler +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s "%X{name}"%n +.level=INFO +---- + +=== MDC output with slf4j and logback + +Logback expects `lockback.xml` on the classpath as one of the configuration +options. You can reference MDC values using the token `%X{name}` where `name` +is the property used in MDC. For example: + +[source] +---- + + + + + %d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg %X{name}%n + + + + + + + + +---- + +=== MDC output with log4j + +There are a variety of ways to configure log4j, but once again the important part +for MDC is you can use the token `%X{name}` to reference MDC values in the log output. + +[source] +---- + +---- + +== Additional Information + +* link:{helidon-github-examples-url}/logging[Helidon logging examples] +* link:{https://medium.com/helidon/helidon-logging-and-mdc-5de272cf085d}[Helidon, Logging, and MDC Blog] +* link:{javadoc-base-url}/io.helidon.logging.common/io/helidon/logging/common/HelidonMdc.html[HelidonMdc Javadoc] \ No newline at end of file diff --git a/docs/src/main/asciidoc/sitegen.yaml b/docs/src/main/asciidoc/sitegen.yaml index 06fcd614f2a..7ad7c1304ce 100644 --- a/docs/src/main/asciidoc/sitegen.yaml +++ b/docs/src/main/asciidoc/sitegen.yaml @@ -339,6 +339,7 @@ backend: - "config.adoc" - "langchain4j.adoc" - "health.adoc" + - "logging.adoc" - "metrics.adoc" - "security-oidc.adoc" - "tracing.adoc"