Skip to content

Commit

Permalink
Build time analytics
Browse files Browse the repository at this point in the history
  • Loading branch information
brunobat committed Jun 16, 2023
1 parent ea080ad commit a8e053f
Show file tree
Hide file tree
Showing 70 changed files with 3,689 additions and 25 deletions.
5 changes: 5 additions & 0 deletions bom/application/pom.xml
Expand Up @@ -6568,6 +6568,11 @@
<artifactId>quarkus-devtools-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-analytics-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-apache-httpclient</artifactId>
Expand Down
24 changes: 24 additions & 0 deletions build-parent/pom.xml
Expand Up @@ -179,6 +179,10 @@
<gcf-invoker.version>1.1.1</gcf-invoker.version>
<!-- Jakarta JMS API -->
<jakarta.jms-api.version>3.1.0</jakarta.jms-api.version>

<!-- Quarkus Analytics -->
<properties-maven-plugin.version>1.1.0</properties-maven-plugin.version>
<quarkus.analytics.disabled>true</quarkus.analytics.disabled>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -431,6 +435,26 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>${properties-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>set-system-properties</goal>
</goals>
<configuration>
<properties>
<property>
<name>quarkus.analytics.disabled</name>
<value>${quarkus.analytics.disabled}</value>
</property>
</properties>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${version.surefire.plugin}</version>
Expand Down
@@ -1,6 +1,8 @@
package io.quarkus.deployment.pkg.builditem;

import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

import io.quarkus.builder.item.SimpleBuildItem;

Expand Down Expand Up @@ -54,5 +56,14 @@ public String getDistribution() {
public static GraalVMVersion unknown() {
return new GraalVMVersion("unknown", "unknown", -1, "unknown");
}

public Map<String, String> toMap() {
final Map<String, String> graalVMVersion = new HashMap<>();
graalVMVersion.put("graalvm.version.full", fullVersion);
graalVMVersion.put("graalvm.version.version", version);
graalVMVersion.put("graalvm.version.java", String.valueOf(javaVersion));
graalVMVersion.put("graalvm.version.distribution", distribution);
return graalVMVersion;
}
}
}
Expand Up @@ -191,7 +191,8 @@ public AugmentResult createProductionApplication() {
.map(a -> new ArtifactResult(a.getPath(), a.getType(), a.getMetadata()))
.collect(Collectors.toList()),
jarBuildItem != null ? jarBuildItem.toJarResult() : null,
nativeImageBuildItem != null ? nativeImageBuildItem.getPath() : null);
nativeImageBuildItem != null ? nativeImageBuildItem.getPath() : null,
nativeImageBuildItem != null ? nativeImageBuildItem.getGraalVMInfo().toMap() : Collections.emptyMap());
}

private void writeDebugSourceFile(BuildResult result) {
Expand Down
@@ -0,0 +1,34 @@
package io.quarkus.runtime;

import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;

/**
* Build time analytics configuration.
* This is a dummy config class to hide the warnings on the comment line.
* All properties in here are actually used in the build tools.
*/
@ConfigRoot(name = "analytics", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
public class BuildAnalyticsConfig {

/**
* If Build time analytics are disabled.
*/
@ConfigItem
public Optional<Boolean> disabled;

/**
* The Segment base URI.
*/
@ConfigItem
public Optional<String> uriBase;

/**
* The Timeout to send the build time analytics to segment.
*/
@ConfigItem(defaultValue = "3000")
public Optional<Integer> timeout;
}
1 change: 1 addition & 0 deletions devtools/gradle/gradle-application-plugin/build.gradle.kts
Expand Up @@ -4,6 +4,7 @@ plugins {

dependencies {
implementation(libs.smallrye.config.yaml)
implementation("io.quarkus:quarkus-analytics-common")

testImplementation(libs.quarkus.project.core.extension.codestarts)
}
Expand Down
4 changes: 4 additions & 0 deletions devtools/gradle/gradle-application-plugin/pom.xml
Expand Up @@ -36,6 +36,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-devtools-common</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-analytics-common</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-project-core-extension-codestarts</artifactId>
Expand Down
@@ -0,0 +1,85 @@
package io.quarkus.gradle;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;

import org.aesh.readline.Readline;
import org.aesh.readline.ReadlineBuilder;
import org.aesh.readline.tty.terminal.TerminalConnection;
import org.aesh.terminal.tty.Signal;

/**
* Prompt implementation.
*
* @author <a href="http://escoffier.me">Clement Escoffier</a>
*/
public class Prompter {

private static class Prompt {
private final String prompt;
private final String defaultValue;
private final Consumer<String> inputConsumer;

public Prompt(String prompt, String defaultValue, Consumer<String> inputConsumer) {
this.prompt = prompt;
this.defaultValue = defaultValue;
this.inputConsumer = inputConsumer;
}
}

private final List<Prompt> prompts = new ArrayList<>();

public Prompter() throws IOException {
}

public Prompter addPrompt(String prompt, Consumer<String> inputConsumer) {
prompts.add(new Prompt(prompt, null, inputConsumer));
return this;
}

public Prompter addPrompt(String prompt, String defaultValue, Consumer<String> inputConsumer) {
prompts.add(new Prompt(prompt, defaultValue, inputConsumer));
return this;
}

public void collectInput() throws IOException {
if (prompts.isEmpty()) {
return;
}
final TerminalConnection connection = new TerminalConnection();
connection.setSignalHandler(interruptionSignalHandler());
try {
read(connection, ReadlineBuilder.builder().enableHistory(false).build(), prompts.iterator());
connection.openBlocking();
} finally {
connection.close();
}
}

private static void read(TerminalConnection connection, Readline readline, Iterator<Prompt> prompts) {
final Prompt prompt = prompts.next();
readline.readline(connection, prompt.prompt, input -> {
prompt.inputConsumer.accept(
(input == null || input.isBlank()) && prompt.defaultValue != null ? prompt.defaultValue : input);
if (!prompts.hasNext()) {
connection.close();
} else {
read(connection, readline, prompts);
}
});
}

private Consumer<Signal> interruptionSignalHandler() {
return new Consumer<Signal>() {
@Override
public void accept(Signal signal) {
if (signal == Signal.INT) {
throw new RuntimeException("Process interrupted");
}
}
};
}
}
Expand Up @@ -225,7 +225,8 @@ public boolean isSatisfiedBy(Task t) {

tasks.register(DEPLOY_TASK_NAME, Deploy.class, task -> task.finalizedBy(quarkusBuild));

TaskProvider<QuarkusDev> quarkusDev = tasks.register(QUARKUS_DEV_TASK_NAME, QuarkusDev.class, devRuntimeDependencies,
TaskProvider<QuarkusDev> quarkusDev = tasks.register(QUARKUS_DEV_TASK_NAME, QuarkusDev.class,
devRuntimeDependencies,
quarkusExt);
TaskProvider<QuarkusRun> quarkusRun = tasks.register(QUARKUS_RUN_TASK_NAME, QuarkusRun.class);
TaskProvider<QuarkusRemoteDev> quarkusRemoteDev = tasks.register(QUARKUS_REMOTE_DEV_TASK_NAME, QuarkusRemoteDev.class,
Expand Down
Expand Up @@ -222,6 +222,7 @@ void generateBuild() {
params.getBaseName().set(extension().finalName());
params.getTargetDirectory().set(buildDir.toFile());
params.getAppModel().set(appModel);
params.getGradleVersion().set(getProject().getGradle().getGradleVersion());
});

workQueue.await();
Expand Down
@@ -1,5 +1,9 @@
package io.quarkus.gradle.tasks;

import static io.quarkus.analytics.dto.segment.ContextBuilder.CommonSystemProperties.GRADLE_VERSION;
import static io.quarkus.analytics.dto.segment.TrackEventType.*;
import static java.util.Collections.*;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
Expand All @@ -15,6 +19,7 @@
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

import javax.inject.Inject;

Expand Down Expand Up @@ -52,6 +57,8 @@
import org.gradle.jvm.toolchain.JavaToolchainSpec;
import org.gradle.util.GradleVersion;

import io.quarkus.analytics.AnalyticsService;
import io.quarkus.analytics.config.FileLocationsImpl;
import io.quarkus.bootstrap.BootstrapConstants;
import io.quarkus.bootstrap.app.ConfiguredClassLoading;
import io.quarkus.bootstrap.app.QuarkusBootstrap;
Expand All @@ -63,6 +70,7 @@
import io.quarkus.deployment.dev.DevModeContext;
import io.quarkus.deployment.dev.DevModeMain;
import io.quarkus.deployment.dev.QuarkusDevModeLauncher;
import io.quarkus.gradle.Prompter;
import io.quarkus.gradle.dependency.ApplicationDeploymentClasspathBuilder;
import io.quarkus.gradle.dsl.CompilerOption;
import io.quarkus.gradle.dsl.CompilerOptions;
Expand Down Expand Up @@ -314,9 +322,23 @@ public void startDev() {
"this should not happen as build should have been executed first. " +
"Does the project have any source files?");
}
AnalyticsService analyticsService = new AnalyticsService(FileLocationsImpl.INSTANCE,
new GradleMessageWriter(getLogger()));
analyticsService.buildAnalyticsUserInput((String prompt) -> {
try {
final AtomicReference<String> userInput = new AtomicReference<>("");
final Prompter prompter = new Prompter();
prompter.addPrompt(prompt, input -> userInput.set(input));
prompter.collectInput();
return userInput.get();
} catch (IOException e) {
getLogger().debug("Failed to collect user input for analytics", e);
return "";
}
});

try {
QuarkusDevModeLauncher runner = newLauncher();
QuarkusDevModeLauncher runner = newLauncher(analyticsService);
String outputFile = System.getProperty(IO_QUARKUS_DEVMODE_ARGS);
if (outputFile == null) {
getProject().exec(action -> {
Expand All @@ -337,6 +359,8 @@ public void startDev() {

} catch (Exception e) {
throw new GradleException("Failed to run", e);
} finally {
analyticsService.cleanup();
}
}

Expand Down Expand Up @@ -364,7 +388,7 @@ private boolean classesExist() {
return false;
}

private QuarkusDevModeLauncher newLauncher() throws Exception {
private QuarkusDevModeLauncher newLauncher(final AnalyticsService analyticsService) throws Exception {
final Project project = getProject();
final JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);

Expand Down Expand Up @@ -420,6 +444,13 @@ private QuarkusDevModeLauncher newLauncher() throws Exception {
builder.sourceEncoding(getSourceEncoding());

final ApplicationModel appModel = extension().getApplicationModel(LaunchMode.DEVELOPMENT);

analyticsService.sendAnalytics(
DEV_MODE,
appModel,
Map.of(GRADLE_VERSION, getProject().getGradle().getGradleVersion()),
getProject().getBuildDir().getAbsoluteFile());

final Set<ArtifactKey> projectDependencies = new HashSet<>();
for (ResolvedDependency localDep : DependenciesFilter.getReloadableModules(appModel)) {
addLocalProject(localDep, builder, projectDependencies, appModel.getAppArtifact().getWorkspaceModule().getId()
Expand Down
Expand Up @@ -110,6 +110,7 @@ public void generateCode() {
.setFrom(sourcesDirectories.stream().map(Path::toFile).collect(Collectors.toList()));
params.getOutputPath().set(outputPath);
params.getLaunchMode().set(launchMode);
params.getGradleVersion().set(getProject().getGradle().getGradleVersion());
});

workQueue.await();
Expand Down

0 comments on commit a8e053f

Please sign in to comment.