diff --git a/.checkstyle/suppressions.xml b/.checkstyle/suppressions.xml index 04ed5fffe..ea0de2320 100644 --- a/.checkstyle/suppressions.xml +++ b/.checkstyle/suppressions.xml @@ -8,6 +8,9 @@ + + + diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index 90e7633c4..51c6a7f99 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { "nbt", "serializer-configurate3", "serializer-configurate4", + "text-logger-slf4j", "text-minimessage", "text-serializer-gson", "text-serializer-gson-legacy-impl", diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4032f3d23..1f67e61a7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,6 +10,8 @@ indra = "2.1.1" jmh = "1.35" jmhPlugin = "0.6.6" junit = "5.8.2" +mockito = "4.5.1" +slf4j = "1.7.36" truth = "1.1.3" [libraries] @@ -28,6 +30,10 @@ kotlin-testJunit5 = { module = "org.jetbrains.kotlin:kotlin-test-junit5" } configurate-v3 = "org.spongepowered:configurate-core:3.7.3" configurate-v4 = "org.spongepowered:configurate-core:4.1.2" +# text-logger-slf4j +slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } +slf4jtest = "com.github.valfirst:slf4j-test:2.6.1" # Specific versions are needed for different SLF4J versions + # text-serializer-gson gson = "com.google.code.gson:gson:2.8.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index 86282d8f6..24b270f19 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -34,6 +34,7 @@ sequenceOf( "nbt", "serializer-configurate3", "serializer-configurate4", + "text-logger-slf4j", "text-minimessage", "text-serializer-gson", "text-serializer-gson-legacy-impl", diff --git a/text-logger-slf4j/build.gradle.kts b/text-logger-slf4j/build.gradle.kts new file mode 100644 index 000000000..f5c0c54e1 --- /dev/null +++ b/text-logger-slf4j/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + id("adventure.common-conventions") +} + +dependencies { + api(projects.adventureApi) + api(libs.slf4j) + testImplementation(libs.slf4jtest) +} + +sourceSets.main { + multirelease { + alternateVersions(9) + } +} + +applyJarMetadata("net.kyori.adventure.text.logger.slf4j") + +eclipse { + // Make sure slf4j doesn't end up on the module path until we are actually a module + classpath.file.whenMerged { + (this as org.gradle.plugins.ide.eclipse.model.Classpath).entries.forEach { entry -> + if (entry is org.gradle.plugins.ide.eclipse.model.Library) { + entry.entryAttributes["module"] = false + } + } + } +} diff --git a/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/CallerClassFinder.java b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/CallerClassFinder.java new file mode 100644 index 000000000..886c89417 --- /dev/null +++ b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/CallerClassFinder.java @@ -0,0 +1,43 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +// Java 8 version, see Java 9 version as well +final class CallerClassFinder { + private CallerClassFinder() { + } + + static String callingClassName() { + return callingClassName(2); // this, plus the calling method + } + + static String callingClassName(final int elementsToSkip) { // elementsToSkip not counting this method + final StackTraceElement[] elements = Thread.currentThread().getStackTrace(); // includes call to getStackTrace() + if (elements.length <= elementsToSkip) { + throw new IllegalArgumentException("Not enough stack elements to skip " + elementsToSkip + " elements"); + } else { + return elements[elementsToSkip + 2].getClassName(); + } + } +} diff --git a/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/ComponentLogger.java b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/ComponentLogger.java new file mode 100644 index 000000000..63a027938 --- /dev/null +++ b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/ComponentLogger.java @@ -0,0 +1,673 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.Marker; + +import static java.util.Objects.requireNonNull; + +/** + * An extended type of Logger capable of logging formatted components to the console. + * + *

The methods in this logger interface are intended to exactly mirror those methods in {@link Logger} that take a format string, but instead accepting {@link Component}s.

+ * + *

Any {@code arg}s may be passed as Components as well.

+ * + * @since 4.11.0 + */ +public interface ComponentLogger extends Logger { + /** + * Get a logger instance with the name of the calling class. + * + *

This method is caller-sensitive and should not be wrapped.

+ * + *

This logger is produced by implementations of the {@link ComponentLoggerProvider}.

+ * + * @return a logger with the name of the calling class + * @since 4.11.0 + */ + static @NotNull ComponentLogger logger() { + return logger(CallerClassFinder.callingClassName()); + } + + /** + * Get a logger instance with the provided name. + * + *

This logger is produced by implementations of the {@link ComponentLoggerProvider}.

+ * + * @param name the name of the logger + * @return a logger with the provided name + * @since 4.11.0 + */ + static @NotNull ComponentLogger logger(final @NotNull String name) { + return Handler.logger(requireNonNull(name, "name")); + } + + /** + * Get a logger instance with the binary name of the provided class. + * + *

This logger is produced by implementations of the {@link ComponentLoggerProvider}.

+ * + * @param clazz the class to use when naming the logger + * @return a logger with the name of the calling class + * @since 4.11.0 + */ + static @NotNull ComponentLogger logger(final @NotNull Class clazz) { + return logger(clazz.getName()); + } + + /** + * Log a message at the TRACE level. + * + * @param msg the message string to be logged + * @since 4.11.0 + */ + void trace(final @NotNull Component msg); + + /** + * Log a message at the TRACE level according to the specified format + * and argument. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the TRACE level.

+ * + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void trace(final @NotNull Component format, final @Nullable Object arg); + + /** + * Log a message at the TRACE level according to the specified format + * and arguments. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the TRACE level.

+ * + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void trace(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * Log a message at the TRACE level according to the specified format + * and arguments. + * + *

This form avoids superfluous string concatenation when the logger + * is disabled for the TRACE level. However, this variant incurs the hidden + * (and relatively small) cost of creating an Object[] before invoking the method, + * even if this logger is disabled for TRACE. The variants taking {@link #trace(Component, Object) one} and + * {@link #trace(Component, Object, Object) two} arguments exist solely in order to avoid this hidden cost.

+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void trace(final @NotNull Component format, final @Nullable Object @NotNull... arguments); + + /** + * Log an exception (throwable) at the TRACE level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void trace(final @NotNull Component msg, final @Nullable Throwable t); + + /** + * Log a message with the specific Marker at the TRACE level. + * + * @param marker the marker data specific to this log statement + * @param msg the message string to be logged + * @since 4.11.0 + */ + void trace(final @NotNull Marker marker, final @NotNull Component msg); + + /** + * This method is similar to {@link #trace(Component, Object)} method except that the + * marker data is also taken into consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void trace(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg); + + /** + * This method is similar to {@link #trace(Component, Object, Object)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void trace(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * This method is similar to {@link #trace(Component, Object...)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param argArray an array of arguments + * @since 4.11.0 + */ + void trace(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object @NotNull... argArray); + + /** + * This method is similar to {@link #trace(Component, Throwable)} method except that the + * marker data is also taken into consideration. + * + * @param marker the marker data specific to this log statement + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void trace(final @NotNull Marker marker, final @NotNull Component msg, final @Nullable Throwable t); + + /** + * Log a message at the DEBUG level. + * + * @param msg the message string to be logged + * @since 4.11.0 + */ + void debug(final @NotNull Component msg); + + /** + * Log a message at the DEBUG level according to the specified format + * and argument. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the DEBUG level.

+ * + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void debug(final @NotNull Component format, final @Nullable Object arg); + + /** + * Log a message at the DEBUG level according to the specified format + * and arguments. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the DEBUG level.

+ * + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void debug(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * Log a message at the DEBUG level according to the specified format + * and arguments. + * + *

This form avoids superfluous string concatenation when the logger + * is disabled for the DEBUG level. However, this variant incurs the hidden + * (and relatively small) cost of creating an Object[] before invoking the method, + * even if this logger is disabled for DEBUG. The variants taking + * {@link #debug(Component, Object) one} and {@link #debug(Component, Object, Object) two} + * arguments exist solely in order to avoid this hidden cost.

+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void debug(final @NotNull Component format, final @Nullable Object @NotNull... arguments); + + /** + * Log an exception (throwable) at the DEBUG level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void debug(final @NotNull Component msg, final @Nullable Throwable t); + + /** + * Log a message with the specific Marker at the DEBUG level. + * + * @param marker the marker data specific to this log statement + * @param msg the message string to be logged + * @since 4.11.0 + */ + void debug(final @NotNull Marker marker, final @NotNull Component msg); + + /** + * This method is similar to {@link #debug(Component, Object)} method except that the + * marker data is also taken into consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void debug(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg); + + /** + * This method is similar to {@link #debug(Component, Object, Object)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void debug(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * This method is similar to {@link #debug(Component, Object...)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void debug(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object @NotNull... arguments); + + /** + * This method is similar to {@link #debug(Component, Throwable)} method except that the + * marker data is also taken into consideration. + * + * @param marker the marker data specific to this log statement + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void debug(final @NotNull Marker marker, final @NotNull Component msg, final @Nullable Throwable t); + + /** + * Log a message at the INFO level. + * + * @param msg the message string to be logged + * @since 4.11.0 + */ + void info(final @NotNull Component msg); + + /** + * Log a message at the INFO level according to the specified format + * and argument. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the INFO level.

+ * + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void info(final @NotNull Component format, final @Nullable Object arg); + + /** + * Log a message at the INFO level according to the specified format + * and arguments. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the INFO level.

+ * + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void info(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * Log a message at the INFO level according to the specified format + * and arguments. + * + *

This form avoids superfluous string concatenation when the logger + * is disabled for the INFO level. However, this variant incurs the hidden + * (and relatively small) cost of creating an Object[] before invoking the method, + * even if this logger is disabled for INFO. The variants taking + * {@link #info(Component, Object) one} and {@link #info(Component, Object, Object) two} + * arguments exist solely in order to avoid this hidden cost.

+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void info(final @NotNull Component format, final @Nullable Object@NotNull... arguments); + + /** + * Log an exception (throwable) at the INFO level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void info(final @NotNull Component msg, final @Nullable Throwable t); + + /** + * Log a message with the specific Marker at the INFO level. + * + * @param marker The marker specific to this log statement + * @param msg the message string to be logged + * @since 4.11.0 + */ + void info(final @NotNull Marker marker, final @NotNull Component msg); + + /** + * This method is similar to {@link #info(Component, Object)} method except that the + * marker data is also taken into consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void info(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg); + + /** + * This method is similar to {@link #info(Component, Object, Object)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void info(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * This method is similar to {@link #info(Component, Object...)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void info(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object@NotNull... arguments); + + /** + * This method is similar to {@link #info(Component, Throwable)} method + * except that the marker data is also taken into consideration. + * + * @param marker the marker data for this log statement + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void info(final @NotNull Marker marker, final @NotNull Component msg, final @NotNull Throwable t); + + /** + * Log a message at the WARN level. + * + * @param msg the message string to be logged + * @since 4.11.0 + */ + void warn(final @NotNull Component msg); + + /** + * Log a message at the WARN level according to the specified format + * and argument. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the WARN level.

+ * + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void warn(final @NotNull Component format, final @Nullable Object arg); + + /** + * Log a message at the WARN level according to the specified format + * and arguments. + * + *

This form avoids superfluous string concatenation when the logger + * is disabled for the WARN level. However, this variant incurs the hidden + * (and relatively small) cost of creating an Object[] before invoking the method, + * even if this logger is disabled for WARN. The variants taking + * {@link #warn(Component, Object) one} and {@link #warn(Component, Object, Object) two} + * arguments exist solely in order to avoid this hidden cost.

+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void warn(final @NotNull Component format, final @Nullable Object@NotNull... arguments); + + /** + * Log a message at the WARN level according to the specified format + * and arguments. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the WARN level.

+ * + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void warn(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * Log an exception (throwable) at the WARN level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void warn(final @NotNull Component msg, final @NotNull Throwable t); + + /** + * Log a message with the specific final @NotNull Marker at the WARN level. + * + * @param marker The marker specific to this log statement + * @param msg the message string to be logged + * @since 4.11.0 + */ + void warn(final @NotNull Marker marker, final @NotNull Component msg); + + /** + * This method is similar to {@link #warn(Component, Object)} method except that the + * marker data is also taken into consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void warn(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg); + + /** + * This method is similar to {@link #warn(Component, Object, Object)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void warn(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * This method is similar to {@link #warn(Component, Object...)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void warn(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object@NotNull... arguments); + + /** + * This method is similar to {@link #warn(Component, Throwable)} method + * except that the marker data is also taken into consideration. + * + * @param marker the marker data for this log statement + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void warn(final @NotNull Marker marker, final @NotNull Component msg, final @NotNull Throwable t); + + /** + * Log a message at the ERROR level. + * + * @param msg the message string to be logged + * @since 4.11.0 + */ + void error(final @NotNull Component msg); + + /** + * Log a message at the ERROR level according to the specified format + * and argument. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the ERROR level.

+ * + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void error(final @NotNull Component format, final @Nullable Object arg); + + /** + * Log a message at the ERROR level according to the specified format + * and arguments. + * + *

This form avoids superfluous object creation when the logger + * is disabled for the ERROR level.

+ * + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void error(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * Log a message at the ERROR level according to the specified format + * and arguments. + * + *

This form avoids superfluous string concatenation when the logger + * is disabled for the ERROR level. However, this variant incurs the hidden + * (and relatively small) cost of creating an Object[] before invoking the method, + * even if this logger is disabled for ERROR. The variants taking + * {@link #error(Component, Object) one} and {@link #error(Component, Object, Object) two} + * arguments exist solely in order to avoid this hidden cost.

+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void error(final @NotNull Component format, final @Nullable Object@NotNull... arguments); + + /** + * Log an exception (throwable) at the ERROR level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void error(final @NotNull Component msg, final @NotNull Throwable t); + + /** + * Log a message with the specific final @NotNull Marker at the ERROR level. + * + * @param marker The marker specific to this log statement + * @param msg the message string to be logged + * @since 4.11.0 + */ + void error(final @NotNull Marker marker, final @NotNull Component msg); + + /** + * This method is similar to {@link #error(Component, Object)} method except that the + * marker data is also taken into consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg the argument + * @since 4.11.0 + */ + void error(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg); + + /** + * This method is similar to {@link #error(Component, Object, Object)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arg1 the first argument + * @param arg2 the second argument + * @since 4.11.0 + */ + void error(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2); + + /** + * This method is similar to {@link #error(Component, Object...)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param format the format string + * @param arguments a list of 3 or more arguments + * @since 4.11.0 + */ + void error(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object@NotNull... arguments); + + /** + * This method is similar to {@link #error(Component, Throwable)} + * method except that the marker data is also taken into + * consideration. + * + * @param marker the marker data specific to this log statement + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + * @since 4.11.0 + */ + void error(final @NotNull Marker marker, final @NotNull Component msg, final @NotNull Throwable t); +} diff --git a/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/ComponentLoggerProvider.java b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/ComponentLoggerProvider.java new file mode 100644 index 000000000..4e9f50520 --- /dev/null +++ b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/ComponentLoggerProvider.java @@ -0,0 +1,77 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +import java.util.function.Function; +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; + +/** + * A service interface for platforms to provide their own component logger implementations. + * + * @since 4.11.0 + */ +@ApiStatus.Internal // SPI for platform use only +public interface ComponentLoggerProvider { + /** + * Create a component logger for the provided logger name. + * + * @param helper a source for common helper implementations when building a logger + * @param name the logger name + * @return a component logger with the provided name + * @since 4.11.0 + */ + @NotNull ComponentLogger logger(final @NotNull LoggerHelper helper, final @NotNull String name); + + /** + * A factory for default implementations of component loggers. + * + * @since 4.11.0 + */ + @ApiStatus.NonExtendable + interface LoggerHelper { + + /** + * Create a serializer function that will translate logged output into the system default locale, and then serialize it to plain text. + * + * @return a plain serializer + * @since 4.11.0 + */ + @NotNull Function plainSerializer(); + + /** + * Create a component logger based on one which delegates to an underlying plain {@link Logger} implementation. + * + *

This sort of logger requires Components to be serialized to some sort of formatted {@link String} to match the SLF4J contract.

+ * + * @param base the base logger + * @param serializer the serializer to translate and format a component in a log message. + * @return a new logger + * @since 4.11.0 + */ + @NotNull ComponentLogger delegating(final @NotNull Logger base, final @NotNull Function serializer); + } +} diff --git a/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/Handler.java b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/Handler.java new file mode 100644 index 000000000..33d8c85cd --- /dev/null +++ b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/Handler.java @@ -0,0 +1,88 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.flattener.ComponentFlattener; +import net.kyori.adventure.translation.GlobalTranslator; +import net.kyori.adventure.util.Services; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility methods relating to creating component loggers. + */ +final class Handler { + private static final ComponentLoggerProvider PROVIDER = Services.service(ComponentLoggerProvider.class) + .orElse(LoggerFactory.getILoggerFactory() instanceof ComponentLoggerProvider ? (ComponentLoggerProvider) LoggerFactory.getILoggerFactory() : new DefaultProvider()); + + private Handler() { + } + + static ComponentLogger logger(final String name) { + return PROVIDER.logger(LoggerHelperImpl.INSTANCE, name); + } + + static final class DefaultProvider implements ComponentLoggerProvider { + private final Map loggers = new ConcurrentHashMap<>(); + + @Override + public @NotNull ComponentLogger logger(final @NotNull LoggerHelper helper, final @NotNull String name) { + final ComponentLogger initial = this.loggers.get(name); + if (initial != null) return initial; + + final Logger backing = LoggerFactory.getLogger(name); + final ComponentLogger created = helper.delegating(backing, helper.plainSerializer()); + final ComponentLogger existing = this.loggers.putIfAbsent(name, created); + return existing == null ? created : existing; + } + } + + static final class LoggerHelperImpl implements ComponentLoggerProvider.LoggerHelper { + static final LoggerHelperImpl INSTANCE = new LoggerHelperImpl(); + + LoggerHelperImpl() { + } + + @Override + public Function plainSerializer() { + return comp -> { + final Component translated = GlobalTranslator.render(comp, Locale.getDefault()); + final StringBuilder contents = new StringBuilder(); + ComponentFlattener.basic().flatten(translated, contents::append); + return contents.toString(); + }; + } + + @Override + public @NotNull ComponentLogger delegating(final @NotNull Logger base, final @NotNull Function serializer) { + return new WrappingComponentLoggerImpl(base, serializer); + } + } +} diff --git a/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/UnpackedComponentThrowable.java b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/UnpackedComponentThrowable.java new file mode 100644 index 000000000..25388b1f4 --- /dev/null +++ b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/UnpackedComponentThrowable.java @@ -0,0 +1,73 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +import java.util.function.Function; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.util.ComponentMessageThrowable; +import org.jetbrains.annotations.Nullable; + +/** + * A wrapper for exceptions that implement ComponentMessageThrowable. + */ +final class UnpackedComponentThrowable extends Throwable { + private static final long serialVersionUID = -1L; + + private final Class backingType; + + static Throwable unpack(final Throwable maybeRich, final Function serializer) { + if (!(maybeRich instanceof ComponentMessageThrowable)) return maybeRich; // TODO: do we need to unwrap any nested exceptions? + + final @Nullable Component message = ((ComponentMessageThrowable) maybeRich).componentMessage(); + final Throwable cause = maybeRich.getCause() != null ? unpack(maybeRich.getCause(), serializer) : null; + final Throwable[] suppressed = maybeRich.getSuppressed(); + + final UnpackedComponentThrowable ret = new UnpackedComponentThrowable(maybeRich.getClass(), serializer.apply(message), cause); + ret.setStackTrace(maybeRich.getStackTrace()); + if (suppressed.length > 0) { + for (int i = 0; i < suppressed.length; i++) { + ret.addSuppressed(unpack(suppressed[i], serializer)); + } + } + + return ret; + } + + private UnpackedComponentThrowable(final Class backingType, final String serializedMessage, final Throwable cause) { + super(serializedMessage, cause); + this.backingType = backingType; + } + + @Override + public String toString() { + final String className = this.backingType.getName(); + final String message = this.getMessage(); + return message == null ? className : className + ":" + message; + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } +} diff --git a/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/WrappingComponentLoggerImpl.java b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/WrappingComponentLoggerImpl.java new file mode 100644 index 000000000..4d13594fd --- /dev/null +++ b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/WrappingComponentLoggerImpl.java @@ -0,0 +1,1944 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +import java.util.Arrays; +import java.util.function.Function; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.Marker; +import org.slf4j.spi.LocationAwareLogger; + +final class WrappingComponentLoggerImpl implements ComponentLogger { + private static final String FQCN = WrappingComponentLoggerImpl.class.getName(); + + private final Logger logger; + private final boolean isLocationAware; + private final Function serializer; + + WrappingComponentLoggerImpl(final Logger backing, final Function serializer) { + this.serializer = serializer; + this.logger = backing; + this.isLocationAware = backing instanceof LocationAwareLogger; + } + + private String serialize(final Component input) { + if (input == null) return null; + + return this.serializer.apply(input); + } + + private Object maybeSerialize(final @Nullable Object input) { + if (input instanceof ComponentLike) { + return this.serialize(((ComponentLike) input).asComponent()); + } else { + return input; + } + } + + private Object[] maybeSerialize(final @Nullable Object@NotNull... args) { + Object[] writable = args; + for (int i = 0; i < writable.length; i++) { + if (writable[i] instanceof ComponentLike) { + if (writable == args) { + writable = Arrays.copyOf(args, args.length); + } + writable[i] = this.serialize(((ComponentLike) writable[i]).asComponent()); + } + } + + if (writable.length > 0 && writable[writable.length - 1] instanceof Throwable) { + if (writable == args) { + writable = Arrays.copyOf(args, args.length); + } + writable[writable.length - 1] = UnpackedComponentThrowable.unpack((Throwable) writable[writable.length - 1], this.serializer); + } + + return writable; + } + + // Basic methods, plain delegation + + @Override + public String getName() { + return this.logger.getName(); + } + + @Override + public boolean isTraceEnabled() { + return this.logger.isTraceEnabled(); + } + + @Override + public boolean isTraceEnabled(final Marker marker) { + return this.logger.isTraceEnabled(marker); + } + + @Override + public boolean isDebugEnabled() { + return this.logger.isDebugEnabled(); + } + + @Override + public boolean isDebugEnabled(final Marker marker) { + return this.logger.isDebugEnabled(marker); + } + + @Override + public boolean isInfoEnabled() { + return this.logger.isInfoEnabled(); + } + + @Override + public boolean isInfoEnabled(final Marker marker) { + return this.logger.isInfoEnabled(marker); + } + + @Override + public boolean isWarnEnabled() { + return this.logger.isWarnEnabled(); + } + + @Override + public boolean isWarnEnabled(final Marker marker) { + return this.logger.isWarnEnabled(marker); + } + + @Override + public boolean isErrorEnabled() { + return this.logger.isErrorEnabled(); + } + + @Override + public boolean isErrorEnabled(final Marker marker) { + return this.logger.isErrorEnabled(marker); + } + + // Standard string methods, to process potential Component arguments + + @Override + public void trace(final @NotNull String format) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + format, + null, + null + ); + } else { + this.logger.trace(format); + } + } + + @Override + public void trace(final @NotNull String format, final @Nullable Object arg) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.trace(format, this.maybeSerialize(arg)); + } + } + + @Override + public void trace(final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.trace(format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void trace(final @NotNull String format, final @Nullable Object @NotNull... arguments) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + format, + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.trace(format, this.maybeSerialize(arguments)); + } + } + + @Override + public void trace(final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.trace(msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull String msg) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + msg, + null, + null + ); + } else { + this.logger.trace(marker, msg); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.trace(marker, format, this.maybeSerialize(arg)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.trace(marker, format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object @NotNull... argArray) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + format, + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.trace(marker, format, this.maybeSerialize(argArray)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.trace(marker, msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void debug(final @NotNull String format) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + format, + null, + null + ); + } else { + this.logger.debug(format); + } + } + + @Override + public void debug(final @NotNull String format, final @Nullable Object arg) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.debug(format, this.maybeSerialize(arg)); + } + } + + @Override + public void debug(final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.debug(format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void debug(final @NotNull String format, final @Nullable Object @NotNull... arguments) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + format, + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.debug(format, this.maybeSerialize(arguments)); + } + } + + @Override + public void debug(final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.debug(msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull String msg) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + msg, + null, + null + ); + } else { + this.logger.debug(marker, msg); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.debug(marker, format, this.maybeSerialize(arg)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.debug(marker, format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object @NotNull... argArray) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + format, + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.debug(marker, format, this.maybeSerialize(argArray)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.debug(marker, msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void info(final @NotNull String format) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + format, + null, + null + ); + } else { + this.logger.info(format); + } + } + + @Override + public void info(final @NotNull String format, final @Nullable Object arg) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.info(format, this.maybeSerialize(arg)); + } + } + + @Override + public void info(final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.info(format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void info(final @NotNull String format, final @Nullable Object @NotNull... arguments) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + format, + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.info(format, this.maybeSerialize(arguments)); + } + } + + @Override + public void info(final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.info(msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull String msg) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + msg, + null, + null + ); + } else { + this.logger.info(marker, msg); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.info(marker, format, this.maybeSerialize(arg)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.info(marker, format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object @NotNull... argArray) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + format, + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.info(marker, format, this.maybeSerialize(argArray)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.info(marker, msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void warn(final @NotNull String format) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + format, + null, + null + ); + } else { + this.logger.warn(format); + } + } + + @Override + public void warn(final @NotNull String format, final @Nullable Object arg) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.warn(format, this.maybeSerialize(arg)); + } + } + + @Override + public void warn(final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.warn(format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void warn(final @NotNull String format, final @Nullable Object @NotNull... arguments) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + format, + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.warn(format, this.maybeSerialize(arguments)); + } + } + + @Override + public void warn(final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.warn(msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull String msg) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + msg, + null, + null + ); + } else { + this.logger.warn(marker, msg); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.warn(marker, format, this.maybeSerialize(arg)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.warn(marker, format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object @NotNull... argArray) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + format, + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.warn(marker, format, this.maybeSerialize(argArray)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.warn(marker, msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void error(final @NotNull String format) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + format, + null, + null + ); + } else { + this.logger.error(format); + } + } + + @Override + public void error(final @NotNull String format, final @Nullable Object arg) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.error(format, this.maybeSerialize(arg)); + } + } + + @Override + public void error(final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.error(format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void error(final @NotNull String format, final @Nullable Object @NotNull... arguments) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + format, + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.error(format, this.maybeSerialize(arguments)); + } + } + + @Override + public void error(final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.error(msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull String msg) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + msg, + null, + null + ); + } else { + this.logger.error(marker, msg); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + format, + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.error(marker, format, this.maybeSerialize(arg)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + format, + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.error(marker, format, this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull String format, final @Nullable Object @NotNull... argArray) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + format, + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.error(marker, format, this.maybeSerialize(argArray)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull String msg, final @Nullable Throwable t) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + msg, + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.error(marker, msg, UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + // Component-primary methods + + @Override + public void trace(final @NotNull Component format) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(format), + null, + null + ); + } else { + this.logger.trace(this.serialize(format)); + } + } + + @Override + public void trace(final @NotNull Component format, final @Nullable Object arg) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.trace(this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void trace(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.trace(this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void trace(final @NotNull Component format, final @Nullable Object @NotNull... arguments) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(format), + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.trace(this.serialize(format), this.maybeSerialize(arguments)); + } + } + + @Override + public void trace(final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isTraceEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.trace(this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull Component msg) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(msg), + null, + null + ); + } else { + this.logger.trace(marker, this.serialize(msg)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.trace(marker, this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.trace(marker, this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object @NotNull... argArray) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(format), + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.trace(marker, this.serialize(format), this.maybeSerialize(argArray)); + } + } + + @Override + public void trace(final @NotNull Marker marker, final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isTraceEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.TRACE_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.trace(marker, this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void debug(final @NotNull Component format) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(format), + null, + null + ); + } else { + this.logger.debug(this.serialize(format)); + } + } + + @Override + public void debug(final @NotNull Component format, final @Nullable Object arg) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.debug(this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void debug(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.debug(this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void debug(final @NotNull Component format, final @Nullable Object @NotNull... arguments) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(format), + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.debug(this.serialize(format), this.maybeSerialize(arguments)); + } + } + + @Override + public void debug(final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isDebugEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.debug(this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull Component msg) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(msg), + null, + null + ); + } else { + this.logger.debug(marker, this.serialize(msg)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.debug(marker, this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.debug(marker, this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object @NotNull... argArray) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(format), + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.debug(marker, this.serialize(format), this.maybeSerialize(argArray)); + } + } + + @Override + public void debug(final @NotNull Marker marker, final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isDebugEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.DEBUG_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.debug(marker, this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void info(final @NotNull Component format) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(format), + null, + null + ); + } else { + this.logger.info(this.serialize(format)); + } + } + + @Override + public void info(final @NotNull Component format, final @Nullable Object arg) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.info(this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void info(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.info(this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void info(final @NotNull Component format, final @Nullable Object @NotNull... arguments) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(format), + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.info(this.serialize(format), this.maybeSerialize(arguments)); + } + } + + @Override + public void info(final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isInfoEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.info(this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull Component msg) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(msg), + null, + null + ); + } else { + this.logger.info(marker, this.serialize(msg)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.info(marker, this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.info(marker, this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object @NotNull... argArray) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(format), + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.info(marker, this.serialize(format), this.maybeSerialize(argArray)); + } + } + + @Override + public void info(final @NotNull Marker marker, final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isInfoEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.INFO_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.info(marker, this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void warn(final @NotNull Component format) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(format), + null, + null + ); + } else { + this.logger.warn(this.serialize(format)); + } + } + + @Override + public void warn(final @NotNull Component format, final @Nullable Object arg) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.warn(this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void warn(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.warn(this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void warn(final @NotNull Component format, final @Nullable Object @NotNull... arguments) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(format), + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.warn(this.serialize(format), this.maybeSerialize(arguments)); + } + } + + @Override + public void warn(final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isWarnEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.warn(this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull Component msg) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(msg), + null, + null + ); + } else { + this.logger.warn(marker, this.serialize(msg)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.warn(marker, this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.warn(marker, this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object @NotNull... argArray) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(format), + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.warn(marker, this.serialize(format), this.maybeSerialize(argArray)); + } + } + + @Override + public void warn(final @NotNull Marker marker, final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isWarnEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.WARN_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.warn(marker, this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void error(final @NotNull Component format) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(format), + null, + null + ); + } else { + this.logger.error(this.serialize(format)); + } + } + + @Override + public void error(final @NotNull Component format, final @Nullable Object arg) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.error(this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void error(final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.error(this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void error(final @NotNull Component format, final @Nullable Object @NotNull... arguments) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(format), + this.maybeSerialize(arguments), + null + ); + } else { + this.logger.error(this.serialize(format), this.maybeSerialize(arguments)); + } + } + + @Override + public void error(final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isErrorEnabled()) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + null, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.error(this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull Component msg) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(msg), + null, + null + ); + } else { + this.logger.error(marker, this.serialize(msg)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg)}, + null + ); + } else { + this.logger.error(marker, this.serialize(format), this.maybeSerialize(arg)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object arg1, final @Nullable Object arg2) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(format), + new Object[] {this.maybeSerialize(arg1), this.maybeSerialize(arg2)}, + null + ); + } else { + this.logger.error(marker, this.serialize(format), this.maybeSerialize(arg1), this.maybeSerialize(arg2)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull Component format, final @Nullable Object @NotNull... argArray) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(format), + this.maybeSerialize(argArray), + null + ); + } else { + this.logger.error(marker, this.serialize(format), this.maybeSerialize(argArray)); + } + } + + @Override + public void error(final @NotNull Marker marker, final @NotNull Component msg, final @Nullable Throwable t) { + if (!this.isErrorEnabled(marker)) return; + + if (this.isLocationAware) { + ((LocationAwareLogger) this.logger).log( + marker, + FQCN, + LocationAwareLogger.ERROR_INT, + this.serialize(msg), + null, + UnpackedComponentThrowable.unpack(t, this.serializer) + ); + } else { + this.logger.error(marker, this.serialize(msg), UnpackedComponentThrowable.unpack(t, this.serializer)); + } + } +} diff --git a/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/package-info.java b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/package-info.java new file mode 100644 index 000000000..04aa92e82 --- /dev/null +++ b/text-logger-slf4j/src/main/java/net/kyori/adventure/text/logger/slf4j/package-info.java @@ -0,0 +1,29 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * A wrapper around SLF4J providing methods for formatted logging of Components. + * + *

This wrapper supports the API provided in 1.7/1.8, but does not yet implement the fluent API present in the 2.0 betas.

+ */ +package net.kyori.adventure.text.logger.slf4j; diff --git a/text-logger-slf4j/src/main/java9/net/kyori/adventure/text/logger/slf4j/CallerClassFinder.java b/text-logger-slf4j/src/main/java9/net/kyori/adventure/text/logger/slf4j/CallerClassFinder.java new file mode 100644 index 000000000..0054a096a --- /dev/null +++ b/text-logger-slf4j/src/main/java9/net/kyori/adventure/text/logger/slf4j/CallerClassFinder.java @@ -0,0 +1,41 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +// Java 9+ version, see Java 8 version as well +final class CallerClassFinder { + private CallerClassFinder() { + } + + static String callingClassName() { + return callingClassName(2); // this, plus the calling method + } + + static String callingClassName(final int elementsToSkip) { // elementsToSkip not counting this method + return StackWalker.getInstance().walk(stream -> stream.map(StackWalker.StackFrame::getClassName) + .skip(elementsToSkip + 1) + .findFirst()) + .orElseThrow(() -> new IllegalArgumentException("Not enough stack elements to skip " + elementsToSkip + " elements")); + } +} diff --git a/text-logger-slf4j/src/test/java/net/kyori/adventure/text/logger/slf4j/CallerClassFinderTest.java b/text-logger-slf4j/src/test/java/net/kyori/adventure/text/logger/slf4j/CallerClassFinderTest.java new file mode 100644 index 000000000..afe3240ea --- /dev/null +++ b/text-logger-slf4j/src/test/java/net/kyori/adventure/text/logger/slf4j/CallerClassFinderTest.java @@ -0,0 +1,42 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CallerClassFinderTest { + + @Test + void testCallerClass() { + assertEquals(CallerClassFinderTest.class.getName(), Holder.test()); + } + + static final class Holder { + static String test() { + return CallerClassFinder.callingClassName(); + } + } +} diff --git a/text-logger-slf4j/src/test/java/net/kyori/adventure/text/logger/slf4j/ComponentLoggerTest.java b/text-logger-slf4j/src/test/java/net/kyori/adventure/text/logger/slf4j/ComponentLoggerTest.java new file mode 100644 index 000000000..ba7b759e2 --- /dev/null +++ b/text-logger-slf4j/src/test/java/net/kyori/adventure/text/logger/slf4j/ComponentLoggerTest.java @@ -0,0 +1,159 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.logger.slf4j; + +import com.github.valfirst.slf4jtest.LoggingEvent; +import com.github.valfirst.slf4jtest.TestLogger; +import com.github.valfirst.slf4jtest.TestLoggerFactory; +import com.github.valfirst.slf4jtest.TestLoggerFactoryExtension; +import com.google.common.collect.ImmutableList; +import java.util.List; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.util.ComponentMessageThrowable; +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(TestLoggerFactoryExtension.class) +public class ComponentLoggerTest { + private static final TestLogger LOGGER = TestLoggerFactory.getTestLogger(ComponentLoggerTest.class); + + private static final Marker MARKED = MarkerFactory.getMarker("MARKED"); + + ComponentLogger makeLogger() { + return ComponentLogger.logger(); + } + + @Test + void testCallerLogger() { + final ComponentLogger logger = ComponentLogger.logger(); + assertEquals(this.getClass().getName(), logger.getName()); + } + + @Test + void testLogSimple() { + final Component toLog = Component.text() + .content("Hello ") + .color(NamedTextColor.RED) + .append(Component.translatable("location.world")) + .build(); + + this.makeLogger().info(toLog); + + assertEquals(LOGGER.getLoggingEvents(), ImmutableList.of(LoggingEvent.info("Hello location.world"))); + } + + @Test + void testComponentArg() { + final Component message = Component.text("Hello ").append(Component.text("{}", NamedTextColor.BLUE)); + final Component arg = Component.selector("@s"); + + this.makeLogger().warn(message, arg); + + assertEquals(LOGGER.getLoggingEvents(), ImmutableList.of(LoggingEvent.warn("Hello {}", "@s"))); + } + + @Test + void testStringArg() { + final Component message = Component.text("Hello ").append(Component.text("{}", NamedTextColor.BLUE)); + final String arg = "world"; + + this.makeLogger().debug(message, arg); + + assertEquals(LOGGER.getLoggingEvents(), ImmutableList.of(LoggingEvent.debug("Hello {}", arg))); + } + + @Test + void testMultiArgs() { + final Component message = Component.text("Good morning! The time is {} and you have {} cats!"); + final Component arg0 = Component.text("14:28", NamedTextColor.BLUE); + final String arg1 = "11"; + + this.makeLogger().error(message, arg0, arg1); + assertEquals( + LOGGER.getLoggingEvents(), + ImmutableList.of(LoggingEvent.error("Good morning! The time is {} and you have {} cats!", "14:28", "11")) + ); + } + + @Test + void testUnwrapThrowable() { + final Component message = Component.text("Hello world"); + final Exception error = new RichTestException(Component.translatable("test.failed", NamedTextColor.DARK_PURPLE)); + + this.makeLogger().warn(message, error); + + final List events = LOGGER.getLoggingEvents(); + assertEquals(1, events.size()); + final Throwable thrownException = events.get(0).getThrowable().orElse(null); + assertNotNull(thrownException); + + assertEquals("test.failed", thrownException.getMessage()); + assertArrayEquals(error.getStackTrace(), thrownException.getStackTrace()); + assertTrue(thrownException.toString().startsWith("net.kyori.adventure.text.logger.slf4j.ComponentLoggerTest$RichTestException")); + } + + static class RichTestException extends Exception implements ComponentMessageThrowable { + private static final long serialVersionUID = -1l; + + private final Component richMessage; + + RichTestException(final Component richMessage) { + super("no"); + this.richMessage = richMessage; + } + + @Override + public @Nullable Component componentMessage() { + return this.richMessage; + } + } + + @Test + void testWithMarker() { + final Component message = Component.text("meow :3"); + this.makeLogger().info(MARKED, message); + assertEquals( + LOGGER.getLoggingEvents(), + ImmutableList.of(LoggingEvent.info(MARKED, "meow :3")) + ); + } + + @Test + void testComponentAsArgToPlainLog() { + this.makeLogger().info("Hello {}", Component.text("friend")); + assertEquals( + LOGGER.getLoggingEvents(), + ImmutableList.of(LoggingEvent.info("Hello {}", "friend")) + ); + } +}