Skip to content

Commit eeedd40

Browse files
committed
Add Cli Telemetry
1 parent f722320 commit eeedd40

File tree

9 files changed

+157
-19
lines changed

9 files changed

+157
-19
lines changed

mcp/mcp-cli-api/build.gradle.kts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,6 @@ tasks.compileJava {
2323
options.compilerArgs.add("-Aproject=mcp-cli-api")
2424
}
2525

26-
sourceSets {
27-
main {
28-
java {
29-
srcDir("model")
30-
}
31-
}
32-
}
33-
3426
afterEvaluate {
3527
val typePath = smithy.getPluginProjectionPath(smithy.sourceProjection.get(), "java-type-codegen")
3628
sourceSets {
@@ -51,10 +43,6 @@ tasks.named("compileJava") {
5143
dependsOn("smithyBuild")
5244
}
5345

54-
tasks.withType<JavaCompile> {
55-
options.release.set(21)
56-
}
57-
5846
// Needed because sources-jar needs to run after smithy-build is done
5947
tasks.sourcesJar {
6048
mustRunAfter(tasks.compileJava)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.java.mcp.cli;
7+
8+
import java.util.Map;
9+
import java.util.concurrent.ConcurrentHashMap;
10+
import software.amazon.smithy.java.mcp.cli.model.TelemetryData;
11+
12+
public final class CliMetrics implements AutoCloseable {
13+
14+
private final TelemetryPublisher telemetryPublisher;
15+
private final TelemetryData.Builder telemetryData;
16+
private final Map<String, Long> counters = new ConcurrentHashMap<>();
17+
private final Map<String, Long> timings = new ConcurrentHashMap<>();
18+
private final long startTime;
19+
20+
CliMetrics(final TelemetryPublisher telemetryPublisher, TelemetryData.Builder telemetryData) {
21+
this.telemetryPublisher = telemetryPublisher;
22+
this.telemetryData = telemetryData;
23+
this.startTime = System.nanoTime();
24+
}
25+
26+
public void addCount(String name, long count) {
27+
counters.put(name, count);
28+
}
29+
30+
public void addTiming(String name, long time) {
31+
timings.put(name, time);
32+
}
33+
34+
@Override
35+
public void close() {
36+
timings.put("Time", System.nanoTime() - startTime);
37+
telemetryData
38+
.counters(counters)
39+
.timings(timings)
40+
.build();
41+
telemetryPublisher.publish(telemetryData.build());
42+
}
43+
}

mcp/mcp-cli-api/src/main/java/software/amazon/smithy/java/mcp/cli/ConfigUtils.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,15 @@ public static McpBundleConfig addMcpBundle(Config config, String id, Bundle bund
303303
.fileLocation(ConfigUtils.getBundleFileLocation(id).toString())
304304
.build();
305305
var builder = McpBundleConfig.builder();
306-
switch (bundle.getValue()) {
307-
case SmithyMcpBundle smithyBundle -> builder.smithyModeled(SmithyModeledBundleConfig.builder()
306+
switch (bundle.type()) {
307+
case smithyBundle -> builder.smithyModeled(SmithyModeledBundleConfig.builder()
308308
.name(id)
309-
.metadata(smithyBundle.getMetadata())
309+
.metadata(((SmithyMcpBundle) (bundle.getValue())).getMetadata())
310310
.bundleLocation(location)
311311
.local(isLocal)
312312
.build());
313-
case GenericBundle genericBundle -> {
313+
case genericBundle -> {
314+
GenericBundle genericBundle = bundle.getValue();
314315
install(genericBundle.getInstall());
315316
builder.genericConfig(
316317
GenericToolBundleConfig.builder()

mcp/mcp-cli-api/src/main/java/software/amazon/smithy/java/mcp/cli/ExecutionContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
import software.amazon.smithy.java.mcp.cli.model.Config;
99
import software.amazon.smithy.mcp.bundle.api.Registry;
1010

11-
public record ExecutionContext(Config config, Registry registry) {}
11+
public record ExecutionContext(Config config, Registry registry, CliMetrics metrics) {}

mcp/mcp-cli-api/src/main/java/software/amazon/smithy/java/mcp/cli/SmithyMcpCommand.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,19 @@
55

66
package software.amazon.smithy.java.mcp.cli;
77

8+
import static picocli.CommandLine.*;
89
import static software.amazon.smithy.java.mcp.cli.ConfigUtils.loadOrCreateConfig;
910

11+
import java.util.ArrayList;
12+
import java.util.List;
13+
import java.util.ServiceLoader;
1014
import java.util.concurrent.Callable;
15+
import picocli.CommandLine;
16+
import picocli.CommandLine.Model.CommandSpec;
17+
import picocli.CommandLine.Spec;
1118
import software.amazon.smithy.java.logging.InternalLogger;
1219
import software.amazon.smithy.java.mcp.cli.model.Config;
20+
import software.amazon.smithy.java.mcp.cli.model.TelemetryData;
1321

1422
/**
1523
* Base class for all Smithy MCP CLI commands.
@@ -18,15 +26,26 @@
1826
* for all MCP CLI commands. It handles loading the configuration, executing the command,
1927
* and providing appropriate error handling.
2028
*/
29+
@Command(name = "dummy")
2130
public abstract class SmithyMcpCommand implements Callable<Integer> {
2231

2332
InternalLogger LOG = InternalLogger.getLogger(SmithyMcpCommand.class);
2433

34+
private static final TelemetryPublisher TELEMETRY_PUBLISHER = findTelemetryPublisher();
35+
36+
@Spec
37+
CommandSpec spec;
38+
2539
@Override
2640
public final Integer call() {
27-
try {
41+
TelemetryData.Builder telemetry = TelemetryData.builder();
42+
String commandName = getCommandName(spec.commandLine());
43+
telemetry.command(commandName)
44+
.cliVersion(spec.version()[0]);
45+
46+
try (var metrics = new CliMetrics(TELEMETRY_PUBLISHER, telemetry)) {
2847
var config = loadOrCreateConfig();
29-
execute(new ExecutionContext(config, RegistryUtils.getRegistry(registryToUse(config), config)));
48+
execute(new ExecutionContext(config, RegistryUtils.getRegistry(registryToUse(config), config), metrics));
3049
return 0;
3150
} catch (IllegalArgumentException e) {
3251
System.out.println("Invalid input : [" + e.getMessage() + "]");
@@ -37,6 +56,22 @@ public final Integer call() {
3756
}
3857
}
3958

59+
private static String getCommandName(CommandLine commandLine) {
60+
List<String> commands = new ArrayList<>();
61+
while (commandLine != null) {
62+
commands.add(commandLine.getCommandName());
63+
commandLine = commandLine.getParent();
64+
}
65+
66+
StringBuilder commandName = new StringBuilder();
67+
for (int i = commands.size() - 2; i >= 0; i--) {
68+
commandName.append(commands.get(i));
69+
if (i > 0)
70+
commandName.append(":");
71+
}
72+
return commandName.toString();
73+
}
74+
4075
/**
4176
* Execute the command with the provided configuration.
4277
* <p>
@@ -50,4 +85,11 @@ public final Integer call() {
5085
protected String registryToUse(Config config) {
5186
return config.getDefaultRegistry();
5287
}
88+
89+
private static TelemetryPublisher findTelemetryPublisher() {
90+
return ServiceLoader.load(TelemetryPublisherProvider.class)
91+
.findFirst()
92+
.map(TelemetryPublisherProvider::get)
93+
.orElse(d -> {});
94+
}
5395
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.java.mcp.cli;
7+
8+
import software.amazon.smithy.java.mcp.cli.model.TelemetryData;
9+
10+
public interface TelemetryPublisher {
11+
12+
void publish(TelemetryData data);
13+
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.java.mcp.cli;
7+
8+
public interface TelemetryPublisherProvider {
9+
10+
TelemetryPublisher get();
11+
12+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mcp-cli-api.smithy

mcp/mcp-cli-api/model/main.smithy renamed to mcp/mcp-cli-api/src/main/resources/META-INF/smithy/mcp-cli-api.smithy

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,28 @@ union McpBundleConfig {
2525
genericConfig: GenericToolBundleConfig
2626
}
2727

28+
structure TelemetryData {
29+
@required
30+
command: String
31+
32+
@required
33+
cliVersion: String
34+
35+
@required
36+
@default({})
37+
counters: Counters
38+
39+
@required
40+
@default({})
41+
properties: Properties
42+
43+
@required
44+
@default({})
45+
timings: Timings
46+
47+
params: String
48+
}
49+
2850
@mixin
2951
structure CommonToolConfig {
3052
name: String
@@ -119,3 +141,18 @@ map EnvVars {
119141
key: String
120142
value: String
121143
}
144+
145+
map Counters {
146+
key: String
147+
value: PrimitiveLong
148+
}
149+
150+
map Timings {
151+
key: String
152+
value: PrimitiveLong
153+
}
154+
155+
map Properties {
156+
key: String
157+
value: String
158+
}

0 commit comments

Comments
 (0)