diff --git a/adoptopenjdk-api-v3-frontend/pom.xml b/adoptopenjdk-api-v3-frontend/pom.xml index 5c4446ef..078f0bc5 100644 --- a/adoptopenjdk-api-v3-frontend/pom.xml +++ b/adoptopenjdk-api-v3-frontend/pom.xml @@ -117,6 +117,11 @@ jackson-datatype-jsr353 test + + com.microsoft.azure + applicationinsights-core + 2.6.2-BETA + diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/metrics/AppInsightsInterceptor.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/metrics/AppInsightsInterceptor.kt new file mode 100644 index 00000000..f89af2d5 --- /dev/null +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/metrics/AppInsightsInterceptor.kt @@ -0,0 +1,118 @@ +package net.adoptopenjdk.api.v3.metrics + +import com.microsoft.applicationinsights.TelemetryClient +import com.microsoft.applicationinsights.telemetry.RequestTelemetry +import org.eclipse.microprofile.metrics.annotation.Timed +import java.io.File +import java.io.FileOutputStream +import java.nio.file.Files +import java.nio.file.Path +import java.util.* +import javax.annotation.Priority +import javax.interceptor.AroundInvoke +import javax.interceptor.Interceptor +import javax.interceptor.InvocationContext +import javax.ws.rs.WebApplicationException +import javax.ws.rs.core.Response + +@Timed +@Suppress("unused") +@Interceptor +@Priority(Interceptor.Priority.LIBRARY_BEFORE + 10) +class AppInsightsInterceptor { + private val telemetryClient: TelemetryClient + + init { + telemetryClient = loadTelemetryClient() + } + + private fun loadTelemetryClient(): TelemetryClient { + val path = saveConfigToFile() + try { + return TelemetryClient() + } finally { + val tmpDir = System.getProperty("java.io.tmpdir") + val isTmpDir = path?.startsWith(tmpDir) + if (isTmpDir != null && isTmpDir) { + path.toFile().deleteRecursively() + } + } + } + + // Unfortunate hack to get around that we seem unable to load ApplicationInsights.xml from the classpath + // from inside the module + private fun saveConfigToFile(): Path? { + val inputStream = AppInsightsInterceptor::class.java.classLoader.getResourceAsStream("ApplicationInsights.xml") + + inputStream?.use { + val configPath = Files.createTempDirectory("appInsightsConfig").toAbsolutePath() + val configFile = File(configPath.toString(), "ApplicationInsights.xml") + configFile.deleteOnExit() + configPath.toFile().deleteOnExit() + System.setProperty("applicationinsights.configurationDirectory", configPath.toString()) + + val outputStream = FileOutputStream(configFile) + + outputStream.use { fileOut -> + inputStream.copyTo(fileOut) + } + + return configPath + } + return null + } + + @AroundInvoke + @Throws(Exception::class) + fun timedMethod(context: InvocationContext): Any? { + var response: Any? = null + var success = true + var status = 200 + var exception: Throwable? = null + + val methodName = context.method.toGenericString() + val start = System.nanoTime() + try { + response = context.proceed() + when (response) { + null -> { + status = 404 + success = false + } + is Response -> { + status = response.status + success = response.status < 400 + } + else -> { + status = 200 + success = true + } + } + } catch (e: Throwable) { + exception = e + success = false + status = if (e is WebApplicationException) { + e.response.status + } else { + 500 + } + } finally { + try { + val duration = (System.nanoTime() - start) / 1000000 + val requestTelemetry = RequestTelemetry( + methodName, + Date(), + duration, + status.toString(), + success + ) + telemetryClient.trackRequest(requestTelemetry) + } finally { + if (exception != null) { + throw exception + } + return response + } + } + } +} diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/AssetsResource.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/AssetsResource.kt index 61b656bc..9c44bb61 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/AssetsResource.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/AssetsResource.kt @@ -20,6 +20,7 @@ import net.adoptopenjdk.api.v3.models.Project import net.adoptopenjdk.api.v3.models.Release import net.adoptopenjdk.api.v3.models.ReleaseType import net.adoptopenjdk.api.v3.models.Vendor +import org.eclipse.microprofile.metrics.annotation.Timed import org.eclipse.microprofile.openapi.annotations.Operation import org.eclipse.microprofile.openapi.annotations.enums.SchemaType import org.eclipse.microprofile.openapi.annotations.media.Content @@ -47,6 +48,7 @@ import javax.ws.rs.core.MediaType @Tag(name = "Assets") @Path("/v3/assets/") @Produces(MediaType.APPLICATION_JSON) +@Timed class AssetsResource { @GET diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/V1Route.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/V1Route.kt index 3c4525de..05d40dc9 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/V1Route.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/V1Route.kt @@ -1,5 +1,6 @@ package net.adoptopenjdk.api.v3.routes +import org.eclipse.microprofile.metrics.annotation.Timed import org.eclipse.microprofile.openapi.annotations.Operation import org.eclipse.microprofile.openapi.annotations.media.Schema import javax.ws.rs.GET @@ -11,6 +12,7 @@ import javax.ws.rs.core.Response @Path("/v1/") @Schema(hidden = true) @Produces(MediaType.TEXT_PLAIN) +@Timed class V1Route { // Cant find a way to match nothing and something in the same request, so need 2 diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/VersionResource.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/VersionResource.kt index b4952d78..e7e4c78f 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/VersionResource.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/VersionResource.kt @@ -3,6 +3,7 @@ package net.adoptopenjdk.api.v3.routes import net.adoptopenjdk.api.v3.models.VersionData import net.adoptopenjdk.api.v3.parser.FailedToParse import net.adoptopenjdk.api.v3.parser.VersionParser +import org.eclipse.microprofile.metrics.annotation.Timed import org.eclipse.microprofile.openapi.annotations.Operation import org.eclipse.microprofile.openapi.annotations.parameters.Parameter import org.eclipse.microprofile.openapi.annotations.responses.APIResponse @@ -18,6 +19,7 @@ import javax.ws.rs.core.MediaType @Tag(name = "Version") @Path("/v3/version/") @Produces(MediaType.APPLICATION_JSON) +@Timed class VersionResource { @GET diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/AvailableReleasesResource.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/AvailableReleasesResource.kt index 2f3a8a16..a68a3951 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/AvailableReleasesResource.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/AvailableReleasesResource.kt @@ -2,6 +2,7 @@ package net.adoptopenjdk.api.v3.routes.info import net.adoptopenjdk.api.v3.dataSources.APIDataStore import net.adoptopenjdk.api.v3.models.ReleaseInfo +import org.eclipse.microprofile.metrics.annotation.Timed import org.eclipse.microprofile.openapi.annotations.Operation import org.eclipse.microprofile.openapi.annotations.tags.Tag import javax.ws.rs.GET @@ -12,6 +13,7 @@ import javax.ws.rs.core.MediaType @Tag(name = "Release Info") @Path("/v3/info/") @Produces(MediaType.APPLICATION_JSON) +@Timed class AvailableReleasesResource { @GET @Path("/available_releases/") diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/PlatformsResource.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/PlatformsResource.kt index a172eb69..0508303b 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/PlatformsResource.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/PlatformsResource.kt @@ -2,6 +2,7 @@ package net.adoptopenjdk.api.v3.routes.info import net.adoptopenjdk.api.v3.dataSources.APIDataStore import net.adoptopenjdk.api.v3.models.Platforms +import org.eclipse.microprofile.metrics.annotation.Timed import org.eclipse.microprofile.openapi.annotations.Operation import org.eclipse.microprofile.openapi.annotations.tags.Tag import javax.ws.rs.GET @@ -12,6 +13,7 @@ import javax.ws.rs.core.MediaType @Tag(name = "Release Info") @Path("/v3/info/") @Produces(MediaType.APPLICATION_JSON) +@Timed class PlatformsResource { @GET diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/ReleaseListResource.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/ReleaseListResource.kt index edc32521..b700e18f 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/ReleaseListResource.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/ReleaseListResource.kt @@ -12,6 +12,7 @@ import net.adoptopenjdk.api.v3.models.ReleaseList import net.adoptopenjdk.api.v3.models.ReleaseType import net.adoptopenjdk.api.v3.models.ReleaseVersionList import net.adoptopenjdk.api.v3.models.Vendor +import org.eclipse.microprofile.metrics.annotation.Timed import org.eclipse.microprofile.openapi.annotations.Operation import org.eclipse.microprofile.openapi.annotations.enums.SchemaType import org.eclipse.microprofile.openapi.annotations.media.Schema @@ -26,6 +27,7 @@ import javax.ws.rs.core.MediaType @Tag(name = "Release Info") @Path("/v3/info") @Produces(MediaType.APPLICATION_JSON) +@Timed class ReleaseListResource { @GET diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/VariantsResource.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/VariantsResource.kt index 2d017356..bc8b0efa 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/VariantsResource.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/info/VariantsResource.kt @@ -2,6 +2,7 @@ package net.adoptopenjdk.api.v3.routes.info import net.adoptopenjdk.api.v3.dataSources.APIDataStore import net.adoptopenjdk.api.v3.models.Variants +import org.eclipse.microprofile.metrics.annotation.Timed import org.eclipse.microprofile.openapi.annotations.Operation import org.eclipse.microprofile.openapi.annotations.tags.Tag import javax.ws.rs.GET @@ -12,6 +13,7 @@ import javax.ws.rs.core.MediaType @Tag(name = "Release Info") @Path("/v3/info") @Produces(MediaType.APPLICATION_JSON) +@Timed class VariantsResource { @GET diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/stats/DownloadStatsResource.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/stats/DownloadStatsResource.kt index 1af20824..6f2deb54 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/stats/DownloadStatsResource.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/stats/DownloadStatsResource.kt @@ -10,6 +10,7 @@ import net.adoptopenjdk.api.v3.models.Release import net.adoptopenjdk.api.v3.models.ReleaseType import net.adoptopenjdk.api.v3.models.StatsSource import net.adoptopenjdk.api.v3.models.Vendor +import org.eclipse.microprofile.metrics.annotation.Timed import org.eclipse.microprofile.openapi.annotations.Operation import org.eclipse.microprofile.openapi.annotations.enums.SchemaType import org.eclipse.microprofile.openapi.annotations.media.Schema @@ -29,6 +30,7 @@ import javax.ws.rs.core.Response @Path("/v3/stats/downloads") @Produces(MediaType.APPLICATION_JSON) @Schema(hidden = true) +@Timed class DownloadStatsResource { private val statsInterface = net.adoptopenjdk.api.v3.DownloadStatsInterface() diff --git a/adoptopenjdk-api-v3-frontend/src/main/resources/ApplicationInsights.xml b/adoptopenjdk-api-v3-frontend/src/main/resources/ApplicationInsights.xml new file mode 100644 index 00000000..7916c40a --- /dev/null +++ b/adoptopenjdk-api-v3-frontend/src/main/resources/ApplicationInsights.xml @@ -0,0 +1,6 @@ + + + + true + + diff --git a/adoptopenjdk-api-v3-frontend/src/main/resources/application.properties b/adoptopenjdk-api-v3-frontend/src/main/resources/application.properties index 9989442e..41aa9cbe 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/resources/application.properties +++ b/adoptopenjdk-api-v3-frontend/src/main/resources/application.properties @@ -10,3 +10,5 @@ quarkus.log.console.enable=true quarkus.log.file.enable=true vertx.disableFileCPResolving=true + +quarkus.smallrye-metrics.path=/v2/metrics diff --git a/pom.xml b/pom.xml index 7b22fe75..fad6eede 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ 11 UTF-8 UTF-8 - 1.4.1.Final + 1.6.1.Final 3.0.0-M3