diff --git a/docs/metrics.mdx b/docs/metrics.mdx index 1d3104818..2a22696d9 100644 --- a/docs/metrics.mdx +++ b/docs/metrics.mdx @@ -15,6 +15,15 @@ These are stored using the following keys: - `builds/d/YYYY-MM-DD` - `builds/o/` - `builds/o//d/YYYY-MM-DD` +- `pulls/a//d/YYYY-MM-DD` +- `pulls/o//a/` +- `pulls/o//a//d/YYYY-MM-DD` +- `fusion/a//d/YYYY-MM-DD` +- `fusion/o//a/` +- `fusion/o//a//d/YYYY-MM-DD` +- `builds/a//d/YYYY-MM-DD` +- `builds/o//a/` +- `builds/o//a//d/YYYY-MM-DD` ## Functionality diff --git a/src/main/groovy/io/seqera/wave/controller/MetricsController.groovy b/src/main/groovy/io/seqera/wave/controller/MetricsController.groovy index f8008674e..3e42c4cfa 100644 --- a/src/main/groovy/io/seqera/wave/controller/MetricsController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/MetricsController.groovy @@ -18,7 +18,6 @@ package io.seqera.wave.controller -import java.util.regex.Pattern import javax.annotation.Nullable import groovy.transform.CompileStatic @@ -35,10 +34,8 @@ import io.micronaut.scheduling.annotation.ExecuteOn import io.micronaut.security.annotation.Secured import io.micronaut.security.authentication.AuthorizationException import io.micronaut.security.rules.SecurityRule -import io.seqera.wave.exception.BadRequestException import io.seqera.wave.service.metric.MetricsConstants import io.seqera.wave.service.metric.MetricsService - import jakarta.inject.Inject import static io.micronaut.http.HttpHeaders.WWW_AUTHENTICATE @@ -58,49 +55,83 @@ class MetricsController { @Inject private MetricsService metricsService - static final private Pattern DATE_PATTERN = Pattern.compile("\\d{4}-\\d{2}-\\d{2}"); - + @Deprecated @Get(uri = "/v1alpha2/metrics/builds", produces = MediaType.APPLICATION_JSON) HttpResponse getBuildsMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org) { if(!date && !org) return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_BUILDS)) - validateQueryParams(date) return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_BUILDS, date, org)) } + @Deprecated @Get(uri = "/v1alpha2/metrics/pulls", produces = MediaType.APPLICATION_JSON) HttpResponse getPullsMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org) { if(!date && !org) return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_PULLS)) - validateQueryParams(date) return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_PULLS, date, org)) } + @Deprecated @Get(uri = "/v1alpha2/metrics/fusion/pulls", produces = MediaType.APPLICATION_JSON) HttpResponse getFusionPullsMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org) { if(!date && !org) return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_FUSION)) - validateQueryParams(date) return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_FUSION, date, org)) } + @Deprecated @Get(uri = "/v1alpha2/metrics/mirrors", produces = MediaType.APPLICATION_JSON) HttpResponse getMirrorsMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org) { if(!date && !org) return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_MIRRORS)) - validateQueryParams(date) return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_MIRRORS, date, org)) } + @Deprecated @Get(uri = "/v1alpha2/metrics/scans", produces = MediaType.APPLICATION_JSON) HttpResponse getScansMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org) { if(!date && !org) return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_SCANS)) - validateQueryParams(date) return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_SCANS, date, org)) } + @Get(uri = "/v1alpha3/metrics/builds", produces = MediaType.APPLICATION_JSON) + HttpResponse getBuildsMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org, @Nullable @QueryValue String arch) { + if(!date && !org) + return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_BUILDS, arch)) + return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_BUILDS, date, org, arch)) + } + + @Get(uri = "/v1alpha3/metrics/pulls", produces = MediaType.APPLICATION_JSON) + HttpResponse getPullsMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org, @Nullable @QueryValue String arch) { + if(!date && !org) + return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_PULLS, arch)) + return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_PULLS, date, org, arch)) + } + + @Get(uri = "/v1alpha3/metrics/fusion/pulls", produces = MediaType.APPLICATION_JSON) + HttpResponse getFusionPullsMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org, @Nullable @QueryValue String arch) { + if(!date && !org) + return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_FUSION, arch)) + return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_FUSION, date, org, arch)) + + } + + @Get(uri = "/v1alpha3/metrics/mirrors", produces = MediaType.APPLICATION_JSON) + HttpResponse getMirrorsMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org, @Nullable @QueryValue String arch) { + if(!date && !org) + return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_MIRRORS, arch)) + return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_MIRRORS, date, org, arch)) + } + + @Get(uri = "/v1alpha3/metrics/scans", produces = MediaType.APPLICATION_JSON) + HttpResponse getScansMetrics(@Nullable @QueryValue String date, @Nullable @QueryValue String org, @Nullable @QueryValue String arch) { + if(!date && !org) + return HttpResponse.ok(metricsService.getAllOrgCount(MetricsConstants.PREFIX_SCANS, arch)) + return HttpResponse.ok(metricsService.getOrgCount(MetricsConstants.PREFIX_SCANS, date, org, arch)) + } + @Error(exception = AuthorizationException.class) HttpResponse handleAuthorizationException() { @@ -108,9 +139,4 @@ class MetricsController { .header(WWW_AUTHENTICATE, "Basic realm=Wave Authentication") } - static void validateQueryParams(String date) { - if(date && !DATE_PATTERN.matcher(date).matches()) { - throw new BadRequestException('date format should be yyyy-MM-dd') - } - } } diff --git a/src/main/groovy/io/seqera/wave/core/ContainerPlatform.groovy b/src/main/groovy/io/seqera/wave/core/ContainerPlatform.groovy index 75a0580e7..55e8cbf83 100644 --- a/src/main/groovy/io/seqera/wave/core/ContainerPlatform.groovy +++ b/src/main/groovy/io/seqera/wave/core/ContainerPlatform.groovy @@ -31,10 +31,10 @@ class ContainerPlatform { public static final ContainerPlatform DEFAULT = new ContainerPlatform(DEFAULT_OS, DEFAULT_ARCH) - private static List ARM64 = ['arm64', 'aarch64'] + final static List ARM64 = ['arm64', 'aarch64'] private static List V8 = ['8','v8'] - private static List AMD64 = ['amd64', 'x86_64', 'x86-64'] - private static List ALLOWED_ARCH = AMD64 + ARM64 + ['arm'] + final static List AMD64 = ['amd64', 'x86_64', 'x86-64'] + final static List ALLOWED_ARCH = AMD64 + ARM64 + ['arm'] public static final String DEFAULT_ARCH = 'amd64' public static final String DEFAULT_OS = 'linux' diff --git a/src/main/groovy/io/seqera/wave/filter/MetricsQueryParamValidationFilter.groovy b/src/main/groovy/io/seqera/wave/filter/MetricsQueryParamValidationFilter.groovy new file mode 100644 index 000000000..3e9c34bd5 --- /dev/null +++ b/src/main/groovy/io/seqera/wave/filter/MetricsQueryParamValidationFilter.groovy @@ -0,0 +1,40 @@ +package io.seqera.wave.filter + +import java.util.regex.Pattern + +import groovy.transform.CompileStatic +import io.micronaut.context.annotation.Requires +import io.micronaut.http.HttpRequest +import io.micronaut.http.MutableHttpResponse +import io.micronaut.http.annotation.Filter +import io.micronaut.http.filter.HttpServerFilter +import io.micronaut.http.filter.ServerFilterChain +import io.seqera.wave.core.ContainerPlatform +import io.seqera.wave.exception.BadRequestException +import org.reactivestreams.Publisher + +@CompileStatic +@Filter(["/v1alpha2/metrics/**", "/v1alpha3/metrics/**/**"]) +@Requires(property = 'wave.metrics.enabled', value = 'true') +class MetricsQueryParamValidationFilter implements HttpServerFilter { + + static final private Pattern DATE_PATTERN = Pattern.compile("\\d{4}-\\d{2}-\\d{2}") + + @Override + Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { + + Map> queryParams = request.getParameters().asMap() + + final String date = queryParams.get("date")?[0] + final String arch = queryParams.get("arch")?[0] + + if(date && !DATE_PATTERN.matcher(date).matches()) { + throw new BadRequestException('date format should be yyyy-MM-dd') + } else if (arch && !ContainerPlatform.ALLOWED_ARCH.contains(arch)) { + throw new BadRequestException('arch should be one of ' + ContainerPlatform.ALLOWED_ARCH) + } + + return chain.proceed(request) + } +} + diff --git a/src/main/groovy/io/seqera/wave/filter/PullMetricsRequestsFilter.groovy b/src/main/groovy/io/seqera/wave/filter/PullMetricsRequestsFilter.groovy index 07fc817e0..4a7541ccc 100644 --- a/src/main/groovy/io/seqera/wave/filter/PullMetricsRequestsFilter.groovy +++ b/src/main/groovy/io/seqera/wave/filter/PullMetricsRequestsFilter.groovy @@ -83,10 +83,11 @@ class PullMetricsRequestsFilter implements HttpServerFilter { final contentType = response.headers.get(HttpHeaders.CONTENT_TYPE) if( contentType && contentType in MANIFEST_TYPES ) { final route = routeHelper.parse(request.path) - CompletableFuture.runAsync(() -> metricsService.incrementPullsCounter(route.identity), executor) + final arch = route.request.platform.arch + CompletableFuture.runAsync(() -> metricsService.incrementPullsCounter(route.identity, arch), executor) final version = route.request?.containerConfig?.fusionVersion() if (version) { - CompletableFuture.runAsync(() -> metricsService.incrementFusionPullsCounter(route.identity), executor) + CompletableFuture.runAsync(() -> metricsService.incrementFusionPullsCounter(route.identity, arch), executor) } } } diff --git a/src/main/groovy/io/seqera/wave/service/builder/impl/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/impl/ContainerBuildServiceImpl.groovy index 63793b1f8..c277c7f22 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/impl/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/impl/ContainerBuildServiceImpl.groovy @@ -207,7 +207,7 @@ class ContainerBuildServiceImpl implements ContainerBuildService, JobHandler metricsService.incrementBuildsCounter(request.identity), executor) + .runAsync(() -> metricsService.incrementBuildsCounter(request.identity, request.platform.arch), executor) // launch the build async CompletableFuture diff --git a/src/main/groovy/io/seqera/wave/service/metric/MetricsConstants.groovy b/src/main/groovy/io/seqera/wave/service/metric/MetricsConstants.groovy index b7e87e105..96dd8fe6f 100644 --- a/src/main/groovy/io/seqera/wave/service/metric/MetricsConstants.groovy +++ b/src/main/groovy/io/seqera/wave/service/metric/MetricsConstants.groovy @@ -18,6 +18,8 @@ package io.seqera.wave.service.metric +import io.seqera.wave.core.ContainerPlatform + /** * Metric constants * @@ -39,4 +41,10 @@ interface MetricsConstants { static final public String PREFIX_DAY = 'd' + static final public String PREFIX_ARCH = 'a' + + static final public String ARM64 = 'arm64' + + static final public String AMD64 = 'amd64' + } diff --git a/src/main/groovy/io/seqera/wave/service/metric/MetricsService.groovy b/src/main/groovy/io/seqera/wave/service/metric/MetricsService.groovy index 2eb8fc3e5..e1dee3cf5 100644 --- a/src/main/groovy/io/seqera/wave/service/metric/MetricsService.groovy +++ b/src/main/groovy/io/seqera/wave/service/metric/MetricsService.groovy @@ -18,6 +18,7 @@ package io.seqera.wave.service.metric +import io.seqera.wave.service.metric.model.GetOrgArchCountResponse import io.seqera.wave.service.metric.model.GetOrgCountResponse import io.seqera.wave.tower.PlatformId /** @@ -31,35 +32,35 @@ interface MetricsService { * * @param seqera platform id */ - void incrementFusionPullsCounter(PlatformId platformId) + void incrementFusionPullsCounter(PlatformId platformId, String arch) /** * increment wave builds count * * @param seqera platform id */ - void incrementBuildsCounter(PlatformId platformId) + void incrementBuildsCounter(PlatformId platformId, String arch) /** * increment wave pulls count * * @param seqera platform id */ - void incrementPullsCounter(PlatformId platformId) + void incrementPullsCounter(PlatformId platformId, String arch) /** * increment wave mirrors count * * @param seqera platform id */ - void incrementMirrorsCounter(PlatformId platformId) + void incrementMirrorsCounter(PlatformId platformId, String arch) /** * increment wave scans count * * @param seqera platform id */ - void incrementScansCounter(PlatformId platformId) + void incrementScansCounter(PlatformId platformId, String arch) /** * Get counts of all organisations @@ -76,4 +77,20 @@ interface MetricsService { * @return GetOrgCountResponse */ GetOrgCountResponse getOrgCount(String metric, String date, String org) + + /** + * Get counts by organisations or by date or by arch or by all + * + * @param metric + * @return GetOrgCountResponse + */ + GetOrgArchCountResponse getOrgCount(String metric, String date, String org, String arch) + + /** + * Get counts of all organisations by arch + * + * @param metric + * @return GetOrgCountResponse + */ + GetOrgArchCountResponse getAllOrgCount(String metric, String arch) } diff --git a/src/main/groovy/io/seqera/wave/service/metric/impl/MetricsServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/metric/impl/MetricsServiceImpl.groovy index 35e3c3f5d..9767c81bd 100644 --- a/src/main/groovy/io/seqera/wave/service/metric/impl/MetricsServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/metric/impl/MetricsServiceImpl.groovy @@ -25,8 +25,10 @@ import java.util.regex.Pattern import groovy.transform.CompileStatic import groovy.util.logging.Slf4j +import io.seqera.wave.core.ContainerPlatform import io.seqera.wave.service.metric.MetricsCounterStore import io.seqera.wave.service.metric.MetricsService +import io.seqera.wave.service.metric.model.GetOrgArchCountResponse import io.seqera.wave.service.metric.model.GetOrgCountResponse import io.seqera.wave.tower.PlatformId import jakarta.inject.Inject @@ -45,7 +47,10 @@ class MetricsServiceImpl implements MetricsService { static final private DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd") - static final private Pattern ORG_DATE_KEY_PATTERN = Pattern.compile('(builds|pulls|fusion|mirrors|scans)/o/([^/]+)/d/\\d{4}-\\d{2}-\\d{2}') + static final private Pattern ORG_DATE_KEY_PATTERN = Pattern.compile('(builds|pulls|fusion|mirrors|scans)/o/([^/]+).*') + + private static final Pattern ORG_ARCH_KEY_PATTERN = Pattern.compile("(?:^|/)o/(?[^/]+)|(?:^|/)a/(?[^/]+)") + @Inject private MetricsCounterStore metricsCounterStore @@ -55,8 +60,31 @@ class MetricsServiceImpl implements MetricsService { final response = new GetOrgCountResponse(metric, 0, [:]) final orgCounts = metricsCounterStore.getAllMatchingEntries("$metric/$PREFIX_ORG/*") for(def entry : orgCounts) { - // orgCounts also contains the records with org and date, so here it filter out the records with date - if(!entry.key.contains("/$PREFIX_DAY/")) { + // orgCounts also contains the records with arch and date, so here it filter out the records with date and arch + if(!entry.key.contains("/$PREFIX_DAY/") && !entry.key.contains("/$PREFIX_ARCH/")) { + response.count += entry.value + //split is used to extract the org name from the key like "metrics/o/seqera.io" => seqera.io + response.orgs.put(entry.key.split("/$PREFIX_ORG/").last(), entry.value) + } + } + return response + } + + @Override + GetOrgArchCountResponse getAllOrgCount(String metric, String arch){ + final orgCounts + if (arch) { + arch = resolveArch(arch) + orgCounts = metricsCounterStore.getAllMatchingEntries("$metric/$PREFIX_ORG/*/$PREFIX_ARCH/$arch/*") + } else { + orgCounts = metricsCounterStore.getAllMatchingEntries("$metric/$PREFIX_ORG/*") + } + + final response = new GetOrgArchCountResponse(metric, arch, 0, [:]) + + for(def entry : orgCounts) { + // orgCounts also contains the records with arch and date, so here it filter out the records with date and arch + if(!entry.key.contains("/$PREFIX_DAY/") && !entry.key.contains("/$PREFIX_ARCH/")) { response.count += entry.value //split is used to extract the org name from the key like "metrics/o/seqera.io" => seqera.io response.orgs.put(entry.key.split("/$PREFIX_ORG/").last(), entry.value) @@ -70,7 +98,7 @@ class MetricsServiceImpl implements MetricsService { final response = new GetOrgCountResponse(metric, 0, [:]) // count is stored per date and per org, so it can be extracted from get method - response.count = metricsCounterStore.get(getKey(metric, date, org)) ?: 0L + response.count = metricsCounterStore.get(getKey(metric, date, org, null)) ?: 0L //when org and date is provided, return the org count for given date if (org) { @@ -88,40 +116,93 @@ class MetricsServiceImpl implements MetricsService { } @Override - void incrementFusionPullsCounter(PlatformId platformId){ - incrementCounter(PREFIX_FUSION, platformId?.user?.email) + GetOrgArchCountResponse getOrgCount(String metric, String date, String org, String arch) { + arch = resolveArch(arch) + final response = new GetOrgArchCountResponse(metric, arch, 0, [:]) + + // count is stored per date and per org, so it can be extracted from get method + response.count = metricsCounterStore.get(getKey(metric, date, org, arch)) ?: 0L + + //when org and date is provided, return the org count for given date + if (org) { + response.orgs.put(org, response.count) + } else if (arch) { + // when date and arch are provide, scan the store and return the count for all orgs with given arch and date + final orgCounts = metricsCounterStore.getAllMatchingEntries("$metric/$PREFIX_ORG/*/$PREFIX_ARCH/$arch/$PREFIX_DAY/$date") + for(def entry : orgCounts) { + response.orgs.put(extractOrgFromKey(entry.key), entry.value) + } + } else { + // when only date is provide, scan the store and return the count for all orgs on given date + final orgCounts = metricsCounterStore.getAllMatchingEntries("$metric/$PREFIX_ORG/*/$PREFIX_DAY/$date") + for(def entry : orgCounts) { + response.orgs.put(extractOrgFromKey(entry.key), entry.value) + } + } + + return response + + } + + @Override + void incrementFusionPullsCounter(PlatformId platformId, String arch){ + incrementCounter(PREFIX_FUSION, platformId?.user?.email, arch) } @Override - void incrementBuildsCounter(PlatformId platformId){ - incrementCounter(PREFIX_BUILDS, platformId?.user?.email) + void incrementBuildsCounter(PlatformId platformId, String arch){ + incrementCounter(PREFIX_BUILDS, platformId?.user?.email, arch) } @Override - void incrementPullsCounter(PlatformId platformId) { - incrementCounter(PREFIX_PULLS, platformId?.user?.email) + void incrementPullsCounter(PlatformId platformId, String arch) { + incrementCounter(PREFIX_PULLS, platformId?.user?.email, arch) } @Override - void incrementMirrorsCounter(PlatformId platformId){ - incrementCounter(PREFIX_MIRRORS, platformId?.user?.email) + void incrementMirrorsCounter(PlatformId platformId, String arch){ + incrementCounter(PREFIX_MIRRORS, platformId?.user?.email, arch) } @Override - void incrementScansCounter(PlatformId platformId) { - incrementCounter(PREFIX_SCANS, platformId?.user?.email) + void incrementScansCounter(PlatformId platformId, String arch) { + incrementCounter(PREFIX_SCANS, platformId?.user?.email, arch) } - protected void incrementCounter(String prefix, String email) { - def org = getOrg(email) - def key = getKey(prefix, LocalDate.now().format(DATE_FORMATTER), null) + protected void incrementCounter(String prefix, String email, String arch) { + final org = getOrg(email) + final day = LocalDate.now().format(DATE_FORMATTER) + + //increment the count for the current day + def key = getKey(prefix, day, null, null) metricsCounterStore.inc(key) log.trace("increment metrics count of: $key") + + //increment the count for the current day and arch + if ( arch ) { + key = getKey(prefix, day, null, arch) + metricsCounterStore.inc(key) + log.trace("increment metrics count of: $key") + } + if ( org ) { - key = getKey(prefix, null, org) + //increment the count for the org + key = getKey(prefix, null, org, null) + metricsCounterStore.inc(key) + log.trace("increment metrics count of: $key") + + //increment the count for the org and day + key = getKey(prefix, day, org, null) + metricsCounterStore.inc(key) + log.trace("increment metrics count of: $key") + + //increment the count for the org and arch + key = getKey(prefix, null, org, arch) metricsCounterStore.inc(key) log.trace("increment metrics count of: $key") - key = getKey(prefix, LocalDate.now().format(DATE_FORMATTER), org) + + //increment the count for the org and arch and current date + key = getKey(prefix, day, org, arch) metricsCounterStore.inc(key) log.trace("increment metrics count of: $key") } @@ -136,21 +217,36 @@ class MetricsServiceImpl implements MetricsService { } } - protected static String getKey(String prefix, String day, String org){ - if( day && org ) - return "$prefix/$PREFIX_ORG/$org/$PREFIX_DAY/$day" - + protected static String getKey(String prefix, String day, String org, String arch){ + def key = "$prefix" if( org ) - return "$prefix/$PREFIX_ORG/$org" + key += "/$PREFIX_ORG/$org" + + if (arch) { + if (ContainerPlatform.AMD64.contains(arch)) + key += "/$PREFIX_ARCH/$AMD64" + else if (ContainerPlatform.ARM64.contains(arch)) + key += "/$PREFIX_ARCH/$ARM64" + } if( day ) - return "$prefix/$PREFIX_DAY/$day" + key += "/$PREFIX_DAY/$day" - return null + return key != prefix ? key : null } protected static String extractOrgFromKey(String key) { Matcher matcher = ORG_DATE_KEY_PATTERN.matcher(key) return matcher.matches() ? matcher.group(2) : "unknown" } + + protected static String resolveArch(String arch){ + if (ContainerPlatform.AMD64.contains(arch)) { + return AMD64 + } + if (ContainerPlatform.ARM64.contains(arch) || 'arm' == arch) { + return ARM64 + } + return null + } } diff --git a/src/main/groovy/io/seqera/wave/service/metric/model/GetArchCountResponse.groovy b/src/main/groovy/io/seqera/wave/service/metric/model/GetArchCountResponse.groovy new file mode 100644 index 000000000..f87b25b01 --- /dev/null +++ b/src/main/groovy/io/seqera/wave/service/metric/model/GetArchCountResponse.groovy @@ -0,0 +1,17 @@ +package io.seqera.wave.service.metric.model + +import groovy.transform.CompileStatic + +@CompileStatic +class GetArchCountResponse { + + String arch + String metric + Long count + + GetArchCountResponse(String arch, String metric, Long count) { + this.arch = arch + this.metric = metric + this.count = count + } +} diff --git a/src/main/groovy/io/seqera/wave/service/metric/model/GetOrgArchCountResponse.groovy b/src/main/groovy/io/seqera/wave/service/metric/model/GetOrgArchCountResponse.groovy new file mode 100644 index 000000000..afa8f22f5 --- /dev/null +++ b/src/main/groovy/io/seqera/wave/service/metric/model/GetOrgArchCountResponse.groovy @@ -0,0 +1,18 @@ +package io.seqera.wave.service.metric.model + +import groovy.transform.CompileStatic + +@CompileStatic +class GetOrgArchCountResponse { + String metric + String arch + Long count + Map orgs + + GetOrgArchCountResponse(String metric, String arch, Long count, Map orgs) { + this.metric = metric + this.arch = arch + this.count = count + this.orgs = orgs + } +} diff --git a/src/main/groovy/io/seqera/wave/service/metric/model/GetOrgCountResponse.groovy b/src/main/groovy/io/seqera/wave/service/metric/model/GetOrgCountResponse.groovy index e44ab49e2..4cc16646e 100644 --- a/src/main/groovy/io/seqera/wave/service/metric/model/GetOrgCountResponse.groovy +++ b/src/main/groovy/io/seqera/wave/service/metric/model/GetOrgCountResponse.groovy @@ -17,11 +17,14 @@ */ package io.seqera.wave.service.metric.model +import groovy.transform.CompileStatic + /** * Model organisations counts response * * @author Munish Chouhan */ +@CompileStatic class GetOrgCountResponse { String metric Long count diff --git a/src/main/groovy/io/seqera/wave/service/mirror/ContainerMirrorServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/mirror/ContainerMirrorServiceImpl.groovy index 1126fe87d..2c2182cb1 100644 --- a/src/main/groovy/io/seqera/wave/service/mirror/ContainerMirrorServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/mirror/ContainerMirrorServiceImpl.groovy @@ -75,7 +75,7 @@ class ContainerMirrorServiceImpl implements ContainerMirrorService, JobHandler metricsService.incrementMirrorsCounter(request.identity), ioExecutor) + CompletableFuture.runAsync(() -> metricsService.incrementMirrorsCounter(request.identity, request.platform.arch), ioExecutor) jobService.launchMirror(request) return new BuildTrack(request.mirrorId, request.targetImage, false, null) } diff --git a/src/main/groovy/io/seqera/wave/service/scan/ContainerScanServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/scan/ContainerScanServiceImpl.groovy index d0e3d7511..6538dd487 100644 --- a/src/main/groovy/io/seqera/wave/service/scan/ContainerScanServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/scan/ContainerScanServiceImpl.groovy @@ -202,7 +202,7 @@ class ContainerScanServiceImpl implements ContainerScanService, JobHandler