Skip to content

Commit d7b0766

Browse files
committed
feat: enrich telemetry with arch, locale, project_types, execution_ms, success, terminal; disable GeoIP
1 parent da6021d commit d7b0766

4 files changed

Lines changed: 58 additions & 17 deletions

File tree

src/main/java/pm/ProjectManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ public static void main(String[] args) {
113113
}
114114

115115
String command = args[0].toLowerCase();
116+
long startTime = System.currentTimeMillis();
117+
boolean success = true;
116118

117119
try {
118120
switch (command) {
@@ -146,10 +148,12 @@ public static void main(String[] args) {
146148
case "version", "-v", "--version" -> printVersion();
147149
default -> handleGenericCommand(command, args);
148150
}
149-
Telemetry.trackCommand(command);
150151
} catch (Exception e) {
152+
success = false;
151153
handleFatalError(e);
152154
} finally {
155+
long elapsedMs = System.currentTimeMillis() - startTime;
156+
Telemetry.trackCommand(command, success, elapsedMs);
153157
Telemetry.flush();
154158
}
155159
}

src/main/java/pm/telemetry/Telemetry.java

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import pm.util.Constants;
66

77
import java.nio.file.Files;
8+
import java.util.HashMap;
9+
import java.util.List;
810
import java.util.Map;
911
import java.util.UUID;
1012

@@ -48,21 +50,30 @@ public static void init() {
4850
/**
4951
* Tracks a command execution event (fire-and-forget).
5052
*
51-
* @param command The command name (e.g., "build", "test")
53+
* @param command The command name (e.g., "build", "test")
54+
* @param success Whether the command completed without exception
55+
* @param elapsedMs Execution time in milliseconds
5256
*/
53-
public static void trackCommand(String command) {
57+
public static void trackCommand(String command, boolean success, long elapsedMs) {
5458
if (config == null || !config.isTelemetryEnabled()) {
5559
return;
5660
}
5761
try {
58-
TelemetryEvent event = new TelemetryEvent("command_executed", Map.of(
59-
"command", command,
60-
"version", Constants.VERSION,
61-
"os", System.getProperty("os.name"),
62-
"os_version", System.getProperty("os.version"),
63-
"java_version", System.getProperty("java.version"),
64-
"project_count", getProjectCount()
65-
));
62+
Map<String, Object> props = new HashMap<>();
63+
props.put("command", command);
64+
props.put("version", Constants.VERSION);
65+
props.put("os", System.getProperty("os.name"));
66+
props.put("os_version", System.getProperty("os.version"));
67+
props.put("java_version", System.getProperty("java.version"));
68+
props.put("arch", System.getProperty("os.arch"));
69+
props.put("locale", java.util.Locale.getDefault().toString());
70+
props.put("terminal", System.getenv("TERM") != null ? System.getenv("TERM") : "unknown");
71+
props.put("project_count", getProjectCount());
72+
props.put("project_types", getProjectTypes());
73+
props.put("success", success);
74+
props.put("execution_ms", elapsedMs);
75+
76+
TelemetryEvent event = new TelemetryEvent("command_executed", props);
6677
TelemetryClient.send(event, Constants.POSTHOG_KEY, config.getDistinctId());
6778
} catch (Exception ignored) {
6879
// Telemetry tracking failure is non-critical
@@ -134,16 +145,41 @@ private static void promptConsent() {
134145
* Reads projects.json directly and counts top-level keys.
135146
*/
136147
private static int getProjectCount() {
148+
try {
149+
return loadProjectsMap().size();
150+
} catch (Exception e) {
151+
return 0;
152+
}
153+
}
154+
155+
/**
156+
* Extracts unique project types (e.g., ["Maven", "Rust", "Flutter"]).
157+
* No project names or paths — only the type field.
158+
*/
159+
private static List<String> getProjectTypes() {
160+
try {
161+
Map<String, Map<String, Object>> projects = loadProjectsMap();
162+
return projects.values().stream()
163+
.map(p -> p.getOrDefault("type", "UNKNOWN").toString())
164+
.distinct()
165+
.sorted()
166+
.toList();
167+
} catch (Exception e) {
168+
return List.of();
169+
}
170+
}
171+
172+
private static Map<String, Map<String, Object>> loadProjectsMap() {
137173
try {
138174
if (!Files.exists(Constants.PROJECTS_FILE)) {
139-
return 0;
175+
return Map.of();
140176
}
141177
String json = Files.readString(Constants.PROJECTS_FILE);
142-
Map<String, Object> projects = new Gson().fromJson(json,
143-
new TypeToken<Map<String, Object>>() {}.getType());
144-
return projects != null ? projects.size() : 0;
178+
Map<String, Map<String, Object>> projects = new Gson().fromJson(json,
179+
new TypeToken<Map<String, Map<String, Object>>>() {}.getType());
180+
return projects != null ? projects : Map.of();
145181
} catch (Exception e) {
146-
return 0;
182+
return Map.of();
147183
}
148184
}
149185

src/main/java/pm/telemetry/TelemetryEvent.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public Map<String, Object> toPostHogPayload(String apiKey, String distinctId) {
3232

3333
Map<String, Object> props = new HashMap<>(properties);
3434
props.put("$lib", "projectmanager");
35+
props.put("$ip", null);
3536
payload.put("properties", props);
3637

3738
return payload;

src/test/java/pm/telemetry/TelemetryTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class TrackingTests {
177177
void trackCommandWithNullConfig() {
178178
Telemetry.reset();
179179
// Should not throw
180-
assertDoesNotThrow(() -> Telemetry.trackCommand("build"));
180+
assertDoesNotThrow(() -> Telemetry.trackCommand("build", true, 100));
181181
}
182182

183183
@Test

0 commit comments

Comments
 (0)