Skip to content

Commit b523e1c

Browse files
committed
Launcher logging and tracing
1 parent 81cfef4 commit b523e1c

4 files changed

Lines changed: 101 additions & 42 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
target/
1+
target/
2+
/nsd.log

pom.xml

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>org.nasdanika</groupId>
6-
<version>2025.5.0</version>
6+
<version>2025.6.0</version>
77
<artifactId>cli-launcher</artifactId>
88
<packaging>jar</packaging>
99
<name>Nasdanika CLI launcher</name>
@@ -24,60 +24,73 @@
2424
<url>https://github.com/Nasdanika/cli</url>
2525

2626
<dependencies>
27+
28+
<!-- Forcing SLF4j version -->
29+
<dependency>
30+
<groupId>org.slf4j</groupId>
31+
<artifactId>slf4j-api</artifactId>
32+
<version>2.0.17</version>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.slf4j</groupId>
36+
<artifactId>jul-to-slf4j</artifactId>
37+
<version>2.0.17</version>
38+
</dependency>
39+
2740
<dependency>
2841
<groupId>org.nasdanika.models.app</groupId>
2942
<artifactId>cli</artifactId>
30-
<version>2025.5.0</version>
43+
<version>2025.6.0</version>
3144
</dependency>
3245
<dependency>
3346
<groupId>org.nasdanika.models.java</groupId>
3447
<artifactId>cli</artifactId>
35-
<version>2025.5.0</version>
48+
<version>2025.6.0</version>
3649
</dependency>
3750
<dependency>
3851
<groupId>org.nasdanika.models.rules</groupId>
3952
<artifactId>cli</artifactId>
40-
<version>2025.5.0</version>
53+
<version>2025.6.0</version>
4154
</dependency>
4255
<dependency>
4356
<groupId>org.nasdanika.models.crew-ai</groupId>
4457
<artifactId>cli</artifactId>
45-
<version>2025.5.0</version>
58+
<version>2025.6.0</version>
4659
</dependency>
4760
<dependency>
4861
<groupId>org.nasdanika.models.architecture</groupId>
4962
<artifactId>model</artifactId>
50-
<version>2025.5.0</version>
63+
<version>2025.6.0</version>
5164
</dependency>
5265
<dependency>
5366
<groupId>org.nasdanika.core</groupId>
5467
<artifactId>http</artifactId>
55-
<version>2025.5.0</version>
68+
<version>2025.6.0</version>
5669
</dependency>
5770
<dependency>
5871
<groupId>org.nasdanika.core</groupId>
5972
<artifactId>groovy</artifactId>
60-
<version>2025.5.0</version>
73+
<version>2025.6.0</version>
6174
</dependency>
6275
<dependency>
6376
<groupId>org.nasdanika.core</groupId>
6477
<artifactId>maven</artifactId>
65-
<version>2025.5.0</version>
78+
<version>2025.6.0</version>
6679
</dependency>
6780
<dependency>
6881
<groupId>org.nasdanika.models.echarts</groupId>
6982
<artifactId>graph</artifactId>
70-
<version>2025.5.0</version>
83+
<version>2025.6.0</version>
7184
</dependency>
7285
<dependency>
7386
<groupId>org.nasdanika.models.ecore</groupId>
7487
<artifactId>cli</artifactId>
75-
<version>2025.5.0</version>
88+
<version>2025.6.0</version>
7689
</dependency>
7790
<dependency>
7891
<groupId>org.apache.groovy</groupId>
7992
<artifactId>groovy-all</artifactId>
80-
<version>4.0.26</version>
93+
<version>4.0.27</version>
8194
<type>pom</type>
8295
</dependency>
8396

@@ -90,13 +103,13 @@
90103
<dependency>
91104
<groupId>org.junit.jupiter</groupId>
92105
<artifactId>junit-jupiter-api</artifactId>
93-
<version>5.11.4</version>
106+
<version>5.12.1</version>
94107
<scope>test</scope>
95108
</dependency>
96109
<dependency>
97110
<groupId>org.junit.jupiter</groupId>
98111
<artifactId>junit-jupiter-engine</artifactId>
99-
<version>5.11.4</version>
112+
<version>5.12.1</version>
100113
<scope>test</scope>
101114
</dependency>
102115
</dependencies>
@@ -149,7 +162,7 @@
149162
<plugin>
150163
<groupId>org.apache.maven.plugins</groupId>
151164
<artifactId>maven-failsafe-plugin</artifactId>
152-
<version>3.5.2</version>
165+
<version>3.5.3</version>
153166
<executions>
154167
<execution>
155168
<goals>
@@ -162,7 +175,7 @@
162175
<dependency>
163176
<groupId>org.junit.jupiter</groupId>
164177
<artifactId>junit-jupiter-engine</artifactId>
165-
<version>5.11.4</version>
178+
<version>5.12.1</version>
166179
</dependency>
167180
</dependencies>
168181
</plugin>

src/main/java/module-info.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
exports org.nasdanika.launcher;
44

55
requires transitive org.nasdanika.cli;
6+
7+
// For loading configuration
8+
requires ch.qos.logback.classic;
9+
requires ch.qos.logback.core;
610

711
requires org.nasdanika.models.echarts.graph;
812
requires java.sql;

src/main/java/org/nasdanika/launcher/Launcher.java

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,82 @@
1212
import org.nasdanika.cli.ShellCommand;
1313
import org.nasdanika.cli.SubCommandRequirement;
1414
import org.nasdanika.common.Closeable;
15-
import org.nasdanika.common.NullProgressMonitor;
15+
import org.nasdanika.common.LoggerProgressMonitor;
1616
import org.nasdanika.common.ProgressMonitor;
17+
import org.nasdanika.telemetry.GlobalOpenTelemetryCapabilityFactory;
18+
import org.nasdanika.telemetry.TelemetryUtil;
19+
import org.slf4j.Logger;
20+
import org.slf4j.LoggerFactory;
1721

22+
import io.opentelemetry.api.OpenTelemetry;
23+
import io.opentelemetry.api.common.Attributes;
24+
import io.opentelemetry.api.trace.Span;
25+
import io.opentelemetry.api.trace.SpanBuilder;
26+
import io.opentelemetry.api.trace.StatusCode;
27+
import io.opentelemetry.api.trace.Tracer;
28+
import io.opentelemetry.context.Scope;
1829
import picocli.CommandLine;
1930

2031
public class Launcher {
21-
22-
public static void main(String[] args) {
23-
CapabilityLoader capabilityLoader = new CapabilityLoader(Launcher.class.getModule().getLayer());
24-
// ProgressMonitor progressMonitor = new PrintStreamProgressMonitor(true);
25-
ProgressMonitor progressMonitor = new NullProgressMonitor(); // TODO configurable through system properties
2632

27-
// Sub-commands, sorting alphabetically
28-
List<CommandLine> rootCommands = new ArrayList<>();
29-
Requirement<SubCommandRequirement, CommandLine> subCommandRequirement = ServiceCapabilityFactory.createRequirement(CommandLine.class, null, new SubCommandRequirement(Collections.emptyList()));
30-
for (CapabilityProvider<Object> cp: capabilityLoader.load(subCommandRequirement, progressMonitor)) {
31-
cp.getPublisher().filter(Objects::nonNull).collectList().block().forEach(cmd -> rootCommands.add((CommandLine) cmd));
33+
private static final Logger LOGGER = LoggerFactory.getLogger(Launcher.class);
34+
35+
private static String getVersion() {
36+
Module module = Launcher.class.getModule();
37+
if (module == null) {
38+
return "(unknown)";
3239
}
3340

34-
// Executing the first one
35-
for (CommandLine rootCommand: rootCommands) {
36-
rootCommand.addSubcommand(new ShellCommand(rootCommand));
37-
int exitCode;
38-
try {
39-
exitCode = rootCommand.execute(args);
40-
} finally {
41-
if (rootCommand instanceof Closeable) {
42-
((Closeable) rootCommand).close(progressMonitor.split("Closing root command", 1));
41+
return module.getDescriptor().toNameAndVersion();
42+
}
43+
44+
public static void main(String[] args) {
45+
OpenTelemetry openTelemetry = GlobalOpenTelemetryCapabilityFactory.getGlobalOpenTelemetry();
46+
Tracer tracer = openTelemetry.getTracer(Launcher.class.getName(), getVersion());
47+
Attributes attributes = Attributes
48+
.builder()
49+
.put("arguments", args)
50+
.build();
51+
SpanBuilder spanBuilder = tracer.spanBuilder("Launcher").setAllAttributes(attributes);
52+
Span launcherSpan = TelemetryUtil.buildSpan(spanBuilder).startSpan();
53+
Integer exitCode = null;
54+
try (Scope scope = launcherSpan.makeCurrent()) {
55+
try (ProgressMonitor progressMonitor = new LoggerProgressMonitor(LOGGER)) { //TracerProgressMonitor(tracer, "Launcher");
56+
CapabilityLoader capabilityLoader = new CapabilityLoader(Launcher.class.getModule().getLayer());
57+
58+
// Sub-commands, sorting alphabetically
59+
List<CommandLine> rootCommands = new ArrayList<>();
60+
Requirement<SubCommandRequirement, CommandLine> subCommandRequirement = ServiceCapabilityFactory.createRequirement(CommandLine.class, null, new SubCommandRequirement(Collections.emptyList()));
61+
for (CapabilityProvider<Object> cp: capabilityLoader.load(subCommandRequirement, progressMonitor)) {
62+
cp.getPublisher().filter(Objects::nonNull).collectList().block().forEach(cmd -> rootCommands.add((CommandLine) cmd));
63+
}
64+
65+
// Executing the first one
66+
for (CommandLine rootCommand: rootCommands) {
67+
rootCommand.addSubcommand(new ShellCommand(rootCommand));
68+
try {
69+
exitCode = rootCommand.execute(args);
70+
launcherSpan.setAttribute("exit-code", exitCode);
71+
} finally {
72+
if (rootCommand instanceof Closeable) {
73+
((Closeable) rootCommand).close(progressMonitor.split("Closing root command", 1));
74+
}
75+
capabilityLoader.close(progressMonitor.split("Closing capability loader", 1));
76+
}
77+
}
78+
79+
if (exitCode == null) {
80+
throw new UnsupportedOperationException("There are no root commands");
4381
}
44-
capabilityLoader.close(progressMonitor.split("Closing capability loader", 1));
4582
}
46-
System.exit(exitCode);
83+
} catch (Exception e) {
84+
launcherSpan.recordException(e);
85+
launcherSpan.setStatus(StatusCode.ERROR);
86+
throw e;
87+
} finally {
88+
launcherSpan.end();
4789
}
48-
49-
throw new UnsupportedOperationException("There are no root commands");
50-
}
90+
System.exit(exitCode);
91+
}
5192

5293
}

0 commit comments

Comments
 (0)