From 3555b6643a6701b045b4b7fb1eb632c16452e19d Mon Sep 17 00:00:00 2001 From: Will Sargent Date: Sun, 23 Jul 2023 15:15:13 -0700 Subject: [PATCH] Update logger context (#309) --- .../echopraxia/spi/CoreLogger.java | 3 + .../echopraxia/spi/DelegateCoreLogger.java | 5 ++ .../echopraxia/spi/LoggerContext.java | 11 +++ .../echopraxia/fake/FakeCoreLogger.java | 73 +++++++++++++------ .../echopraxia/fake/FakeLoggerContext.java | 32 ++++++++ .../echopraxia/jul/JULCoreLogger.java | 6 ++ .../echopraxia/jul/JULLoggerContext.java | 3 +- .../echopraxia/log4j/Log4JCoreLogger.java | 8 +- .../echopraxia/log4j/ContextTest.java | 15 ++++ .../logback/LogbackLoggerContext.java | 6 +- .../logstash/LogstashCoreLogger.java | 6 ++ .../echopraxia/logstash/ContextTest.java | 16 ++++ 12 files changed, 157 insertions(+), 27 deletions(-) create mode 100644 api/src/main/java/com/tersesystems/echopraxia/spi/LoggerContext.java create mode 100644 api/src/testFixtures/java/com/tersesystems/echopraxia/fake/FakeLoggerContext.java diff --git a/api/src/main/java/com/tersesystems/echopraxia/spi/CoreLogger.java b/api/src/main/java/com/tersesystems/echopraxia/spi/CoreLogger.java index 402ccb33..08c4f17c 100644 --- a/api/src/main/java/com/tersesystems/echopraxia/spi/CoreLogger.java +++ b/api/src/main/java/com/tersesystems/echopraxia/spi/CoreLogger.java @@ -28,6 +28,9 @@ public interface CoreLogger { @NotNull String getName(); + @NotNull + LoggerContext getLoggerContext(); + /** * Returns the given condition. * diff --git a/api/src/main/java/com/tersesystems/echopraxia/spi/DelegateCoreLogger.java b/api/src/main/java/com/tersesystems/echopraxia/spi/DelegateCoreLogger.java index 837baf48..829fedb6 100644 --- a/api/src/main/java/com/tersesystems/echopraxia/spi/DelegateCoreLogger.java +++ b/api/src/main/java/com/tersesystems/echopraxia/spi/DelegateCoreLogger.java @@ -25,6 +25,11 @@ public String getName() { return core.getName(); } + @Override + public @NotNull LoggerContext getLoggerContext() { + return core.getLoggerContext(); + } + @Override @NotNull public Condition condition() { diff --git a/api/src/main/java/com/tersesystems/echopraxia/spi/LoggerContext.java b/api/src/main/java/com/tersesystems/echopraxia/spi/LoggerContext.java new file mode 100644 index 00000000..7f25fc8c --- /dev/null +++ b/api/src/main/java/com/tersesystems/echopraxia/spi/LoggerContext.java @@ -0,0 +1,11 @@ +package com.tersesystems.echopraxia.spi; + +import com.tersesystems.echopraxia.api.Field; +import java.util.List; +import org.jetbrains.annotations.NotNull; + +public interface LoggerContext { + + @NotNull + List getLoggerFields(); +} diff --git a/api/src/testFixtures/java/com/tersesystems/echopraxia/fake/FakeCoreLogger.java b/api/src/testFixtures/java/com/tersesystems/echopraxia/fake/FakeCoreLogger.java index c70f8d38..5170b7ca 100644 --- a/api/src/testFixtures/java/com/tersesystems/echopraxia/fake/FakeCoreLogger.java +++ b/api/src/testFixtures/java/com/tersesystems/echopraxia/fake/FakeCoreLogger.java @@ -1,7 +1,11 @@ package com.tersesystems.echopraxia.fake; +import static com.tersesystems.echopraxia.spi.Utilities.joinFields; + import com.tersesystems.echopraxia.api.*; import com.tersesystems.echopraxia.spi.CoreLogger; +import com.tersesystems.echopraxia.spi.LoggerContext; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; @@ -14,7 +18,7 @@ public class FakeCoreLogger implements CoreLogger { - private final FakeLoggingContext context; + private final FakeLoggerContext context; private final Condition condition; private final Executor executor; private final String fqcn; @@ -23,7 +27,7 @@ public class FakeCoreLogger implements CoreLogger { public FakeCoreLogger(String fqcn) { this.fqcn = fqcn; - this.context = FakeLoggingContext.empty(this); + this.context = FakeLoggerContext.empty(); this.condition = Condition.always(); this.executor = ForkJoinPool.commonPool(); this.tlsSupplier = () -> (Runnable) () -> {}; @@ -31,7 +35,7 @@ public FakeCoreLogger(String fqcn) { public FakeCoreLogger( String fqcn, - FakeLoggingContext context, + FakeLoggerContext context, Condition condition, Executor executor, Supplier tlsSupplier) { @@ -49,17 +53,24 @@ public FakeCoreLogger( @Override public boolean isEnabled(@NotNull Level level) { - return this.condition.test(level, context); + return this.condition.test( + level, new FakeLoggingContext(this, context::getLoggerFields, Collections::emptyList)); } @Override public boolean isEnabled(@NotNull Level level, @NotNull Condition condition) { - return this.condition.and(condition).test(level, context); + return this.condition + .and(condition) + .test( + level, new FakeLoggingContext(this, context::getLoggerFields, Collections::emptyList)); } @Override public boolean isEnabled(@NotNull Level level, @NotNull Supplier> extraFields) { - return this.condition.test(level, context.withFields(extraFields)); + return this.condition.test( + level, + new FakeLoggingContext( + this, () -> context.withFields(extraFields).getLoggerFields(), Collections::emptyList)); } @Override @@ -67,7 +78,14 @@ public boolean isEnabled( @NotNull Level level, @NotNull Condition condition, @NotNull Supplier> extraFields) { - return this.condition.and(condition).test(level, context.withFields(extraFields)); + return this.condition + .and(condition) + .test( + level, + new FakeLoggingContext( + this, + () -> context.withFields(extraFields).getLoggerFields(), + Collections::emptyList)); } @Override @@ -80,11 +98,17 @@ public boolean isEnabled( return fqcn; } + @NotNull + public LoggerContext getLoggerContext() { + return context; + } + @Override public @NotNull CoreLogger withFields( @NotNull Function f, @NotNull FB builder) { - FakeLoggingContext ctx = - new FakeLoggingContext(this, context::getLoggerFields, () -> convert(f.apply(builder))); + FakeLoggerContext ctx = + new FakeLoggerContext( + joinFields(() -> context.getLoggerFields(), () -> convert(f.apply(builder)))); return new FakeCoreLogger(fqcn, ctx, this.condition.and(condition), executor, tlsSupplier); } @@ -122,8 +146,10 @@ private List convert(FieldBuilderResult input) { @Override public void log(@NotNull Level level, @Nullable String message) { - if (isEnabledFor(level) && this.condition.test(level, context)) { - List fields = context.getFields(); + FakeLoggingContext memo = + new FakeLoggingContext(this, context::getLoggerFields, Collections::emptyList); + if (isEnabledFor(level) && this.condition.test(level, memo)) { + List fields = memo.getFields(); System.out.printf("" + message + " level %s fields %s\n", level, fields); } } @@ -131,8 +157,10 @@ public void log(@NotNull Level level, @Nullable String message) { @Override public void log( @NotNull Level level, @NotNull Supplier> extraFields, @Nullable String message) { - if (isEnabledFor(level) && this.condition.test(level, context)) { - List fields = context.withFields(extraFields).getFields(); + FakeLoggingContext ctx = + new FakeLoggingContext(this, context::getLoggerFields, Collections::emptyList); + if (isEnabledFor(level) && this.condition.test(level, ctx)) { + List fields = ctx.withFields(extraFields).getFields(); System.out.printf("" + message + " level %s fields %s\n", level, fields); } } @@ -146,9 +174,9 @@ public void log( List args = convert(f.apply(builder)); if (isEnabledFor(level)) { FakeLoggingContext memo = - new FakeLoggingContext(this, context::getLoggerFields, context::getArgumentFields); + new FakeLoggingContext(this, context::getLoggerFields, () -> f.apply(builder).fields()); if (this.condition.test(level, memo)) { - List fields = context.getFields(); + List fields = memo.getFields(); System.out.printf("" + message + " level %s fields %s args %s\n", level, fields, args); } } @@ -164,10 +192,9 @@ public void log( List args = convert(f.apply(builder)); if (isEnabledFor(level)) { FakeLoggingContext memo = - new FakeLoggingContext( - FakeCoreLogger.this, context::getLoggerFields, context::getArgumentFields); + new FakeLoggingContext(this, context::getLoggerFields, () -> f.apply(builder).fields()); if (this.condition.test(level, memo)) { - List fields = context.getFields(); + List fields = memo.getFields(); System.out.printf("" + message + " level %s fields %s args %s\n", level, fields, args); } } @@ -175,8 +202,10 @@ public void log( @Override public void log(@NotNull Level level, @NotNull Condition condition, @Nullable String message) { - if (isEnabledFor(level) && this.condition.and(condition).test(level, context)) { - List fields = context.getLoggerFields(); + FakeLoggingContext memo = + new FakeLoggingContext(this, context::getLoggerFields, Collections::emptyList); + if (isEnabledFor(level) && this.condition.and(condition).test(level, memo)) { + List fields = memo.getLoggerFields(); System.out.printf("" + message + " level %s fields %s\n", level, fields); } } @@ -187,7 +216,9 @@ public void log( @NotNull Supplier> extraFields, @NotNull Condition condition, @Nullable String message) { - if (isEnabledFor(level) && this.condition.and(condition).test(level, context)) { + FakeLoggingContext memo = + new FakeLoggingContext(this, context::getLoggerFields, Collections::emptyList); + if (isEnabledFor(level) && this.condition.and(condition).test(level, memo)) { List fields = context.withFields(extraFields).getLoggerFields(); System.out.printf("" + message + " level %s fields %s\n", level, fields); } diff --git a/api/src/testFixtures/java/com/tersesystems/echopraxia/fake/FakeLoggerContext.java b/api/src/testFixtures/java/com/tersesystems/echopraxia/fake/FakeLoggerContext.java new file mode 100644 index 00000000..b59b6cc1 --- /dev/null +++ b/api/src/testFixtures/java/com/tersesystems/echopraxia/fake/FakeLoggerContext.java @@ -0,0 +1,32 @@ +package com.tersesystems.echopraxia.fake; + +import static com.tersesystems.echopraxia.spi.Utilities.joinFields; +import static com.tersesystems.echopraxia.spi.Utilities.memoize; + +import com.tersesystems.echopraxia.api.Field; +import com.tersesystems.echopraxia.spi.LoggerContext; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; +import org.jetbrains.annotations.NotNull; + +public class FakeLoggerContext implements LoggerContext { + private final Supplier> fieldsSupplier; + + public static FakeLoggerContext empty() { + return new FakeLoggerContext(Collections::emptyList); + } + + public FakeLoggerContext(Supplier> fieldsSupplier) { + this.fieldsSupplier = memoize(fieldsSupplier); + } + + @Override + public @NotNull List getLoggerFields() { + return fieldsSupplier.get(); + } + + public LoggerContext withFields(Supplier> extraFields) { + return new FakeLoggerContext(joinFields(fieldsSupplier, extraFields)); + } +} diff --git a/jul/src/main/java/com/tersesystems/echopraxia/jul/JULCoreLogger.java b/jul/src/main/java/com/tersesystems/echopraxia/jul/JULCoreLogger.java index ee9b5cad..7c4508af 100644 --- a/jul/src/main/java/com/tersesystems/echopraxia/jul/JULCoreLogger.java +++ b/jul/src/main/java/com/tersesystems/echopraxia/jul/JULCoreLogger.java @@ -3,6 +3,7 @@ import com.tersesystems.echopraxia.api.*; import com.tersesystems.echopraxia.spi.CoreLogger; import com.tersesystems.echopraxia.spi.EchopraxiaService; +import com.tersesystems.echopraxia.spi.LoggerContext; import java.util.Collections; import java.util.List; import java.util.Map; @@ -63,6 +64,11 @@ public String getName() { return logger.getName(); } + @Override + public @NotNull LoggerContext getLoggerContext() { + return context; + } + @Override public @NotNull Condition condition() { return this.condition; diff --git a/jul/src/main/java/com/tersesystems/echopraxia/jul/JULLoggerContext.java b/jul/src/main/java/com/tersesystems/echopraxia/jul/JULLoggerContext.java index 922c07e5..d803c854 100644 --- a/jul/src/main/java/com/tersesystems/echopraxia/jul/JULLoggerContext.java +++ b/jul/src/main/java/com/tersesystems/echopraxia/jul/JULLoggerContext.java @@ -3,12 +3,13 @@ import static com.tersesystems.echopraxia.spi.Utilities.joinFields; import com.tersesystems.echopraxia.api.Field; +import com.tersesystems.echopraxia.spi.LoggerContext; import java.util.Collections; import java.util.List; import java.util.function.Supplier; import org.jetbrains.annotations.NotNull; -public class JULLoggerContext { +public class JULLoggerContext implements LoggerContext { protected final Supplier> fieldsSupplier; private static final JULLoggerContext EMPTY = new JULLoggerContext(); diff --git a/log4j/src/main/java/com/tersesystems/echopraxia/log4j/Log4JCoreLogger.java b/log4j/src/main/java/com/tersesystems/echopraxia/log4j/Log4JCoreLogger.java index 04e36c7c..350d7d02 100644 --- a/log4j/src/main/java/com/tersesystems/echopraxia/log4j/Log4JCoreLogger.java +++ b/log4j/src/main/java/com/tersesystems/echopraxia/log4j/Log4JCoreLogger.java @@ -6,6 +6,7 @@ import com.tersesystems.echopraxia.log4j.layout.EchopraxiaFieldsMessage; import com.tersesystems.echopraxia.spi.CoreLogger; import com.tersesystems.echopraxia.spi.EchopraxiaService; +import com.tersesystems.echopraxia.spi.LoggerContext; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -69,6 +70,11 @@ public String getName() { return logger.getName(); } + @Override + public @NotNull LoggerContext getLoggerContext() { + return context; + } + @Override public @NotNull Condition condition() { return this.condition; @@ -676,7 +682,7 @@ public String toString() { return "Log4JCoreLogger[" + logger.getName() + "]"; } - protected static class Context { + protected static class Context implements LoggerContext { protected final Supplier> fieldsSupplier; protected final Marker marker; diff --git a/log4j/src/test/java/com/tersesystems/echopraxia/log4j/ContextTest.java b/log4j/src/test/java/com/tersesystems/echopraxia/log4j/ContextTest.java index 16be96fa..eefef5e9 100644 --- a/log4j/src/test/java/com/tersesystems/echopraxia/log4j/ContextTest.java +++ b/log4j/src/test/java/com/tersesystems/echopraxia/log4j/ContextTest.java @@ -23,6 +23,21 @@ void clearThreadContext() { ThreadContext.clearAll(); } + @Test + void testGetLoggerContext() { + Log4JCoreLogger core = + (Log4JCoreLogger) CoreLoggerFactory.getLogger(Logger.class.getName(), ContextTest.class); + var logger = + LoggerFactory.getLogger(core, FieldBuilder.instance()) + .withFields(fb -> fb.string("herp", "derp")); + var coreWithFields = logger.core(); + var fields = coreWithFields.getLoggerContext().getLoggerFields(); + + Field field = fields.get(0); + assertThat(field.name()).isEqualTo("herp"); + assertThat(field.value().asString().raw()).isEqualTo("derp"); + } + @Test void testMarkers() { Marker securityMarker = MarkerManager.getMarker("SECURITY"); diff --git a/logback/src/main/java/com/tersesystems/echopraxia/logback/LogbackLoggerContext.java b/logback/src/main/java/com/tersesystems/echopraxia/logback/LogbackLoggerContext.java index 4fd1033d..80033efd 100644 --- a/logback/src/main/java/com/tersesystems/echopraxia/logback/LogbackLoggerContext.java +++ b/logback/src/main/java/com/tersesystems/echopraxia/logback/LogbackLoggerContext.java @@ -1,15 +1,13 @@ package com.tersesystems.echopraxia.logback; -import com.tersesystems.echopraxia.api.Field; +import com.tersesystems.echopraxia.spi.LoggerContext; import java.util.List; import org.jetbrains.annotations.NotNull; import org.slf4j.Marker; /** The logback context associated with the logger across multiple logging events. */ -public interface LogbackLoggerContext { +public interface LogbackLoggerContext extends LoggerContext { @NotNull - List getLoggerFields(); - List getMarkers(); } diff --git a/logstash/src/main/java/com/tersesystems/echopraxia/logstash/LogstashCoreLogger.java b/logstash/src/main/java/com/tersesystems/echopraxia/logstash/LogstashCoreLogger.java index e2bb5d2c..0b23cb79 100644 --- a/logstash/src/main/java/com/tersesystems/echopraxia/logstash/LogstashCoreLogger.java +++ b/logstash/src/main/java/com/tersesystems/echopraxia/logstash/LogstashCoreLogger.java @@ -108,6 +108,12 @@ public String getName() { return fqcn; } + @Override + @NotNull + public com.tersesystems.echopraxia.spi.LoggerContext getLoggerContext() { + return context; + } + // Logstash specific, not part of CoreLogger API public CoreLogger withMarkers(Marker... markers) { final LogstashMarkerContext contextWithMarkers = diff --git a/logstash/src/test/java/com/tersesystems/echopraxia/logstash/ContextTest.java b/logstash/src/test/java/com/tersesystems/echopraxia/logstash/ContextTest.java index d201c246..60d8a4b3 100644 --- a/logstash/src/test/java/com/tersesystems/echopraxia/logstash/ContextTest.java +++ b/logstash/src/test/java/com/tersesystems/echopraxia/logstash/ContextTest.java @@ -13,6 +13,8 @@ import com.tersesystems.echopraxia.api.Field; import com.tersesystems.echopraxia.api.FieldBuilder; import com.tersesystems.echopraxia.api.Value; +import com.tersesystems.echopraxia.spi.CoreLogger; +import com.tersesystems.echopraxia.spi.CoreLoggerFactory; import java.io.IOException; import java.io.StringWriter; import java.util.*; @@ -35,6 +37,20 @@ void clearMDC() { MDC.clear(); } + @Test + void testGetLoggerContext() { + CoreLogger core = CoreLoggerFactory.getLogger(Logger.class.getName(), ContextTest.class); + var logger = + LoggerFactory.getLogger(core, FieldBuilder.instance()) + .withFields(fb -> fb.string("herp", "derp")); + var coreWithFields = logger.core(); + var fields = coreWithFields.getLoggerContext().getLoggerFields(); + + Field field = fields.get(0); + assertThat(field.name()).isEqualTo("herp"); + assertThat(field.value().asString().raw()).isEqualTo("derp"); + } + @Test void testMarkers() {