diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc index f2aa01cba62..787e75928ea 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc @@ -647,6 +647,57 @@ You can also declare implementations by listing them in a `META-INF/spring.facto +[[features.logging.structured.customizing-stack-traces]] +=== Customizing Structured Logging Stack Traces + +Complete stack traces are included in the JSON output whenever a message is logged with an exception. +This amount of information may be costly to process by your log ingestion system, so you may want to tune the way that stack traces are printed. + +To do this, you can use one or more of the following properties: + +|=== +| Property | Description + +| configprop:logging.structured.json.stacktrace.root[] +| Use `last` to print the root item last (same as Java) or `first` to print the root item first. + +| configprop:logging.structured.json.stacktrace.max-length[] +| The maximum length that should be printed + +| configprop:logging.structured.json.stacktrace.max-throwable-depth[] +| The maximum number of frames to print per stack trace (including common and suppressed frames) + +| configprop:logging.structured.json.stacktrace.include-common-frames[] +| If common frames should be included or removed + +| configprop:logging.structured.json.stacktrace.include-hashes[] +| If a hash of the stack trace should be included +|=== + +For example, the following will use root first stack traces, limit their length, and include hashes. + +[configprops,yaml] +---- +logging: + structured: + json: + stacktrace: + root: first + max-length: 1024 + include-common-frames: true + include-hashes: true +---- + +[TIP] +==== +If you need complete control over stack trace printing you can set configprop:logging.structured.json.stacktrace.printer[] to the name of a javadoc:org.springframework.boot.logging.StackTracePrinter[] implementation. +You can also set it to `logging-system` to force regular logging system stack trace output to be used. + +Your `StackTracePrinter` implementation can also include a constructor argument that accepts a javadoc:org.springframework.boot.logging.StandardStackTracePrinter[] if it wishes to apply further customization to the stack trace printer created from the properties. +==== + + + [[features.logging.structured.other-formats]] === Supporting Other Structured Logging Formats diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/StackTracePrinter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/StackTracePrinter.java new file mode 100644 index 00000000000..5ca12a33ab2 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/StackTracePrinter.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * 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 + * + * https://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. + */ + +package org.springframework.boot.logging; + +import java.io.IOException; +import java.io.UncheckedIOException; + +/** + * Interface that can be used to print the stack trace of a {@link Throwable}. + * + * @author Phillip Webb + * @since 3.5.0 + * @see StandardStackTracePrinter + */ +@FunctionalInterface +public interface StackTracePrinter { + + /** + * Return a {@link String} containing the printed stack trace for a given + * {@link Throwable}. + * @param throwable the throwable that should have its stack trace printed + * @return the stack trace string + */ + default String printStackTraceToString(Throwable throwable) { + try { + StringBuilder out = new StringBuilder(4096); + printStackTrace(throwable, out); + return out.toString(); + } + catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + /** + * Prints a stack trace for the given {@link Throwable}. + * @param throwable the throwable that should have its stack trace printed + * @param out the destination to write output + * @throws IOException on IO error + */ + void printStackTrace(Throwable throwable, Appendable out) throws IOException; + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/StandardStackTracePrinter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/StandardStackTracePrinter.java new file mode 100644 index 00000000000..d35a6797a29 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/StandardStackTracePrinter.java @@ -0,0 +1,474 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * 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 + * + * https://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. + */ + +package org.springframework.boot.logging; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.ToIntFunction; + +import org.springframework.util.Assert; + +/** + * {@link StackTracePrinter} that prints a standard form stack trace. This printer + * produces a result in a similar form to {@link Throwable#printStackTrace()}, but offers + * more customization options. + * + * @author Phillip Webb + * @since 3.5.0 + */ +public final class StandardStackTracePrinter implements StackTracePrinter { + + private static final String DEFAULT_LINE_SEPARATOR = System.lineSeparator(); + + private static final ToIntFunction DEFAULT_FRAME_HASHER = (frame) -> Objects + .hash(frame.getClassName(), frame.getMethodName(), frame.getLineNumber()); + + private static final int UNLIMTED = Integer.MAX_VALUE; + + private final EnumSet