diff --git a/example/build.gradle.kts b/example/build.gradle.kts index cadad78..9cb5d7d 100644 --- a/example/build.gradle.kts +++ b/example/build.gradle.kts @@ -6,5 +6,4 @@ plugins { tracks { automatticProject.set(io.github.wzieba.tracks.plugin.TracksExtension.AutomatticProject.WooCommerce) enabled.set(true) - customEventName.set("test_gradle_plugin") } diff --git a/example/gradle.properties b/example/gradle.properties new file mode 100644 index 0000000..3fec180 --- /dev/null +++ b/example/gradle.properties @@ -0,0 +1 @@ +appsMetricsToken = foobar \ No newline at end of file diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildReporter.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildReporter.kt index db7d85f..7b3e1e7 100644 --- a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildReporter.kt +++ b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildReporter.kt @@ -12,30 +12,26 @@ class BuildReporter( ) { @Suppress("TooGenericExceptionCaught") - fun report(buildData: BuildData, username: String?, customEventName: String?) { + fun report(buildData: BuildData, username: String) { try { - reportMeasured(buildData, username, customEventName) + reportMeasured(buildData, username) } catch (ex: Exception) { logger.warn("$FAILURE_ICON Build time reporting failed: $ex") } } - private fun reportMeasured(buildData: BuildData, username: String?, customEventName: String?) { + private fun reportMeasured(buildData: BuildData, username: String) { val start = nowMillis() - reportInternal(buildData, username, customEventName) + reportInternal(buildData, username) val reportingOverhead = nowMillis() - start logger.info("Reporting overhead: $reportingOverhead ms.") } - private fun reportInternal( - buildData: BuildData, - username: String?, - customEventName: String?, - ) { + private fun reportInternal(buildData: BuildData, username: String) { runBlocking { - analyticsReporter.report(logger, buildData, username, customEventName) + analyticsReporter.report(logger, buildData, username) } } diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildTimeListener.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildTimeListener.kt index 29b0a75..fe825bc 100644 --- a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildTimeListener.kt +++ b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildTimeListener.kt @@ -1,5 +1,6 @@ package io.github.wzieba.tracks.plugin +import org.codehaus.groovy.runtime.EncodingGroovyMethods import org.gradle.BuildListener import org.gradle.BuildResult import org.gradle.api.initialization.IncludedBuild @@ -31,11 +32,13 @@ internal class BuildTimeListener( tracksExtension.automatticProject.get(), includedBuilds.map(IncludedBuild::getName) ) + val encodedUser = System.getProperty("user.name")?.let { + EncodingGroovyMethods.digest(it, "SHA-1") + } buildReporter.report( buildData, - tracksExtension.username.orNull, - tracksExtension.customEventName.orNull, + encodedUser.orEmpty() ) } } diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildTimePlugin.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildTimePlugin.kt index 7cef2ba..6f6de46 100644 --- a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildTimePlugin.kt +++ b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/BuildTimePlugin.kt @@ -1,6 +1,6 @@ package io.github.wzieba.tracks.plugin -import io.github.wzieba.tracks.plugin.analytics.networking.TracksReporter +import io.github.wzieba.tracks.plugin.analytics.networking.AppsMetricsReporter import org.gradle.api.Plugin import org.gradle.api.Project import kotlin.time.ExperimentalTime @@ -14,7 +14,7 @@ abstract class BuildTimePlugin : Plugin { val buildTimeListener = BuildTimeListener( buildDataFactory = BuildDataFactory, - buildReporter = BuildReporter(project.logger, TracksReporter()), + buildReporter = BuildReporter(project.logger, AppsMetricsReporter(project)), tracksExtension = extension, includedBuilds = project.gradle.includedBuilds ) diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/TracksExtension.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/TracksExtension.kt index 3fb9306..4b45f82 100644 --- a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/TracksExtension.kt +++ b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/TracksExtension.kt @@ -2,7 +2,6 @@ package io.github.wzieba.tracks.plugin import org.gradle.api.Project import org.gradle.api.provider.Property -import org.gradle.api.tasks.Optional import javax.inject.Inject @Suppress("UnnecessaryAbstractClass") @@ -14,12 +13,6 @@ abstract class TracksExtension @Inject constructor(project: Project) { val enabled: Property = objects.property(Boolean::class.java) - @Optional - val username: Property = objects.property(String::class.java) - - @Optional - val customEventName: Property = objects.property(String::class.java) - enum class AutomatticProject { WooCommerce, WordPress, DayOne } diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/AnalyticsReporter.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/AnalyticsReporter.kt index 3f78446..c24a984 100644 --- a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/AnalyticsReporter.kt +++ b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/AnalyticsReporter.kt @@ -7,7 +7,6 @@ interface AnalyticsReporter { suspend fun report( logger: Logger, event: BuildData, - username: String?, - customEventName: String?, + user: String, ) } diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/AppsMetricsGroupedMetrics.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/AppsMetricsGroupedMetrics.kt new file mode 100644 index 0000000..ffa1e9e --- /dev/null +++ b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/AppsMetricsGroupedMetrics.kt @@ -0,0 +1,20 @@ +package io.github.wzieba.tracks.plugin.analytics.networking + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class GroupedAppsMetrics( + @SerialName("meta") + val meta: List, + @SerialName("metrics") + val metrics: List, +) + +@Serializable +data class AppsMetric( + @SerialName("name") + val name: String, + @SerialName("value") + val value: String, +) diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/TracksReporter.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/AppsMetricsReporter.kt similarity index 70% rename from plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/TracksReporter.kt rename to plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/AppsMetricsReporter.kt index 4aa7e55..35cfc1f 100644 --- a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/TracksReporter.kt +++ b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/AppsMetricsReporter.kt @@ -15,21 +15,29 @@ import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.HttpStatement import io.ktor.http.ContentType import io.ktor.http.HttpHeaders +import io.ktor.http.HttpHeaders.Authorization import io.ktor.http.HttpStatusCode import io.ktor.http.contentType +import org.gradle.api.Project import org.gradle.api.logging.Logger import java.util.Locale import java.util.concurrent.TimeUnit.MILLISECONDS import java.util.concurrent.TimeUnit.MINUTES -class TracksReporter : AnalyticsReporter { +class AppsMetricsReporter(private val project: Project) : AnalyticsReporter { override suspend fun report( logger: Logger, event: BuildData, - username: String?, - customEventName: String?, + user: String, ) { + val authToken: String? = project.properties["appsMetricsToken"] as String? + + if (authToken.isNullOrBlank()) { + logger.warn("Did not find appsMetricsToken in gradle.properties. Skipping reporting.") + return + } + logger.debug("Reporting $event") val client = HttpClient(CIO) { @@ -46,26 +54,34 @@ class TracksReporter : AnalyticsReporter { } } - client.post("https://public-api.wordpress.com/rest/v1.1/tracks/record") { + client.post("https://seal-app-e8plp.ondigitalocean.app/api/grouped-metrics") { headers { append(HttpHeaders.UserAgent, "Gradle") + append(Authorization, "Bearer $authToken") } contentType(ContentType.Application.Json) - body = event.toTracksPayload(customEventName, username) + body = event.toAppsInfraPayload(user) }.execute { response: HttpResponse -> logger.debug(response.toString()) when (response.status) { - HttpStatusCode.Accepted -> { + HttpStatusCode.Created -> { val buildTime = event.buildTime val timeFormatted = String.format( Locale.US, "%dm %ds", MILLISECONDS.toMinutes(buildTime), - MILLISECONDS.toSeconds(buildTime) - MINUTES.toSeconds(MILLISECONDS.toMinutes(buildTime)) + MILLISECONDS.toSeconds(buildTime) - MINUTES.toSeconds( + MILLISECONDS.toMinutes( + buildTime + ) + ) + ) + logger.lifecycle( + "$SUCCESS_ICON Build time report of $timeFormatted has been received by App Metrics." ) - logger.lifecycle("$SUCCESS_ICON Build time report of $timeFormatted has been received by Tracks.") } + else -> { logger.warn( "$FAILURE_ICON Build time has not been uploaded. Add `debug` property to see more logs." diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/ToAppsInfraPayload.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/ToAppsInfraPayload.kt new file mode 100644 index 0000000..0389fc0 --- /dev/null +++ b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/ToAppsInfraPayload.kt @@ -0,0 +1,103 @@ +package io.github.wzieba.tracks.plugin.analytics.networking + +import io.github.wzieba.tracks.plugin.BuildData + +@Suppress("LongMethod") +fun BuildData.toAppsInfraPayload(user: String) = GroupedAppsMetrics( + meta = listOf( + AppsMetric( + name = "User", + value = user + ), + AppsMetric( + name = "Project", + value = this.forProject.name + ) + ), + metrics = listOf( + AppsMetric( + name = "Requested tasks", + value = this.tasks.joinToString(separator = ",") + ), + AppsMetric( + name = "Performed Gradle action", + value = this.action + ), + AppsMetric( + name = "Build time (ms)", + value = this.buildTime.toString() + ), + AppsMetric( + name = "Build status", + value = if (this.failed) "Failure" else "Success" + ), + AppsMetric( + name = "Failure message", + value = this.failure.toString() + ), + AppsMetric( + name = "Number of running daemons", + value = this.daemonsRunning.toString() + ), + AppsMetric( + name = "Daemon's build count", + value = this.thisDaemonBuilds.toString() + ), + AppsMetric( + name = "Gradle version", + value = this.gradleVersion + ), + AppsMetric( + name = "Operating system", + value = this.operatingSystem + ), + AppsMetric( + name = "Environment", + value = this.environment.toString() + ), + AppsMetric( + name = "Total number of tasks", + value = this.taskStatistics.total.toString() + ), + AppsMetric( + name = "Up to date tasks", + value = this.taskStatistics.upToDate.toString() + ), + AppsMetric( + name = "Tasks from cache", + value = this.taskStatistics.fromCache.toString() + ), + AppsMetric( + name = "Executed tasks", + value = this.taskStatistics.executed.toString() + ), + AppsMetric( + name = "Is configure on demand", + value = this.isConfigureOnDemand.toString() + ), + AppsMetric( + name = "Is configuration cache", + value = this.isConfigurationCache.toString() + ), + AppsMetric( + name = "Is build cache", + value = this.isBuildCache.toString() + ), + AppsMetric( + name = "Max workers", + value = this.maxWorkers.toString() + ), + AppsMetric( + name = "Build data collection overhead", + value = this.buildDataCollectionOverhead.toString() + ), + AppsMetric( + name = "Included builds", + value = this.includedBuildsNames.joinToString(separator = ",").ifEmpty { "none" } + ), + AppsMetric( + name = "Architecture", + value = this.architecture + ), + ) +) diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/ToNosaraPayload.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/ToNosaraPayload.kt deleted file mode 100644 index 3456a65..0000000 --- a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/ToNosaraPayload.kt +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.wzieba.tracks.plugin.analytics.networking - -import io.github.wzieba.tracks.plugin.BuildData -import io.github.wzieba.tracks.plugin.TracksExtension - -fun BuildData.toTracksPayload(customEventName: String?, username: String?) = TracksPayload( - events = listOf( - Event( - eventName = customEventName ?: this.forProject.toEventName(), - eventTimestamp = System.currentTimeMillis(), - tasks = this.tasks, - gradleAction = this.action, - buildTime = this.buildTime, - failed = this.failed, - failure = this.failure?.message, - daemonsRunning = this.daemonsRunning, - thisDaemonBuilds = this.thisDaemonBuilds, - gradleVersion = this.gradleVersion, - operatingSystem = this.operatingSystem, - environment = this.environment, - tasksTotal = this.taskStatistics.total, - tasksUpToDate = this.taskStatistics.upToDate, - tasksFromCache = this.taskStatistics.fromCache, - tasksExecuted = this.taskStatistics.executed, - isConfigureOnDemand = this.isConfigureOnDemand, - isConfigurationCache = this.isConfigurationCache, - isBuildCache = this.isBuildCache, - maxWorkers = this.maxWorkers, - includedBuilds = this.includedBuildsNames, - userType = "anon", - userId = -1, // Tracks require a non-null user id - username = username, - architecture = this.architecture, - ) - ) -) - -private fun TracksExtension.AutomatticProject.toEventName() = when (this) { - TracksExtension.AutomatticProject.WooCommerce -> "woocommerceandroid_gradle_build_finished" - TracksExtension.AutomatticProject.WordPress -> "wpandroid_gradle_build_finished" - TracksExtension.AutomatticProject.DayOne -> "dayone_gradle_build_finished" -} diff --git a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/TracksPayload.kt b/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/TracksPayload.kt deleted file mode 100644 index 87c1dd8..0000000 --- a/plugin-build/plugin/src/main/java/io/github/wzieba/tracks/plugin/analytics/networking/TracksPayload.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.wzieba.tracks.plugin.analytics.networking - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class TracksPayload( - @SerialName("events") - val events: List, -)