This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-mcp-server-contributions.git
The following commit(s) were added to refs/heads/master by this push:
new bd747d4 chore: clearer separation of 'api' and 'impl' classes for the
log support (#4)
bd747d4 is described below
commit bd747d4a4f4b850a5a9f4c4bbca36e34cf433fb5
Author: Robert Munteanu <[email protected]>
AuthorDate: Tue May 12 23:43:07 2026 +0200
chore: clearer separation of 'api' and 'impl' classes for the log support
(#4)
This is related to SLING-13188
---
.../internal => contribs/log}/LogSnapshot.java | 44 +-----------------
.../server/contribs/log/StructuredLogBuffer.java} | 19 ++++----
.../server/impl/contribs/LogToolContribution.java | 21 +++++----
.../mcp/server/impl/contribs/log/LogLevel.java} | 28 ++++++++----
.../StructuredLogBufferAppender.java | 39 +++++-----------
.../StructuredLogBufferImpl.java} | 52 ++++++++++++++++++----
.../contribs/log/StructuredLogBufferSink.java} | 14 ++----
.../internal => contribs/log}/LogSnapshotTest.java | 14 +++---
.../StructuredLogBufferAppenderTest.java | 43 ++++++++++++++----
.../StructuredLogBufferImplTest.java} | 36 ++++++++++-----
10 files changed, 169 insertions(+), 141 deletions(-)
diff --git
a/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshot.java
b/src/main/java/org/apache/sling/mcp/server/contribs/log/LogSnapshot.java
similarity index 53%
rename from
src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshot.java
rename to
src/main/java/org/apache/sling/mcp/server/contribs/log/LogSnapshot.java
index 6dc4cb4..c986ad8 100644
---
a/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshot.java
+++ b/src/main/java/org/apache/sling/mcp/server/contribs/log/LogSnapshot.java
@@ -16,11 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.contribs.log;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
import java.util.Map;
/**
@@ -29,52 +27,14 @@ import java.util.Map;
*/
public record LogSnapshot(
long timeMillis,
- LogLevel level, // avoid binding to logback or a specific version of
slf4j
+ String level,
String loggerName,
String threadName,
String formattedMessage,
String throwableText,
Map<String, String> mdc) {
- public static boolean isValidLogLevel(String logLevelName) {
- try {
- LogLevel.valueOf(logLevelName);
- return true;
- } catch (IllegalArgumentException e) {
- return false;
- }
- }
-
- public static List<String> getValidLogLevelNames() {
- return Arrays.stream(LogLevel.values()).map(Enum::toString).toList();
- }
-
- public static String getHighestLogLevelName() {
- return LogLevel.values()[LogLevel.values().length - 1].toString();
- }
-
public LogSnapshot {
mdc = mdc == null ? Collections.emptyMap() :
Collections.unmodifiableMap(mdc);
}
-
- enum LogLevel {
- TRACE,
- DEBUG,
- INFO,
- WARN,
- ERROR;
-
- boolean isGreaterOrEqual(LogLevel minLevel) {
- return ordinal() >= minLevel.ordinal();
- }
-
- public boolean isValid(String logLevelName) {
- try {
- LogLevel.valueOf(logLevelName);
- return true;
- } catch (IllegalArgumentException e) {
- return false;
- }
- }
- }
}
diff --git
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
b/src/main/java/org/apache/sling/mcp/server/contribs/log/StructuredLogBuffer.java
similarity index 68%
copy from
src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
copy to
src/main/java/org/apache/sling/mcp/server/contribs/log/StructuredLogBuffer.java
index 8c494b5..07e0c8d 100644
---
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
+++
b/src/main/java/org/apache/sling/mcp/server/contribs/log/StructuredLogBuffer.java
@@ -16,17 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.contribs.log;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot.LogLevel;
-import org.junit.jupiter.api.Test;
+import java.util.List;
+import java.util.regex.Pattern;
-import static org.junit.jupiter.api.Assertions.*;
+public interface StructuredLogBuffer {
-class LogSnapshotTest {
+ boolean isValidLogLevel(String logLevelName);
- @Test
- void logLevelComparison() {
- assertTrue(LogSnapshot.LogLevel.INFO.isGreaterOrEqual(LogLevel.TRACE));
- }
+ List<String> getValidLogLevelNames();
+
+ String getHighestLogLevelName();
+
+ List<LogSnapshot> getRecent(Pattern pattern, String minLevel, int
maxEntries);
}
diff --git
a/src/main/java/org/apache/sling/mcp/server/impl/contribs/LogToolContribution.java
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/LogToolContribution.java
index bbd11c9..169ad35 100644
---
a/src/main/java/org/apache/sling/mcp/server/impl/contribs/LogToolContribution.java
+++
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/LogToolContribution.java
@@ -30,8 +30,8 @@ import io.modelcontextprotocol.json.McpJsonMapperSupplier;
import
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.Tool;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot;
-import
org.apache.sling.mcp.server.impl.contribs.internal.StructuredLogBufferAppender;
+import org.apache.sling.mcp.server.contribs.log.LogSnapshot;
+import org.apache.sling.mcp.server.contribs.log.StructuredLogBuffer;
import org.apache.sling.mcp.server.spi.McpServerContribution;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
@@ -44,7 +44,7 @@ import org.osgi.service.component.annotations.Reference;
public class LogToolContribution implements McpServerContribution {
@Reference
- private StructuredLogBufferAppender structuredLogBufferAppender;
+ private StructuredLogBuffer structuredLogBuffer;
@Reference
private McpJsonMapperSupplier jsonMapper;
@@ -79,7 +79,7 @@ public class LogToolContribution implements
McpServerContribution {
}
""".formatted(
validLogLevelValuesAsCsv(),
- LogSnapshot.getHighestLogLevelName(),
+ structuredLogBuffer.getHighestLogLevelName(),
validLogLevelValuesAsJsonSchemaEnum());
return List.of(new SyncToolSpecification(
@@ -103,12 +103,12 @@ public class LogToolContribution implements
McpServerContribution {
maxEntries = Math.min(maxEntries, 1000); // Cap at 1000
}
- String minLogLevel = LogSnapshot.getHighestLogLevelName();
+ String minLogLevel =
structuredLogBuffer.getHighestLogLevelName();
if (logLevelStr != null && !logLevelStr.isEmpty()) {
- if (!LogSnapshot.isValidLogLevel(logLevelStr)) {
+ if (!structuredLogBuffer.isValidLogLevel(logLevelStr))
{
return CallToolResult.builder()
.addTextContent("Invalid log level: " +
logLevelStr + ". Valid options are: "
- + String.join(", ",
LogSnapshot.getValidLogLevelNames()))
+ + String.join(", ",
structuredLogBuffer.getValidLogLevelNames()))
.isError(true)
.build();
}
@@ -128,8 +128,7 @@ public class LogToolContribution implements
McpServerContribution {
}
}
- List<LogSnapshot> filteredLogs =
-
structuredLogBufferAppender.getBuffer().getRecent(pattern, minLogLevel,
maxEntries);
+ List<LogSnapshot> filteredLogs =
structuredLogBuffer.getRecent(pattern, minLogLevel, maxEntries);
// Format output
String result = formatLogs(filteredLogs, regexPattern,
minLogLevel, maxEntries);
@@ -216,13 +215,13 @@ public class LogToolContribution implements
McpServerContribution {
}
private String validLogLevelValuesAsCsv() {
- return String.join(", ", LogSnapshot.getValidLogLevelNames());
+ return String.join(", ", structuredLogBuffer.getValidLogLevelNames());
}
private String validLogLevelValuesAsJsonSchemaEnum() {
StringBuilder result = new StringBuilder();
result.append("[ ");
- result.append(LogSnapshot.getValidLogLevelNames().stream()
+ result.append(structuredLogBuffer.getValidLogLevelNames().stream()
.map(name -> '"' + name + '"')
.collect(Collectors.joining(", ")));
result.append(" ]");
diff --git
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/log/LogLevel.java
similarity index 60%
copy from
src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
copy to
src/main/java/org/apache/sling/mcp/server/impl/contribs/log/LogLevel.java
index 8c494b5..c0cb8fd 100644
---
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
+++ b/src/main/java/org/apache/sling/mcp/server/impl/contribs/log/LogLevel.java
@@ -16,17 +16,29 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.impl.contribs.log;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot.LogLevel;
-import org.junit.jupiter.api.Test;
+enum LogLevel {
+ TRACE,
+ DEBUG,
+ INFO,
+ WARN,
+ ERROR;
-import static org.junit.jupiter.api.Assertions.*;
+ static boolean isValid(String logLevelName) {
+ try {
+ LogLevel.valueOf(logLevelName);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
-class LogSnapshotTest {
+ static String getHighestName() {
+ return values()[values().length - 1].toString();
+ }
- @Test
- void logLevelComparison() {
- assertTrue(LogSnapshot.LogLevel.INFO.isGreaterOrEqual(LogLevel.TRACE));
+ boolean isGreaterOrEqual(LogLevel minLevel) {
+ return ordinal() >= minLevel.ordinal();
}
}
diff --git
a/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppender.java
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferAppender.java
similarity index 81%
rename from
src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppender.java
rename to
src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferAppender.java
index 244f297..2122531 100644
---
a/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppender.java
+++
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferAppender.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.impl.contribs.log;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -29,52 +29,37 @@ import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.AppenderBase;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot.LogLevel;
+import org.apache.sling.mcp.server.contribs.log.LogSnapshot;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.osgi.service.component.annotations.Reference;
@Component(
- service = {Appender.class, StructuredLogBufferAppender.class},
- property = {
- "loggers=ROOT",
- "service.description=Structured in-memory MCP log appender",
- "service.vendor=The Apache Software Foundation"
- })
-@Designate(ocd = StructuredLogBufferAppender.Configuration.class)
+ service = Appender.class,
+ property = {"loggers=ROOT"})
public class StructuredLogBufferAppender extends AppenderBase<ILoggingEvent> {
// Forward compatibility with logback 1.5+, where IThrowableProxy may
expose getOverridingMessage().
private static final MethodHandle GET_OVERRIDING_MESSAGE =
findGetOverridingMessage();
- @ObjectClassDefinition(name = "Apache Sling Structured Log Buffer")
- public @interface Configuration {
-
- @AttributeDefinition(name = "Max entries")
- int maxEntries() default 10000;
- }
-
- private final StructuredLogBuffer buffer;
+ private final StructuredLogBufferSink buffer;
@Activate
- public StructuredLogBufferAppender(Configuration configuration) {
- buffer = new StructuredLogBuffer(configuration.maxEntries());
+ public StructuredLogBufferAppender(@Reference StructuredLogBufferSink
buffer) {
+ this.buffer = buffer;
setName("structured-log-buffer");
}
- public StructuredLogBuffer getBuffer() {
- return buffer;
- }
-
@Override
protected void append(ILoggingEvent eventObject) {
if (eventObject == null) {
return;
}
- LogLevel logLevel = LogLevel.valueOf(eventObject.getLevel().levelStr);
+ String logLevel = eventObject.getLevel().levelStr;
+ if (!LogLevel.isValid(logLevel)) {
+ return;
+ }
buffer.append(new LogSnapshot(
eventObject.getTimeStamp(),
diff --git
a/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBuffer.java
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferImpl.java
similarity index 65%
rename from
src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBuffer.java
rename to
src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferImpl.java
index 9a9ba53..c3bfe5f 100644
---
a/src/main/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBuffer.java
+++
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferImpl.java
@@ -16,26 +16,48 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.impl.contribs.log;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import java.util.regex.Pattern;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot.LogLevel;
+import org.apache.sling.mcp.server.contribs.log.LogSnapshot;
+import org.apache.sling.mcp.server.contribs.log.StructuredLogBuffer;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
-public class StructuredLogBuffer {
+@Component(service = {StructuredLogBuffer.class,
StructuredLogBufferSink.class})
+@Designate(ocd = StructuredLogBufferImpl.Configuration.class)
+public class StructuredLogBufferImpl implements StructuredLogBuffer,
StructuredLogBufferSink {
+
+ @ObjectClassDefinition(name = "Apache Sling Structured Log Buffer")
+ public @interface Configuration {
+
+ @AttributeDefinition(name = "Max entries")
+ int maxEntries() default 10000;
+ }
private final Object lock = new Object();
private final Deque<LogSnapshot> entries = new ArrayDeque<>();
private int maxEntriesKept;
- public StructuredLogBuffer(int maxEntriesKept) {
+ public StructuredLogBufferImpl(int maxEntriesKept) {
this.maxEntriesKept = Math.max(1, maxEntriesKept);
}
+ @Activate
+ public StructuredLogBufferImpl(Configuration configuration) {
+ this(configuration.maxEntries());
+ }
+
+ @Override
public void append(LogSnapshot snapshot) {
synchronized (lock) {
entries.addLast(snapshot);
@@ -43,9 +65,24 @@ public class StructuredLogBuffer {
}
}
+ @Override
+ public boolean isValidLogLevel(String logLevelName) {
+ return LogLevel.isValid(logLevelName);
+ }
+
+ @Override
+ public List<String> getValidLogLevelNames() {
+ return Arrays.stream(LogLevel.values()).map(Enum::toString).toList();
+ }
+
+ @Override
+ public String getHighestLogLevelName() {
+ return LogLevel.getHighestName();
+ }
+
public List<LogSnapshot> getRecent(Pattern pattern, String minLevel, int
maxEntries) {
- if (!LogSnapshot.isValidLogLevel(minLevel)) {
+ if (!isValidLogLevel(minLevel)) {
throw new IllegalArgumentException("Invalid log level: " +
minLevel);
}
@@ -70,12 +107,11 @@ public class StructuredLogBuffer {
private boolean matches(LogSnapshot snapshot, Pattern pattern, LogLevel
minLevel) {
- if (snapshot.level().isGreaterOrEqual(minLevel)) {
+ if (LogLevel.valueOf(snapshot.level()).isGreaterOrEqual(minLevel)) {
if (pattern == null) {
return true;
}
- return matchesField(
- pattern, snapshot.level() != null ?
snapshot.level().toString() : null)
+ return matchesField(pattern, snapshot.level())
|| matchesField(pattern, snapshot.loggerName())
|| matchesField(pattern, snapshot.threadName())
|| matchesField(pattern, snapshot.formattedMessage())
diff --git
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferSink.java
similarity index 68%
copy from
src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
copy to
src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferSink.java
index 8c494b5..1524641 100644
---
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
+++
b/src/main/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferSink.java
@@ -16,17 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.impl.contribs.log;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot.LogLevel;
-import org.junit.jupiter.api.Test;
+import org.apache.sling.mcp.server.contribs.log.LogSnapshot;
-import static org.junit.jupiter.api.Assertions.*;
+interface StructuredLogBufferSink {
-class LogSnapshotTest {
-
- @Test
- void logLevelComparison() {
- assertTrue(LogSnapshot.LogLevel.INFO.isGreaterOrEqual(LogLevel.TRACE));
- }
+ void append(LogSnapshot snapshot);
}
diff --git
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
b/src/test/java/org/apache/sling/mcp/server/contribs/log/LogSnapshotTest.java
similarity index 69%
rename from
src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
rename to
src/test/java/org/apache/sling/mcp/server/contribs/log/LogSnapshotTest.java
index 8c494b5..5ea3105 100644
---
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/LogSnapshotTest.java
+++
b/src/test/java/org/apache/sling/mcp/server/contribs/log/LogSnapshotTest.java
@@ -16,17 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.contribs.log;
+
+import java.util.Map;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot.LogLevel;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
class LogSnapshotTest {
@Test
- void logLevelComparison() {
- assertTrue(LogSnapshot.LogLevel.INFO.isGreaterOrEqual(LogLevel.TRACE));
+ void storesMdcAsUnmodifiableMap() {
+ LogSnapshot snapshot = new LogSnapshot(1L, "INFO", "logger", "thread",
"message", null, Map.of("k", "v"));
+
+ assertEquals("INFO", snapshot.level());
+ assertEquals(Map.of("k", "v"), snapshot.mdc());
}
}
diff --git
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppenderTest.java
b/src/test/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferAppenderTest.java
similarity index 58%
rename from
src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppenderTest.java
rename to
src/test/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferAppenderTest.java
index 1d34628..aa81263 100644
---
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferAppenderTest.java
+++
b/src/test/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferAppenderTest.java
@@ -16,26 +16,28 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.impl.contribs.log;
+import java.lang.reflect.Constructor;
import java.util.List;
-import java.util.Map;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggingEvent;
+import org.apache.sling.mcp.server.contribs.log.LogSnapshot;
import org.junit.jupiter.api.Test;
-import org.osgi.util.converter.Converters;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
class StructuredLogBufferAppenderTest {
@Test
void appenderSnapshotsFormattedMessageAndThrowable() {
- StructuredLogBufferAppender appender = new
StructuredLogBufferAppender(configuration(5));
+ StructuredLogBufferImpl buffer = new StructuredLogBufferImpl(5);
+ StructuredLogBufferAppender appender = new
StructuredLogBufferAppender(buffer);
LoggerContext context = new LoggerContext();
appender.setContext(context);
@@ -47,16 +49,39 @@ class StructuredLogBufferAppenderTest {
appender.append(event);
- List<LogSnapshot> logs = appender.getBuffer().getRecent(null, "TRACE",
10);
+ List<LogSnapshot> logs = buffer.getRecent(null, "TRACE", 10);
assertEquals(1, logs.size());
assertEquals("message", logs.get(0).formattedMessage());
assertEquals("worker-1", logs.get(0).threadName());
+ assertEquals("ERROR", logs.get(0).level());
assertNotNull(logs.get(0).throwableText());
}
- private StructuredLogBufferAppender.Configuration configuration(int
maxEntries) {
- return Converters.standardConverter()
- .convert(Map.of("maxEntries", maxEntries))
- .to(StructuredLogBufferAppender.Configuration.class);
+ @Test
+ void appenderSkipsInvalidLogLevels() {
+ StructuredLogBufferImpl buffer = new StructuredLogBufferImpl(5);
+ StructuredLogBufferAppender appender = new
StructuredLogBufferAppender(buffer);
+
+ LoggerContext context = new LoggerContext();
+ LoggingEvent event = new LoggingEvent();
+ event.setLoggerName("invalid.logger");
+ event.setThreadName("invalid-thread");
+ event.setMessage("ignored");
+ event.setLevel(invalidLevel());
+
+ appender.append(event);
+
+ assertEquals(List.of(), buffer.getRecent(null, "TRACE", 10));
+ }
+
+ private Level invalidLevel() {
+ try {
+ Constructor<Level> constructor =
Level.class.getDeclaredConstructor(int.class, String.class);
+ constructor.setAccessible(true);
+ return constructor.newInstance(Integer.MAX_VALUE, "INVALID");
+ } catch (ReflectiveOperationException e) {
+ fail("Unable to construct invalid log level", e);
+ return null;
+ }
}
}
diff --git
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferTest.java
b/src/test/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferImplTest.java
similarity index 57%
rename from
src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferTest.java
rename to
src/test/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferImplTest.java
index 8557801..d2e4d7d 100644
---
a/src/test/java/org/apache/sling/mcp/server/impl/contribs/internal/StructuredLogBufferTest.java
+++
b/src/test/java/org/apache/sling/mcp/server/impl/contribs/log/StructuredLogBufferImplTest.java
@@ -16,26 +16,28 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.mcp.server.impl.contribs.internal;
+package org.apache.sling.mcp.server.impl.contribs.log;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
-import org.apache.sling.mcp.server.impl.contribs.internal.LogSnapshot.LogLevel;
+import org.apache.sling.mcp.server.contribs.log.LogSnapshot;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
-class StructuredLogBufferTest {
+class StructuredLogBufferImplTest {
@Test
void keepsOnlyNewestEntriesWithinCapacity() {
- StructuredLogBuffer buffer = new StructuredLogBuffer(2);
+ StructuredLogBufferImpl buffer = new StructuredLogBufferImpl(2);
- buffer.append(snapshot(1L, LogLevel.INFO, "first"));
- buffer.append(snapshot(2L, LogLevel.INFO, "second"));
- buffer.append(snapshot(3L, LogLevel.INFO, "third"));
+ buffer.append(snapshot(1L, "INFO", "first"));
+ buffer.append(snapshot(2L, "INFO", "second"));
+ buffer.append(snapshot(3L, "INFO", "third"));
List<LogSnapshot> logs = buffer.getRecent(null, "TRACE", 10);
assertEquals(
@@ -45,11 +47,11 @@ class StructuredLogBufferTest {
@Test
void filtersByLevelAndRegex() {
- StructuredLogBuffer buffer = new StructuredLogBuffer(10);
+ StructuredLogBufferImpl buffer = new StructuredLogBufferImpl(10);
- buffer.append(snapshot(1L, LogLevel.DEBUG, "debug trace"));
- buffer.append(snapshot(2L, LogLevel.INFO, "first user ok"));
- buffer.append(snapshot(3L, LogLevel.ERROR, "first user failure"));
+ buffer.append(snapshot(1L, "DEBUG", "debug trace"));
+ buffer.append(snapshot(2L, "INFO", "first user ok"));
+ buffer.append(snapshot(3L, "ERROR", "first user failure"));
List<LogSnapshot> logs = buffer.getRecent(Pattern.compile("first",
Pattern.CASE_INSENSITIVE), "INFO", 10);
@@ -58,7 +60,17 @@ class StructuredLogBufferTest {
logs.stream().map(LogSnapshot::formattedMessage).toList());
}
- private LogSnapshot snapshot(long timeMillis, LogLevel level, String
message) {
+ @Test
+ void exposesSupportedLogLevels() {
+ StructuredLogBufferImpl buffer = new StructuredLogBufferImpl(10);
+
+ assertTrue(buffer.isValidLogLevel("INFO"));
+ assertFalse(buffer.isValidLogLevel("info"));
+ assertEquals(List.of("TRACE", "DEBUG", "INFO", "WARN", "ERROR"),
buffer.getValidLogLevelNames());
+ assertEquals("ERROR", buffer.getHighestLogLevelName());
+ }
+
+ private LogSnapshot snapshot(long timeMillis, String level, String
message) {
return new LogSnapshot(timeMillis, level, "logger", "thread", message,
null, Map.of());
}
}