From e40c69a0e6a8d0c2daa1f000783908584bc5dfda Mon Sep 17 00:00:00 2001 From: q3769 Date: Sat, 7 Oct 2023 20:15:24 -0500 Subject: [PATCH] + timestamp goes before message in json element + internal rename --- README.md | 14 +- pom.xml | 2 +- .../{ClassPattern.java => ClassElement.java} | 11 +- .../{PatternType.java => ElementType.java} | 121 +++++++++--------- ...eNamePattern.java => FileNameElement.java} | 9 +- .../{JsonPattern.java => JsonElement.java} | 17 +-- .../{LevelPattern.java => LevelElement.java} | 11 +- ...berPattern.java => LineNumberElement.java} | 9 +- .../engine/service/pattern/LogPattern.java | 40 ++++-- ...n.java => MessageAndExceptionElement.java} | 9 +- ...{MethodPattern.java => MethodElement.java} | 9 +- ...{PatternGroup.java => PatternElement.java} | 40 ++---- ...ern.java => SystemEnvironmentElement.java} | 11 +- ...attern.java => SystemPropertyElement.java} | 11 +- ...{ThreadPattern.java => ThreadElement.java} | 11 +- ...tampPattern.java => TimestampElement.java} | 11 +- ...batimPattern.java => VerbatimElement.java} | 12 +- .../service/writer/StandardStreamWriter.java | 11 +- .../service/pattern/ElementTypeTest.java | 18 +++ .../service/pattern/JsonPatternTest.java | 10 +- .../MessageAndExceptionPatternTest.java | 11 +- .../service/pattern/PatternGroupTest.java | 10 +- .../service/pattern/VerbatimPatternTest.java | 10 +- 23 files changed, 194 insertions(+), 224 deletions(-) rename src/main/java/elf4j/engine/service/pattern/{ClassPattern.java => ClassElement.java} (88%) rename src/main/java/elf4j/engine/service/pattern/{PatternType.java => ElementType.java} (50%) rename src/main/java/elf4j/engine/service/pattern/{FileNamePattern.java => FileNameElement.java} (85%) rename src/main/java/elf4j/engine/service/pattern/{JsonPattern.java => JsonElement.java} (92%) rename src/main/java/elf4j/engine/service/pattern/{LevelPattern.java => LevelElement.java} (85%) rename src/main/java/elf4j/engine/service/pattern/{LineNumberPattern.java => LineNumberElement.java} (84%) rename src/main/java/elf4j/engine/service/pattern/{MessageAndExceptionPattern.java => MessageAndExceptionElement.java} (85%) rename src/main/java/elf4j/engine/service/pattern/{MethodPattern.java => MethodElement.java} (85%) rename src/main/java/elf4j/engine/service/pattern/{PatternGroup.java => PatternElement.java} (57%) rename src/main/java/elf4j/engine/service/pattern/{SystemEnvironmentPattern.java => SystemEnvironmentElement.java} (82%) rename src/main/java/elf4j/engine/service/pattern/{SystemPropertyPattern.java => SystemPropertyElement.java} (82%) rename src/main/java/elf4j/engine/service/pattern/{ThreadPattern.java => ThreadElement.java} (84%) rename src/main/java/elf4j/engine/service/pattern/{TimestampPattern.java => TimestampElement.java} (82%) rename src/main/java/elf4j/engine/service/pattern/{VerbatimPattern.java => VerbatimElement.java} (77%) create mode 100644 src/test/java/elf4j/engine/service/pattern/ElementTypeTest.java diff --git a/README.md b/README.md index 724ff94..e11650e 100644 --- a/README.md +++ b/README.md @@ -119,13 +119,13 @@ A stand-alone log engine in the meantime, it is designed to be adaptable for ser The output becomes: ``` - {"message":"Hello, world!","timestamp":"2023-10-04T09:06:08.2921769-05:00","level":"INFO","callerClass":"elf4j.engine.Main"} - {"message":"It's a beautiful day","timestamp":"2023-10-04T09:06:08.2951796-05:00","level":"TRACE","callerClass":"elf4j.engine.Main"} - {"message":"... no matter on what level you say it","timestamp":"2023-10-04T09:06:08.2951796-05:00","level":"INFO","callerClass":"elf4j.engine.Main"} - {"message":"Houston, we do not have a problem but let's do a drill","timestamp":"2023-10-04T09:06:08.2951796-05:00","level":"WARN","callerClass":"elf4j.engine.Main"} - {"message":"","timestamp":"2023-10-04T09:06:08.2951796-05:00","level":"ERROR","callerClass":"elf4j.engine.Main","exception":"java.lang.Exception: This is a drill\r\n\tat elf4j.engine.Main.main(Main.java:43)\r\n"} - {"message":"i.e. Throwable always comes first, then the following optional message and arguments work as usual","timestamp":"2023-10-04T09:06:08.2951796-05:00","level":"INFO","callerClass":"elf4j.engine.Main","exception":"java.lang.Exception: This is a drill\r\n\tat elf4j.engine.Main.main(Main.java:43)\r\n"} - {"message":"Not a practical example but now the severity level is DEBUG","timestamp":"2023-10-04T09:06:08.2951796-05:00","level":"DEBUG","callerClass":"elf4j.engine.Main"} + {"timestamp":"2023-10-07T20:11:44.0345848-05:00","message":"Hello, world!","level":"INFO","callerClass":"elf4j.engine.Main"} + {"timestamp":"2023-10-07T20:11:44.0375856-05:00","message":"It's a beautiful day","level":"TRACE","callerClass":"elf4j.engine.Main"} + {"timestamp":"2023-10-07T20:11:44.038585-05:00","message":"... no matter on what level you say it","level":"INFO","callerClass":"elf4j.engine.Main"} + {"timestamp":"2023-10-07T20:11:44.038585-05:00","message":"Houston, we do not have a problem but let's do a drill","level":"WARN","callerClass":"elf4j.engine.Main"} + {"timestamp":"2023-10-07T20:11:44.038585-05:00","message":"","level":"ERROR","callerClass":"elf4j.engine.Main","exception":"java.lang.Exception: This is a drill\r\n\tat elf4j.engine.Main.main(Main.java:43)\r\n"} + {"timestamp":"2023-10-07T20:11:44.038585-05:00","message":"i.e. Throwable always comes first, then the following optional message and arguments work as usual","level":"INFO","callerClass":"elf4j.engine.Main","exception":"java.lang.Exception: This is a drill\r\n\tat elf4j.engine.Main.main(Main.java:43)\r\n"} + {"timestamp":"2023-10-07T20:11:44.038585-05:00","message":"Not a practical example but now the severity level is DEBUG","level":"DEBUG","callerClass":"elf4j.engine.Main"} ``` The JSON pattern can be configured to pretty-print format, and/or mixed with other patterns. diff --git a/pom.xml b/pom.xml index e601299..57c78ad 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ io.github.elf4j elf4j-engine - 13.0.1 + 13.0.2 jar elf4j-engine A stand-alone Java log engine implementing the ELF4J (Easy Logging Facade for Java) API diff --git a/src/main/java/elf4j/engine/service/pattern/ClassPattern.java b/src/main/java/elf4j/engine/service/pattern/ClassElement.java similarity index 88% rename from src/main/java/elf4j/engine/service/pattern/ClassPattern.java rename to src/main/java/elf4j/engine/service/pattern/ClassElement.java index 8033f64..5590da1 100644 --- a/src/main/java/elf4j/engine/service/pattern/ClassPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/ClassElement.java @@ -35,7 +35,7 @@ * */ @Value -class ClassPattern implements LogPattern { +class ClassElement implements PatternElement { private static final DisplayOption DEFAULT_DISPLAY_OPTION = DisplayOption.SIMPLE; @NonNull DisplayOption classDisplayOption; @@ -45,18 +45,15 @@ class ClassPattern implements LogPattern { * @return converted patternSegment object */ @Nonnull - public static ClassPattern from(@NonNull String patternSegment) { - if (!PatternType.CLASS.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new ClassPattern(PatternType.getPatternDisplayOption(patternSegment) + public static ClassElement from(@NonNull String patternSegment) { + return new ClassElement(ElementType.getPatternDisplayOption(patternSegment) .map(displayOption -> DisplayOption.valueOf(displayOption.toUpperCase())) .orElse(DEFAULT_DISPLAY_OPTION)); } /** * @return false assuming the logger's owner class is the same as the caller class. Therefore, unlike - * the {@link MethodPattern}, it does not take a stack trace walk to locate the caller class - the owner + * the {@link MethodElement}, it does not take a stack trace walk to locate the caller class - the owner * class is taken instead. */ @Override diff --git a/src/main/java/elf4j/engine/service/pattern/PatternType.java b/src/main/java/elf4j/engine/service/pattern/ElementType.java similarity index 50% rename from src/main/java/elf4j/engine/service/pattern/PatternType.java rename to src/main/java/elf4j/engine/service/pattern/ElementType.java index 5074a12..85dd0b6 100644 --- a/src/main/java/elf4j/engine/service/pattern/PatternType.java +++ b/src/main/java/elf4j/engine/service/pattern/ElementType.java @@ -35,14 +35,14 @@ /** * */ -enum PatternType { +enum ElementType { /** * */ TIMESTAMP { @Override - LogPattern translate(String patternSegment) { - return TimestampPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return TimestampElement.from(patternElement); } }, /** @@ -50,8 +50,8 @@ LogPattern translate(String patternSegment) { */ LEVEL { @Override - LogPattern translate(String patternSegment) { - return LevelPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return LevelElement.from(patternElement); } }, /** @@ -59,8 +59,8 @@ LogPattern translate(String patternSegment) { */ THREAD { @Override - LogPattern translate(String patternSegment) { - return ThreadPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return ThreadElement.from(patternElement); } }, /** @@ -68,8 +68,8 @@ LogPattern translate(String patternSegment) { */ CLASS { @Override - LogPattern translate(String patternSegment) { - return ClassPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return ClassElement.from(patternElement); } }, /** @@ -77,20 +77,20 @@ LogPattern translate(String patternSegment) { */ METHOD { @Override - LogPattern translate(String patternSegment) { - return MethodPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return MethodElement.from(patternElement); } }, FILENAME { @Override - LogPattern translate(String patternSegment) { - return FileNamePattern.from(patternSegment); + PatternElement parse(String patternElement) { + return FileNameElement.from(patternElement); } }, LINENUMBER { @Override - LogPattern translate(String patternSegment) { - return LineNumberPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return LineNumberElement.from(patternElement); } }, @@ -99,8 +99,8 @@ LogPattern translate(String patternSegment) { */ MESSAGE { @Override - LogPattern translate(String patternSegment) { - return MessageAndExceptionPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return MessageAndExceptionElement.from(patternElement); } }, /** @@ -108,20 +108,20 @@ LogPattern translate(String patternSegment) { */ JSON { @Override - LogPattern translate(String patternSegment) { - return JsonPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return JsonElement.from(patternElement); } }, SYSPROP { @Override - LogPattern translate(String patternSegment) { - return SystemPropertyPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return SystemPropertyElement.from(patternElement); } }, SYSENV { @Override - LogPattern translate(String patternSegment) { - return SystemEnvironmentPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return SystemEnvironmentElement.from(patternElement); } }, /** @@ -129,89 +129,94 @@ LogPattern translate(String patternSegment) { */ VERBATIM { @Override - LogPattern translate(String patternSegment) { - return VerbatimPattern.from(patternSegment); + PatternElement parse(String patternElement) { + return VerbatimElement.from(patternElement); } }; - private static final EnumSet PATTERN_TYPES = EnumSet.allOf(PatternType.class); - private static final EnumSet PREDEFINED_PATTERN_TYPES = EnumSet.complementOf(EnumSet.of(VERBATIM)); + private static final EnumSet PREDEFINED_TYPES = EnumSet.complementOf(EnumSet.of(VERBATIM)); /** - * @param patternSegment - * entire text of an individual pattern segment, including pattern segment name and possibly options - * @return the option portion of the pattern segment text if present; otherwise, empty Optional + * @param patternElement + * entire text of an individual pattern element, including pattern element name and possibly options + * @return the option portion of the pattern element text if present; otherwise, empty Optional */ - static Optional getPatternDisplayOption(@NonNull String patternSegment) { - String[] elements = patternSegment.split(":", 2); + static Optional getPatternDisplayOption(@NonNull String patternElement) { + String[] elements = patternElement.split(":", 2); return elements.length == 1 ? Optional.empty() : Optional.of(elements[1].trim()); } /** * @param pattern - * entire layout pattern text of a writer, including one or more individual pattern segments. Predefined - * pattern segment texts in curly braces - e.g. {timestamp}, {level}, or {json} - will be parsed into - * pattern segment objects who extract and render specific log data to form the final log message. Undefined + * entire layout pattern text of a writer, including one or more individual pattern elements. Predefined + * pattern element texts in curly braces - e.g. {timestamp}, {level}, or {json} - will be parsed into + * pattern element objects who extract and render specific log data to form the final log message. Undefined * pattern texts, in or outside curly braces, are to be rendered verbatim in the final log message. * @return ordered list of individual patterns forming the entire layout pattern of the writer */ - static @NonNull List parsePatterns(@NonNull String pattern) { + static @NonNull List parsePattern(@NonNull String pattern) { if (pattern.trim().isEmpty()) { throw new IllegalArgumentException("Unexpected blank pattern"); } - List logPatterns = new ArrayList<>(); + List patternElements = new ArrayList<>(); final int length = pattern.length(); int i = 0; while (i < length) { - String segment; + String element; int j; if (pattern.charAt(i) == '{') { j = pattern.indexOf('}', i); if (j != -1) { - segment = pattern.substring(i + 1, j); + element = pattern.substring(i + 1, j); i = j + 1; } else { - segment = pattern.substring(i); + element = pattern.substring(i); i = length; } + patternElements.add(parsePredefinedPatternELement(element)); } else { j = pattern.indexOf('{', i); if (j != -1) { - segment = pattern.substring(i, j); + element = pattern.substring(i, j); i = j; } else { - segment = pattern.substring(i); + element = pattern.substring(i); i = length; } + patternElements.add(VERBATIM.parse(element)); } - logPatterns.add(parsePattern(segment)); } - return logPatterns; + return patternElements; } - private static LogPattern parsePattern(String patternSegment) { - return PATTERN_TYPES.stream() - .filter(type -> type.isTargetTypeOf(patternSegment)) + private static String getPatternElementName(String patternElement) { + return patternElement.split(":", 2)[0].trim(); + } + + private static PatternElement parsePredefinedPatternELement(String predefinedPatternElement) { + return PREDEFINED_TYPES.stream() + .filter(type -> type.isTargetTypeOf(predefinedPatternElement)) .findFirst() - .orElseThrow(() -> new IllegalArgumentException("pattern segment: '" + patternSegment + "'")) - .translate(patternSegment); + .orElseThrow(() -> new IllegalArgumentException( + "Predefined pattern element: '" + predefinedPatternElement + "'")) + .parse(predefinedPatternElement); } /** - * @param patternSegment + * @param patternElement * text to translate - * @return pattern segment object of the specified text + * @return pattern element object of the specified text */ - abstract LogPattern translate(String patternSegment); + abstract PatternElement parse(String patternElement); /** - * @param patternSegment - * text configuration of an individual pattern segment - * @return true if this pattern segment type is the target type of the specified pattern segment text + * @param patternElement + * text configuration of an individual pattern element + * @return true if this pattern element type is the target type of the specified pattern element text */ - boolean isTargetTypeOf(String patternSegment) { + private boolean isTargetTypeOf(String patternElement) { if (this == VERBATIM) { - return PREDEFINED_PATTERN_TYPES.stream().noneMatch(type -> type.isTargetTypeOf(patternSegment)); + return PREDEFINED_TYPES.stream().noneMatch(type -> type.isTargetTypeOf(patternElement)); } - return name().equalsIgnoreCase(patternSegment.split(":", 2)[0].trim()); + return name().equalsIgnoreCase(getPatternElementName(patternElement)); } } diff --git a/src/main/java/elf4j/engine/service/pattern/FileNamePattern.java b/src/main/java/elf4j/engine/service/pattern/FileNameElement.java similarity index 85% rename from src/main/java/elf4j/engine/service/pattern/FileNamePattern.java rename to src/main/java/elf4j/engine/service/pattern/FileNameElement.java index b2b22aa..2d343f3 100644 --- a/src/main/java/elf4j/engine/service/pattern/FileNamePattern.java +++ b/src/main/java/elf4j/engine/service/pattern/FileNameElement.java @@ -36,18 +36,15 @@ * */ @Value -class FileNamePattern implements LogPattern { +class FileNameElement implements PatternElement { /** * @param patternSegment * text segment to convert * @return converted patternSegment object */ @Nonnull - public static FileNamePattern from(String patternSegment) { - if (!PatternType.FILENAME.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new FileNamePattern(); + public static FileNameElement from(String patternSegment) { + return new FileNameElement(); } @Override diff --git a/src/main/java/elf4j/engine/service/pattern/JsonPattern.java b/src/main/java/elf4j/engine/service/pattern/JsonElement.java similarity index 92% rename from src/main/java/elf4j/engine/service/pattern/JsonPattern.java rename to src/main/java/elf4j/engine/service/pattern/JsonElement.java index 167ff3c..f944c9a 100644 --- a/src/main/java/elf4j/engine/service/pattern/JsonPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/JsonElement.java @@ -54,7 +54,7 @@ */ @Value @Builder -class JsonPattern implements LogPattern { +class JsonElement implements PatternElement { private static final String UTF_8 = StandardCharsets.UTF_8.toString(); private static final int JSON_BYTES_INIT_SIZE = 1024; private static final String CALLER_DETAIL = "caller-detail"; @@ -73,20 +73,17 @@ class JsonPattern implements LogPattern { * to convert * @return converted patternSegment object */ - public static JsonPattern from(@NonNull String patternSegment) { - if (!PatternType.JSON.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - Optional displayOption = PatternType.getPatternDisplayOption(patternSegment); + public static JsonElement from(@NonNull String patternSegment) { + Optional displayOption = ElementType.getPatternDisplayOption(patternSegment); if (!displayOption.isPresent()) { - return JsonPattern.builder().build(); + return JsonElement.builder().build(); } Set options = Arrays.stream(displayOption.get().split(",")).map(String::trim).collect(Collectors.toSet()); if (!DISPLAY_OPTIONS.containsAll(options)) { throw new IllegalArgumentException("Invalid JSON display option inside: " + options); } - return JsonPattern.builder() + return JsonElement.builder() .includeCallerThread(options.contains(CALLER_THREAD)) .includeCallerDetail(options.contains(CALLER_DETAIL)) .prettyPrint(options.contains(PRETTY)) @@ -114,15 +111,15 @@ public void render(LogEvent logEvent, @NonNull StringBuilder target) { @Builder @CompiledJson static class JsonLogEntry { - CharSequence message; OffsetDateTime timestamp; + CharSequence message; String level; String callerClass; LogEvent.ThreadValue callerThread; LogEvent.StackFrameValue callerDetail; CharSequence exception; - static JsonLogEntry from(@NonNull LogEvent logEvent, @NonNull JsonPattern jsonPattern) { + static JsonLogEntry from(@NonNull LogEvent logEvent, @NonNull JsonElement jsonPattern) { return JsonLogEntry.builder() .timestamp(OffsetDateTime.ofInstant(logEvent.getTimestamp(), ZoneId.systemDefault())) .callerClass(jsonPattern.includeCallerDetail ? null : logEvent.getCallerClassName()) diff --git a/src/main/java/elf4j/engine/service/pattern/LevelPattern.java b/src/main/java/elf4j/engine/service/pattern/LevelElement.java similarity index 85% rename from src/main/java/elf4j/engine/service/pattern/LevelPattern.java rename to src/main/java/elf4j/engine/service/pattern/LevelElement.java index 773c244..c86d7c7 100644 --- a/src/main/java/elf4j/engine/service/pattern/LevelPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/LevelElement.java @@ -35,11 +35,11 @@ * */ @Value -class LevelPattern implements LogPattern { +class LevelElement implements PatternElement { private static final int UNSPECIFIED = -1; int displayLength; - private LevelPattern(int displayLength) { + private LevelElement(int displayLength) { this.displayLength = displayLength; } @@ -49,11 +49,8 @@ private LevelPattern(int displayLength) { * @return converted patternSegment object */ @Nonnull - public static LevelPattern from(@NonNull String patternSegment) { - if (!PatternType.LEVEL.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new LevelPattern(PatternType.getPatternDisplayOption(patternSegment) + public static LevelElement from(@NonNull String patternSegment) { + return new LevelElement(ElementType.getPatternDisplayOption(patternSegment) .map(Integer::parseInt) .orElse(UNSPECIFIED)); } diff --git a/src/main/java/elf4j/engine/service/pattern/LineNumberPattern.java b/src/main/java/elf4j/engine/service/pattern/LineNumberElement.java similarity index 84% rename from src/main/java/elf4j/engine/service/pattern/LineNumberPattern.java rename to src/main/java/elf4j/engine/service/pattern/LineNumberElement.java index c8d43d8..e007505 100644 --- a/src/main/java/elf4j/engine/service/pattern/LineNumberPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/LineNumberElement.java @@ -36,18 +36,15 @@ * */ @Value -class LineNumberPattern implements LogPattern { +class LineNumberElement implements PatternElement { /** * @param patternSegment * text segment to convert * @return converted patternSegment object */ @Nonnull - public static LineNumberPattern from(String patternSegment) { - if (!PatternType.LINENUMBER.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new LineNumberPattern(); + public static LineNumberElement from(String patternSegment) { + return new LineNumberElement(); } @Override diff --git a/src/main/java/elf4j/engine/service/pattern/LogPattern.java b/src/main/java/elf4j/engine/service/pattern/LogPattern.java index a587930..5229d2c 100644 --- a/src/main/java/elf4j/engine/service/pattern/LogPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/LogPattern.java @@ -26,24 +26,38 @@ package elf4j.engine.service.pattern; import elf4j.engine.service.LogEvent; -import elf4j.engine.service.writer.PerformanceSensitive; +import lombok.NonNull; +import lombok.Value; -import javax.annotation.concurrent.ThreadSafe; +import javax.annotation.Nonnull; +import java.util.List; /** - * Implementation should be thread-safe + * Composite of individual patterns, intended to form the entire log layout */ -@ThreadSafe -public interface LogPattern extends PerformanceSensitive { +@Value +public class LogPattern implements PatternElement { + List patternElements; /** - * Extracts the content of particular interest to this log pattern instance from the specified log event, and - * appends the result to the specified target aggregator of the final log message - * - * @param logEvent - * entire log content data source to render - * @param target - * logging text aggregator of the final log message + * @param pattern + * entire layout pattern text from configuration + * @return composite pattern object for the entire final log message output layout */ - void render(LogEvent logEvent, StringBuilder target); + @Nonnull + public static LogPattern from(@NonNull String pattern) { + return new LogPattern(ElementType.parsePattern(pattern)); + } + + @Override + public boolean includeCallerDetail() { + return patternElements.stream().anyMatch(PatternElement::includeCallerDetail); + } + + @Override + public void render(LogEvent logEvent, StringBuilder target) { + for (PatternElement pattern : patternElements) { + pattern.render(logEvent, target); + } + } } diff --git a/src/main/java/elf4j/engine/service/pattern/MessageAndExceptionPattern.java b/src/main/java/elf4j/engine/service/pattern/MessageAndExceptionElement.java similarity index 85% rename from src/main/java/elf4j/engine/service/pattern/MessageAndExceptionPattern.java rename to src/main/java/elf4j/engine/service/pattern/MessageAndExceptionElement.java index c402d03..dbd301a 100644 --- a/src/main/java/elf4j/engine/service/pattern/MessageAndExceptionPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/MessageAndExceptionElement.java @@ -36,18 +36,15 @@ * */ @Value -class MessageAndExceptionPattern implements LogPattern { +class MessageAndExceptionElement implements PatternElement { /** * @param patternSegment * text segment to convert * @return converted patternSegment object */ @Nonnull - public static MessageAndExceptionPattern from(String patternSegment) { - if (!PatternType.MESSAGE.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment text: " + patternSegment); - } - return new MessageAndExceptionPattern(); + public static MessageAndExceptionElement from(String patternSegment) { + return new MessageAndExceptionElement(); } @Override diff --git a/src/main/java/elf4j/engine/service/pattern/MethodPattern.java b/src/main/java/elf4j/engine/service/pattern/MethodElement.java similarity index 85% rename from src/main/java/elf4j/engine/service/pattern/MethodPattern.java rename to src/main/java/elf4j/engine/service/pattern/MethodElement.java index 21125c4..70aa8c9 100644 --- a/src/main/java/elf4j/engine/service/pattern/MethodPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/MethodElement.java @@ -36,18 +36,15 @@ * */ @Value -class MethodPattern implements LogPattern { +class MethodElement implements PatternElement { /** * @param patternSegment * text segment to convert * @return converted patternSegment object */ @Nonnull - public static MethodPattern from(String patternSegment) { - if (!PatternType.METHOD.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new MethodPattern(); + public static MethodElement from(String patternSegment) { + return new MethodElement(); } @Override diff --git a/src/main/java/elf4j/engine/service/pattern/PatternGroup.java b/src/main/java/elf4j/engine/service/pattern/PatternElement.java similarity index 57% rename from src/main/java/elf4j/engine/service/pattern/PatternGroup.java rename to src/main/java/elf4j/engine/service/pattern/PatternElement.java index 156102b..803a708 100644 --- a/src/main/java/elf4j/engine/service/pattern/PatternGroup.java +++ b/src/main/java/elf4j/engine/service/pattern/PatternElement.java @@ -26,38 +26,24 @@ package elf4j.engine.service.pattern; import elf4j.engine.service.LogEvent; -import lombok.NonNull; -import lombok.Value; +import elf4j.engine.service.writer.PerformanceSensitive; -import javax.annotation.Nonnull; -import java.util.List; +import javax.annotation.concurrent.ThreadSafe; /** - * Composite of individual patterns forming the entire layout pattern + * Implementation should be thread-safe */ -@Value -public class PatternGroup implements LogPattern { - List patterns; +@ThreadSafe +public interface PatternElement extends PerformanceSensitive { /** - * @param pattern - * entire layout pattern text from configuration - * @return composite pattern object for the entire final log message output layout + * Extracts the content of particular interest to this log pattern instance from the specified log event, and + * appends the result to the specified target aggregator of the final log message + * + * @param logEvent + * entire log content data source to render + * @param target + * logging text aggregator of the final log message */ - @Nonnull - public static PatternGroup from(@NonNull String pattern) { - return new PatternGroup(PatternType.parsePatterns(pattern)); - } - - @Override - public boolean includeCallerDetail() { - return patterns.stream().anyMatch(LogPattern::includeCallerDetail); - } - - @Override - public void render(LogEvent logEvent, StringBuilder target) { - for (LogPattern pattern : patterns) { - pattern.render(logEvent, target); - } - } + void render(LogEvent logEvent, StringBuilder target); } diff --git a/src/main/java/elf4j/engine/service/pattern/SystemEnvironmentPattern.java b/src/main/java/elf4j/engine/service/pattern/SystemEnvironmentElement.java similarity index 82% rename from src/main/java/elf4j/engine/service/pattern/SystemEnvironmentPattern.java rename to src/main/java/elf4j/engine/service/pattern/SystemEnvironmentElement.java index e8013e8..11dfaee 100644 --- a/src/main/java/elf4j/engine/service/pattern/SystemEnvironmentPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/SystemEnvironmentElement.java @@ -35,11 +35,11 @@ * */ @Value -class SystemEnvironmentPattern implements LogPattern { +class SystemEnvironmentElement implements PatternElement { String key; String value; - private SystemEnvironmentPattern(String key) { + private SystemEnvironmentElement(String key) { this.key = key; this.value = System.getenv(key); } @@ -50,11 +50,8 @@ private SystemEnvironmentPattern(String key) { * @return converted patternSegment object */ @Nonnull - public static SystemEnvironmentPattern from(String patternSegment) { - if (!PatternType.SYSENV.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new SystemEnvironmentPattern(PatternType.getPatternDisplayOption(patternSegment) + public static SystemEnvironmentElement from(String patternSegment) { + return new SystemEnvironmentElement(ElementType.getPatternDisplayOption(patternSegment) .orElseThrow(NoSuchElementException::new)); } diff --git a/src/main/java/elf4j/engine/service/pattern/SystemPropertyPattern.java b/src/main/java/elf4j/engine/service/pattern/SystemPropertyElement.java similarity index 82% rename from src/main/java/elf4j/engine/service/pattern/SystemPropertyPattern.java rename to src/main/java/elf4j/engine/service/pattern/SystemPropertyElement.java index d64c838..60a8142 100644 --- a/src/main/java/elf4j/engine/service/pattern/SystemPropertyPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/SystemPropertyElement.java @@ -35,10 +35,10 @@ * */ @Value -class SystemPropertyPattern implements LogPattern { +class SystemPropertyElement implements PatternElement { String key; - private SystemPropertyPattern(String key) { + private SystemPropertyElement(String key) { this.key = key; } @@ -48,11 +48,8 @@ private SystemPropertyPattern(String key) { * @return converted patternSegment object */ @Nonnull - public static SystemPropertyPattern from(String patternSegment) { - if (!PatternType.SYSPROP.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new SystemPropertyPattern(PatternType.getPatternDisplayOption(patternSegment) + public static SystemPropertyElement from(String patternSegment) { + return new SystemPropertyElement(ElementType.getPatternDisplayOption(patternSegment) .orElseThrow(NoSuchElementException::new)); } diff --git a/src/main/java/elf4j/engine/service/pattern/ThreadPattern.java b/src/main/java/elf4j/engine/service/pattern/ThreadElement.java similarity index 84% rename from src/main/java/elf4j/engine/service/pattern/ThreadPattern.java rename to src/main/java/elf4j/engine/service/pattern/ThreadElement.java index d135181..c73f099 100644 --- a/src/main/java/elf4j/engine/service/pattern/ThreadPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/ThreadElement.java @@ -36,8 +36,8 @@ * */ @Value -class ThreadPattern implements LogPattern { - @NonNull ThreadPattern.DisplayOption threadDisplayOption; +class ThreadElement implements PatternElement { + @NonNull ThreadElement.DisplayOption threadDisplayOption; /** * @param patternSegment @@ -45,11 +45,8 @@ class ThreadPattern implements LogPattern { * @return the thread pattern segment converted from the specified text */ @Nonnull - public static ThreadPattern from(@NonNull String patternSegment) { - if (!PatternType.THREAD.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new ThreadPattern(PatternType.getPatternDisplayOption(patternSegment) + public static ThreadElement from(@NonNull String patternSegment) { + return new ThreadElement(ElementType.getPatternDisplayOption(patternSegment) .map(displayOption -> DisplayOption.valueOf(displayOption.toUpperCase())) .orElse(DisplayOption.NAME)); } diff --git a/src/main/java/elf4j/engine/service/pattern/TimestampPattern.java b/src/main/java/elf4j/engine/service/pattern/TimestampElement.java similarity index 82% rename from src/main/java/elf4j/engine/service/pattern/TimestampPattern.java rename to src/main/java/elf4j/engine/service/pattern/TimestampElement.java index b3b6d64..27d6e1a 100644 --- a/src/main/java/elf4j/engine/service/pattern/TimestampPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/TimestampElement.java @@ -38,7 +38,7 @@ * */ @Value -class TimestampPattern implements LogPattern { +class TimestampElement implements PatternElement { private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; private static final ZoneId DISPLAY_TIME_ZONE = ZoneId.systemDefault(); DateTimeFormatter dateTimeFormatter; @@ -49,17 +49,14 @@ class TimestampPattern implements LogPattern { * @return converted pattern segment object */ @Nonnull - public static TimestampPattern from(@NonNull String patternSegment) { - if (!PatternType.TIMESTAMP.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException("patternSegment: " + patternSegment); - } - return new TimestampPattern(DateTimeFormatter.ofPattern(PatternType.getPatternDisplayOption(patternSegment) + public static TimestampElement from(@NonNull String patternSegment) { + return new TimestampElement(DateTimeFormatter.ofPattern(ElementType.getPatternDisplayOption(patternSegment) .orElse(DEFAULT_DATETIME_PATTERN)).withZone(DISPLAY_TIME_ZONE)); } @Override public String toString() { - return "TimestampPattern{" + "sample=" + dateTimeFormatter.format(Instant.now()) + '}'; + return "TimestampElement{" + "sample=" + dateTimeFormatter.format(Instant.now()) + '}'; } @Override diff --git a/src/main/java/elf4j/engine/service/pattern/VerbatimPattern.java b/src/main/java/elf4j/engine/service/pattern/VerbatimElement.java similarity index 77% rename from src/main/java/elf4j/engine/service/pattern/VerbatimPattern.java rename to src/main/java/elf4j/engine/service/pattern/VerbatimElement.java index fe06bd9..a06ff2c 100644 --- a/src/main/java/elf4j/engine/service/pattern/VerbatimPattern.java +++ b/src/main/java/elf4j/engine/service/pattern/VerbatimElement.java @@ -35,7 +35,7 @@ * */ @Value -class VerbatimPattern implements LogPattern { +class VerbatimElement implements PatternElement { @NonNull String text; /** @@ -44,14 +44,8 @@ class VerbatimPattern implements LogPattern { * @return converted pattern segment object */ @Nonnull - public static VerbatimPattern from(String patternSegment) { - if (!PatternType.VERBATIM.isTargetTypeOf(patternSegment)) { - throw new IllegalArgumentException(String.format( - "patternSegment '%s' looks to be targeted at another known patternSegment type than %s", - patternSegment, - PatternType.VERBATIM)); - } - return new VerbatimPattern(patternSegment); + public static VerbatimElement from(String patternSegment) { + return new VerbatimElement(patternSegment); } @Override diff --git a/src/main/java/elf4j/engine/service/writer/StandardStreamWriter.java b/src/main/java/elf4j/engine/service/writer/StandardStreamWriter.java index f154c32..aba5da1 100644 --- a/src/main/java/elf4j/engine/service/writer/StandardStreamWriter.java +++ b/src/main/java/elf4j/engine/service/writer/StandardStreamWriter.java @@ -29,7 +29,7 @@ import elf4j.engine.service.LogEvent; import elf4j.engine.service.configuration.LogServiceConfiguration; import elf4j.engine.service.pattern.LogPattern; -import elf4j.engine.service.pattern.PatternGroup; +import elf4j.engine.service.pattern.PatternElement; import elf4j.engine.service.util.PropertiesUtils; import lombok.Builder; import lombok.NonNull; @@ -53,7 +53,7 @@ public class StandardStreamWriter implements LogWriter { private static final OutStreamType DEFAULT_OUT_STREAM_TYPE = OutStreamType.STDOUT; private static final String LINE_FEED = System.lineSeparator(); private final Level minimumLevel; - private final LogPattern logPattern; + private final PatternElement logPattern; private final OutStreamType outStreamType; private final StandardOutput standardOutput; @@ -99,7 +99,7 @@ private static StandardStreamWriter getDefaultWriter(@NonNull LogServiceConfigur .minimumLevel(Level.valueOf(properties.getProperty("level", DEFAULT_MINIMUM_LEVEL) .trim() .toUpperCase())) - .logPattern(PatternGroup.from(properties.getProperty("pattern", DEFAULT_PATTERN))) + .logPattern(LogPattern.from(properties.getProperty("pattern", DEFAULT_PATTERN))) .outStreamType(getGlobalOutStreamType(properties)) .standardOutput(logServiceConfiguration.getStandardOutput()) .build(); @@ -127,7 +127,8 @@ public List getLogWriters(LogServiceConfiguration logServiceConfigura if (writerConfigurations.isEmpty()) { return Collections.singletonList(getDefaultWriter(logServiceConfiguration)); } - return writerConfigurations.stream().map(writerConfiguration -> StandardStreamWriter.builder() + return writerConfigurations.stream() + .map(writerConfiguration -> StandardStreamWriter.builder() .outStreamType(OutStreamType.valueOf(getWriterConfigurationValueOrGlobalDefault("stream", writerConfiguration, properties, @@ -136,7 +137,7 @@ public List getLogWriters(LogServiceConfiguration logServiceConfigura writerConfiguration, properties, DEFAULT_MINIMUM_LEVEL).trim().toUpperCase())) - .logPattern(PatternGroup.from(getWriterConfigurationValueOrGlobalDefault("pattern", + .logPattern(LogPattern.from(getWriterConfigurationValueOrGlobalDefault("pattern", writerConfiguration, properties, DEFAULT_PATTERN))) diff --git a/src/test/java/elf4j/engine/service/pattern/ElementTypeTest.java b/src/test/java/elf4j/engine/service/pattern/ElementTypeTest.java new file mode 100644 index 0000000..8f1a5d3 --- /dev/null +++ b/src/test/java/elf4j/engine/service/pattern/ElementTypeTest.java @@ -0,0 +1,18 @@ +package elf4j.engine.service.pattern; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class ElementTypeTest { + + @Nested + class parsePattern { + @Test + void whenPredefinedElementIsUnrecognized() { + assertThrows(IllegalArgumentException.class, + () -> ElementType.parsePattern("{testUnrecognizedPredefined}")); + } + } +} diff --git a/src/test/java/elf4j/engine/service/pattern/JsonPatternTest.java b/src/test/java/elf4j/engine/service/pattern/JsonPatternTest.java index db49663..189a344 100644 --- a/src/test/java/elf4j/engine/service/pattern/JsonPatternTest.java +++ b/src/test/java/elf4j/engine/service/pattern/JsonPatternTest.java @@ -66,28 +66,28 @@ void beforeEach() { class from { @Test void noPatternOptionDefaults() { - JsonPattern jsonPattern = JsonPattern.from("json"); + JsonElement jsonPattern = JsonElement.from("json"); assertFalse(jsonPattern.includeCallerDetail()); } @Test void includeCallerOption() { - JsonPattern jsonPattern = JsonPattern.from("json:caller-detail"); + JsonElement jsonPattern = JsonElement.from("json:caller-detail"); assertTrue(jsonPattern.includeCallerDetail()); } @Test void includeThreadOption() { - JsonPattern jsonPattern = JsonPattern.from("json:caller-thread"); + JsonElement jsonPattern = JsonElement.from("json:caller-thread"); assertFalse(jsonPattern.includeCallerDetail()); } @Test void includeCallerAndThreadOptions() { - JsonPattern jsonPattern = JsonPattern.from("json:caller-thread,caller-detail"); + JsonElement jsonPattern = JsonElement.from("json:caller-thread,caller-detail"); assertTrue(jsonPattern.includeCallerDetail()); } @@ -95,7 +95,7 @@ void includeCallerAndThreadOptions() { @Nested class render { - JsonPattern jsonPattern = JsonPattern.from("json"); + JsonElement jsonPattern = JsonElement.from("json"); @Test void resolveMessage() { diff --git a/src/test/java/elf4j/engine/service/pattern/MessageAndExceptionPatternTest.java b/src/test/java/elf4j/engine/service/pattern/MessageAndExceptionPatternTest.java index 0dc02ca..e8a4d0e 100644 --- a/src/test/java/elf4j/engine/service/pattern/MessageAndExceptionPatternTest.java +++ b/src/test/java/elf4j/engine/service/pattern/MessageAndExceptionPatternTest.java @@ -36,7 +36,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @ExtendWith(MockitoExtension.class) @@ -63,19 +62,11 @@ void beforeEach() { .build(); } - @Nested - class from { - @Test - void errorOnInvalidPatternText() { - assertThrows(IllegalArgumentException.class, () -> MessageAndExceptionPattern.from("badPatternText")); - } - } - @Nested class render { @Test void includeBothMessageAndException() { - MessageAndExceptionPattern messageAndExceptionPattern = MessageAndExceptionPattern.from("message"); + MessageAndExceptionElement messageAndExceptionPattern = MessageAndExceptionElement.from("message"); StringBuilder logText = new StringBuilder(); messageAndExceptionPattern.render(mockLogEvent, logText); diff --git a/src/test/java/elf4j/engine/service/pattern/PatternGroupTest.java b/src/test/java/elf4j/engine/service/pattern/PatternGroupTest.java index e557f22..66c73ba 100644 --- a/src/test/java/elf4j/engine/service/pattern/PatternGroupTest.java +++ b/src/test/java/elf4j/engine/service/pattern/PatternGroupTest.java @@ -42,15 +42,15 @@ class PatternGroupTest { @Nested class render { - @Mock LogPattern mockPattern; - @Mock LogPattern mockPattern2; + @Mock PatternElement mockPattern; + @Mock PatternElement mockPattern2; @Mock LogEvent stubLogEvent; - PatternGroup patternGroupEntry; + LogPattern patternGroupEntry; @Test void dispatchAll() { - patternGroupEntry = new PatternGroup(Arrays.asList(mockPattern2, mockPattern)); + patternGroupEntry = new LogPattern(Arrays.asList(mockPattern2, mockPattern)); StringBuilder stringBuilder = new StringBuilder(); patternGroupEntry.render(stubLogEvent, stringBuilder); @@ -60,4 +60,4 @@ void dispatchAll() { then(mockPattern).should(inOrder).render(stubLogEvent, stringBuilder); } } -} \ No newline at end of file +} diff --git a/src/test/java/elf4j/engine/service/pattern/VerbatimPatternTest.java b/src/test/java/elf4j/engine/service/pattern/VerbatimPatternTest.java index 6aff14b..77a93ad 100644 --- a/src/test/java/elf4j/engine/service/pattern/VerbatimPatternTest.java +++ b/src/test/java/elf4j/engine/service/pattern/VerbatimPatternTest.java @@ -29,7 +29,6 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyNoInteractions; @@ -42,14 +41,9 @@ void appendPatternTextAsIs() { String inputLogText = "inputLogText"; StringBuilder logTextBuilder = new StringBuilder(inputLogText); - new VerbatimPattern(verbatimTextToAppend).render(mockEntry, logTextBuilder); + new VerbatimElement(verbatimTextToAppend).render(mockEntry, logTextBuilder); verifyNoInteractions(mockEntry); assertEquals(inputLogText + verbatimTextToAppend, logTextBuilder.toString()); } - - @Test - void errorOnPatternIntendedForAnotherLogPatternType() { - assertThrows(IllegalArgumentException.class, () -> VerbatimPattern.from("thread:name")); - } -} \ No newline at end of file +}