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