Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions oap-mcp/oap-mcp-admin/src/main/java/oap/mcp/admin/McpLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import oap.ws.admin.LogWS;

import java.util.Map;
import java.util.Optional;

import static dev.khbd.interp4j.core.Interpolations.s;

Expand All @@ -26,9 +27,14 @@ public McpLog( LogWS logWS ) {
this.logWS = logWS;
}

@McpTool( name = "getLoggers", description = "Returns all loggers with their current log levels" )
public String getLoggers() {
Map<String, String> loggers = logWS.getAll();
@McpTool( name = "getLoggers",
description = "Returns loggers with their current log levels. Pass all=true to include loggers inheriting from root." )
public String getLoggers(
@McpToolParam( name = "all",
description = "Set to 'true' or 'yes' to include loggers inheriting their level from root",
required = false ) String all
) {
Map<String, String> loggers = logWS.getAll( Optional.ofNullable( all ) );
StringBuilder sb = new StringBuilder();
loggers.forEach( ( name, level ) -> sb.append( name ).append( " = " ).append( level ).append( '\n' ) );
return sb.toString();
Expand Down Expand Up @@ -59,14 +65,15 @@ Identify any loggers set to verbose levels (TRACE/DEBUG) that may impact perform

@McpPrompt( name = "diagnosePackage", description = "Diagnose logging for a specific Java package" )
public String diagnosePackage(
@McpPromptParam( name = "package", description = "Java package name to diagnose", required = true ) String pkg
@McpPromptParam( name = "package", description = "Java package name or partial name to diagnose", required = true ) String pkg
) {
return s( """
You are a Java application expert. Diagnose the logging configuration for package '${pkg}'.
Steps:
1. Use 'getLoggers' to check the current level for '${pkg}'.
2. If no explicit level is set, explain that it inherits from its parent logger.
3. Suggest an appropriate log level for debugging vs. production use.
4. Use 'setLogLevel' if a level change is needed.""" );
1. Call 'getLoggers' with all='true' to retrieve all loggers including those inheriting from root.
2. Filter the result to find all logger names that contain '${pkg}' as a substring.
3. Present the matching logger names and their current effective levels to the user.
4. Ask the user to confirm which exact logger name they want to target.
5. Once confirmed, suggest the appropriate log level and offer to call 'setLogLevel' with the confirmed name.""" );
}
}
20 changes: 15 additions & 5 deletions oap-mcp/oap-mcp-testing/src/test/java/oap/mcp/McpLogTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,18 @@ public void listTools() {
public void callGetLoggers() {
try( McpSyncClient client = createClient() ) {
McpSchema.CallToolResult result = client.callTool( new McpSchema.CallToolRequest( "getLoggers", Map.of() ) );
assertThat( result.isError() ).isNotEqualTo( Boolean.TRUE );
assertThat( ( ( McpSchema.TextContent ) result.content().get( 0 ) ).text() ).isNotBlank();
assertThat( result.isError() ).isFalse();
assertThat( ( ( McpSchema.TextContent ) result.content().getFirst() ).text() ).isNotBlank();
}
}

@Test
public void callGetLoggersAll() {
try( McpSyncClient client = createClient() ) {
McpSchema.CallToolResult result = client.callTool(
new McpSchema.CallToolRequest( "getLoggers", Map.of( "all", "true" ) ) );
assertThat( result.isError() ).isFalse();
assertThat( ( ( McpSchema.TextContent ) result.content().getFirst() ).text() ).contains( "ROOT" );
}
}

Expand All @@ -72,7 +82,7 @@ public void callSetLogLevel() {
try( McpSyncClient client = createClient() ) {
McpSchema.CallToolResult result = client.callTool( new McpSchema.CallToolRequest( "setLogLevel",
Map.of( "package", "oap", "level", "DEBUG" ) ) );
assertThat( result.isError() ).isNotEqualTo( Boolean.TRUE );
assertThat( result.isError() ).isFalse();
}
}

Expand All @@ -91,7 +101,7 @@ public void getPromptAnalyzeLogging() {
try( McpSyncClient client = createClient() ) {
McpSchema.GetPromptResult result = client.getPrompt(
new McpSchema.GetPromptRequest( "analyzeLogging", Map.of() ) );
assertThat( ( ( McpSchema.TextContent ) result.messages().get( 0 ).content() ).text() ).isNotBlank();
assertThat( ( ( McpSchema.TextContent ) result.messages().getFirst().content() ).text() ).isNotBlank();
}
}

Expand All @@ -100,7 +110,7 @@ public void getPromptDiagnosePackage() {
try( McpSyncClient client = createClient() ) {
McpSchema.GetPromptResult result = client.getPrompt(
new McpSchema.GetPromptRequest( "diagnosePackage", Map.of( "package", "oap.ws" ) ) );
assertThat( ( ( McpSchema.TextContent ) result.messages().get( 0 ).content() ).text() ).contains( "oap.ws" );
assertThat( ( ( McpSchema.TextContent ) result.messages().getFirst().content() ).text() ).contains( "oap.ws" );
}
}
}
13 changes: 9 additions & 4 deletions oap-ws/oap-ws-admin-ws/src/main/java/oap/ws/admin/LogWS.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,27 @@
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

import static oap.http.server.nio.HttpServerExchange.HttpMethod.GET;
import static oap.io.Resources.urlOrThrow;
import static oap.ws.WsParam.From.PATH;
import static oap.ws.WsParam.From.QUERY;

@Slf4j
public class LogWS {
@WsMethod( path = "/", method = GET )
public Map<String, String> getAll() {
log.debug( "get all" );
public Map<String, String> getAll( @WsParam( from = QUERY ) Optional<String> all ) {
log.debug( "get all, all={}", all );

LinkedHashMap<String, String> map = new LinkedHashMap<>();
boolean includeAll = all.map( v -> v.equalsIgnoreCase( "true" ) || v.equalsIgnoreCase( "yes" ) ).orElse( false );

LinkedHashMap<String, String> map = new LinkedHashMap<>();
LoggerContext loggerContext = ( LoggerContext ) LoggerFactory.getILoggerFactory();
for( Logger logger : loggerContext.getLoggerList() ) {
if( logger.getLevel() != null ) {
if( includeAll ) {
map.put( logger.getName(), logger.getEffectiveLevel().toString() );
} else if( logger.getLevel() != null ) {
map.put( logger.getName(), logger.getLevel().toString() );
}
}
Expand Down
15 changes: 13 additions & 2 deletions oap-ws/oap-ws-admin-ws/src/test/java/oap/ws/admin/LogWSTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.testng.annotations.Test;

import java.util.Map;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
Expand All @@ -51,9 +52,19 @@ public void logs() {

@Test
public void testGetAll() {
log.trace( "testGetAll" );
LogWS logWS = new LogWS();
Map<String, String> map = logWS.getAll();
Map<String, String> map = logWS.getAll( Optional.empty() );

assertThat( map ).contains( entry( "org", "WARN" ) );
assertThat( map )
.contains( entry( "org", "WARN" ) )
.doesNotContainKey( "oap.ws.admin.LogWSTest" );
}

@Test
public void testGetAllIncludeRoot() {
LogWS logWS = new LogWS();
assertThat( logWS.getAll( Optional.of( "true" ) ) ).containsKey( "oap.ws.admin.LogWSTest" );
assertThat( logWS.getAll( Optional.of( "yes" ) ) ).containsKey( "oap.ws.admin.LogWSTest" );
}
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
</dependencies>

<properties>
<oap.project.version>25.7.1</oap.project.version>
<oap.project.version>25.7.2</oap.project.version>

<oap.deps.config.version>25.0.1</oap.deps.config.version>
<oap.deps.oap-teamcity.version>25.0.0</oap.deps.oap-teamcity.version>
Expand Down
Loading