From 46c83ba6bb503d0a833803b7e9265be9147a9731 Mon Sep 17 00:00:00 2001
From: Oleksandr Zhevedenko <720803+Net-burst@users.noreply.github.com>
Date: Sat, 15 Feb 2025 18:02:22 -0500
Subject: [PATCH 1/3] Emit a metric for requests not carrying API access header

---
 .../cache/handlers/cache/CacheHandler.java    | 16 +++++------
 .../cache/handlers/cache/GetCacheHandler.java |  8 +++---
 .../handlers/cache/PostCacheHandler.java      | 11 ++++++--
 .../prebid/cache/metrics/MeasurementTag.java  | 28 +++++++++++++++++++
 .../prebid/cache/metrics/MetricsRecorder.java | 27 +-----------------
 5 files changed, 49 insertions(+), 41 deletions(-)
 create mode 100644 src/main/java/org/prebid/cache/metrics/MeasurementTag.java

diff --git a/src/main/java/org/prebid/cache/handlers/cache/CacheHandler.java b/src/main/java/org/prebid/cache/handlers/cache/CacheHandler.java
index 6d0bbca..de7585a 100644
--- a/src/main/java/org/prebid/cache/handlers/cache/CacheHandler.java
+++ b/src/main/java/org/prebid/cache/handlers/cache/CacheHandler.java
@@ -11,7 +11,7 @@
 import org.prebid.cache.handlers.MetricsHandler;
 import org.prebid.cache.handlers.ServiceType;
 import org.prebid.cache.log.ConditionalLogger;
-import org.prebid.cache.metrics.MetricsRecorder;
+import org.prebid.cache.metrics.MeasurementTag;
 import org.prebid.cache.metrics.MetricsRecorder.MetricsRecorderTimer;
 import org.springframework.core.io.buffer.DataBufferLimitException;
 import org.springframework.http.HttpHeaders;
@@ -69,7 +69,7 @@ Mono<ServerResponse> finalizeResult(final Mono<ServerResponse> mono,
 
     private Mono<ServerResponse> handleErrorMetrics(final Throwable error, final ServerRequest request) {
         if (error instanceof RepositoryException) {
-            recordMetric(MetricsRecorder.MeasurementTag.ERROR_DB);
+            recordMetric(MeasurementTag.ERROR_DB);
         } else if (error instanceof ResourceNotFoundException) {
             conditionalLogger.info(
                     error.getMessage()
@@ -79,7 +79,7 @@ private Mono<ServerResponse> handleErrorMetrics(final Throwable error, final Ser
         } else if (error instanceof BadRequestException) {
             log.error(error.getMessage());
         } else if (error instanceof TimeoutException) {
-            metricsRecorder.markMeterForTag(this.metricTagPrefix, MetricsRecorder.MeasurementTag.ERROR_TIMEDOUT);
+            metricsRecorder.markMeterForTag(this.metricTagPrefix, MeasurementTag.ERROR_TIMED_OUT);
         } else if (error instanceof DataBufferLimitException) {
             final long contentLength = request.headers().contentLength().orElse(UNKNOWN_SIZE_VALUE);
             conditionalLogger.error(
@@ -98,17 +98,17 @@ private void handleErrorStatusCodes(ServerRequest request, Signal<ServerResponse
         final var response = signal.get();
         HttpMethod method = request.method();
         if (method == null || signal.isOnError() || response == null) {
-            recordMetric(MetricsRecorder.MeasurementTag.ERROR_UNKNOWN);
+            recordMetric(MeasurementTag.ERROR_UNKNOWN);
         } else if (response.statusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
-            recordMetric(MetricsRecorder.MeasurementTag.ERROR_UNKNOWN);
+            recordMetric(MeasurementTag.ERROR_UNKNOWN);
         } else if (response.statusCode() == HttpStatus.BAD_REQUEST) {
-            recordMetric(MetricsRecorder.MeasurementTag.ERROR_BAD_REQUEST);
+            recordMetric(MeasurementTag.ERROR_BAD_REQUEST);
         } else if (response.statusCode() == HttpStatus.NOT_FOUND) {
-            recordMetric(MetricsRecorder.MeasurementTag.ERROR_MISSINGID);
+            recordMetric(MeasurementTag.ERROR_MISSING_ID);
         }
     }
 
-    private void recordMetric(MetricsRecorder.MeasurementTag tag) {
+    private void recordMetric(MeasurementTag tag) {
         metricsRecorder.markMeterForTag(this.metricTagPrefix, tag);
     }
 
diff --git a/src/main/java/org/prebid/cache/handlers/cache/GetCacheHandler.java b/src/main/java/org/prebid/cache/handlers/cache/GetCacheHandler.java
index 3cb5739..37371b7 100644
--- a/src/main/java/org/prebid/cache/handlers/cache/GetCacheHandler.java
+++ b/src/main/java/org/prebid/cache/handlers/cache/GetCacheHandler.java
@@ -12,6 +12,7 @@
 import org.prebid.cache.handlers.ErrorHandler;
 import org.prebid.cache.handlers.PayloadType;
 import org.prebid.cache.handlers.ServiceType;
+import org.prebid.cache.metrics.MeasurementTag;
 import org.prebid.cache.metrics.MetricsRecorder;
 import org.prebid.cache.metrics.MetricsRecorder.MetricsRecorderTimer;
 import org.prebid.cache.model.PayloadWrapper;
@@ -77,7 +78,7 @@ private static Map<String, WebClient> createClientsCache(final int ttl, final in
 
     public Mono<ServerResponse> fetch(ServerRequest request) {
         // metrics
-        metricsRecorder.markMeterForTag(this.metricTagPrefix, MetricsRecorder.MeasurementTag.REQUEST);
+        metricsRecorder.markMeterForTag(this.metricTagPrefix, MeasurementTag.REQUEST);
         final var timerContext = metricsRecorder.createRequestTimerForServiceType(this.type);
 
         return request.queryParam(ID_KEY).map(id -> fetch(request, id, timerContext)).orElseGet(() -> {
@@ -163,14 +164,13 @@ private Mono<ServerResponse> processRequest(final ServerRequest request, final S
 
     private Mono<ServerResponse> createServerResponse(final PayloadWrapper wrapper, final ServerRequest request) {
         if (wrapper.getPayload().getType().equals(PayloadType.JSON.toString())) {
-            metricsRecorder.markMeterForTag(this.metricTagPrefix, MetricsRecorder.MeasurementTag.JSON);
+            metricsRecorder.markMeterForTag(this.metricTagPrefix, MeasurementTag.JSON);
             return builder.createResponseMono(request, MediaType.APPLICATION_JSON_UTF8, wrapper);
         } else if (wrapper.getPayload().getType().equals(PayloadType.XML.toString())) {
-            metricsRecorder.markMeterForTag(this.metricTagPrefix, MetricsRecorder.MeasurementTag.XML);
+            metricsRecorder.markMeterForTag(this.metricTagPrefix, MeasurementTag.XML);
             return builder.createResponseMono(request, MediaType.APPLICATION_XML, wrapper);
         }
 
         return Mono.error(new UnsupportedMediaTypeException(UNSUPPORTED_MEDIATYPE));
     }
 }
-
diff --git a/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java b/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
index 42867da..5b53d41 100644
--- a/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
+++ b/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
@@ -14,6 +14,7 @@
 import org.prebid.cache.handlers.ErrorHandler;
 import org.prebid.cache.handlers.ServiceType;
 import org.prebid.cache.helpers.RandomUUID;
+import org.prebid.cache.metrics.MeasurementTag;
 import org.prebid.cache.metrics.MetricsRecorder;
 import org.prebid.cache.model.Payload;
 import org.prebid.cache.model.PayloadTransfer;
@@ -89,7 +90,7 @@ public Mono<ServerResponse> save(final ServerRequest request) {
             return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
         }
 
-        metricsRecorder.markMeterForTag(this.metricTagPrefix, MetricsRecorder.MeasurementTag.REQUEST);
+        metricsRecorder.markMeterForTag(this.metricTagPrefix, MeasurementTag.REQUEST);
         final var timerContext = metricsRecorder.createRequestTimerForServiceType(type);
 
         String secondaryCache = request.queryParam(SECONDARY_CACHE_KEY).orElse(StringUtils.EMPTY);
@@ -129,8 +130,12 @@ public Mono<ServerResponse> save(final ServerRequest request) {
     }
 
     private boolean isWriteAllowed(final ServerRequest request) {
-        return !apiConfig.isCacheWriteSecured()
-                || StringUtils.equals(request.headers().firstHeader(API_KEY_HEADER), apiConfig.getApiKey());
+        final boolean isValidApiKey = StringUtils.equals(request.headers().firstHeader(API_KEY_HEADER),
+                apiConfig.getApiKey());
+        if (!isValidApiKey) {
+            metricsRecorder.markMeterForTag(metricTagPrefix, MeasurementTag.UNAUTHORIZED_WRITE);
+        }
+        return !apiConfig.isCacheWriteSecured() || isValidApiKey;
     }
 
     private Function<PayloadTransfer, PayloadWrapper> payloadWrapperTransformer() {
diff --git a/src/main/java/org/prebid/cache/metrics/MeasurementTag.java b/src/main/java/org/prebid/cache/metrics/MeasurementTag.java
new file mode 100644
index 0000000..7f04e1d
--- /dev/null
+++ b/src/main/java/org/prebid/cache/metrics/MeasurementTag.java
@@ -0,0 +1,28 @@
+package org.prebid.cache.metrics;
+
+import lombok.Getter;
+
+@Getter
+public enum MeasurementTag {
+    REQUEST_DURATION("pbc.${prefix}.request.duration"),
+    REQUEST("pbc.${prefix}.request"),
+    ERROR_UNKNOWN("pbc.${prefix}.err.unknown"),
+    ERROR_TIMED_OUT("pbc.${prefix}.err.timedOut"),
+    ERROR_MISSING_ID("pbc.${prefix}.err.missingId"),
+    ERROR_BAD_REQUEST("pbc.${prefix}.err.badRequest"),
+    REQUEST_INVALID("pbc.request.invalid"),
+    JSON("pbc.${prefix}.json"),
+    XML("pbc.${prefix}.xml"),
+    ERROR_DB("pbc.${prefix}.err.db"),
+    ERROR_SECONDARY_WRITE("pbc.err.secondaryWrite"),
+    ERROR_EXISTING_ID("pbc.err.existingId"),
+    PROXY_SUCCESS("pbc.proxy.success"),
+    PROXY_FAILURE("pbc.proxy.failure"),
+    UNAUTHORIZED_WRITE("pbc.${prefix}.unauthorizedWrite");
+
+    private final String tag;
+
+    MeasurementTag(final String tag) {
+        this.tag = tag;
+    }
+}
diff --git a/src/main/java/org/prebid/cache/metrics/MetricsRecorder.java b/src/main/java/org/prebid/cache/metrics/MetricsRecorder.java
index 02eac81..bda7c1c 100644
--- a/src/main/java/org/prebid/cache/metrics/MetricsRecorder.java
+++ b/src/main/java/org/prebid/cache/metrics/MetricsRecorder.java
@@ -3,7 +3,6 @@
 import io.micrometer.core.instrument.Counter;
 import io.micrometer.core.instrument.MeterRegistry;
 import io.micrometer.core.instrument.Timer;
-import lombok.Getter;
 import org.prebid.cache.handlers.ServiceType;
 import org.springframework.stereotype.Component;
 
@@ -18,30 +17,6 @@ public MetricsRecorder(MeterRegistry meterRegistry) {
         this.meterRegistry = meterRegistry;
     }
 
-    public enum MeasurementTag {
-        REQUEST_DURATION("pbc.${prefix}.request.duration"),
-        REQUEST("pbc.${prefix}.request"),
-        ERROR_UNKNOWN("pbc.${prefix}.err.unknown"),
-        ERROR_TIMEDOUT("pbc.${prefix}.err.timedOut"),
-        ERROR_MISSINGID("pbc.${prefix}.err.missingId"),
-        ERROR_BAD_REQUEST("pbc.${prefix}.err.badRequest"),
-        REQUEST_INVALID("pbc.request.invalid"),
-        JSON("pbc.${prefix}.json"),
-        XML("pbc.${prefix}.xml"),
-        ERROR_DB("pbc.${prefix}.err.db"),
-        ERROR_SECONDARY_WRITE("pbc.err.secondaryWrite"),
-        ERROR_EXISTINGID("pbc.err.existingId"),
-        PROXY_SUCCESS("pbc.proxy.success"),
-        PROXY_FAILURE("pbc.proxy.failure");
-
-        @Getter
-        private final String tag;
-
-        MeasurementTag(final String tag) {
-            this.tag = tag;
-        }
-    }
-
     public class MetricsRecorderTimer {
         private final Timer timer;
         private final Timer.Sample sample;
@@ -65,7 +40,7 @@ public Counter getSecondaryCacheWriteError() {
     }
 
     public Counter getExistingKeyError() {
-        return meterRegistry.counter(MeasurementTag.ERROR_EXISTINGID.getTag());
+        return meterRegistry.counter(MeasurementTag.ERROR_EXISTING_ID.getTag());
     }
 
     public Counter getProxySuccess() {

From 6383f54d3fa980d699695e2b9d65817b7008d2b6 Mon Sep 17 00:00:00 2001
From: Oleksandr Zhevedenko <720803+Net-burst@users.noreply.github.com>
Date: Mon, 17 Feb 2025 21:33:02 -0500
Subject: [PATCH 2/3] Remarks

---
 .../cache/handlers/cache/PostCacheHandler.java  | 17 +++++++++--------
 .../prebid/cache/metrics/MeasurementTag.java    |  9 +++++----
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java b/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
index 5b53d41..ddfa6ca 100644
--- a/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
+++ b/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
@@ -86,7 +86,13 @@ public PostCacheHandler(final ReactiveRepository<PayloadWrapper, String> reposit
     }
 
     public Mono<ServerResponse> save(final ServerRequest request) {
-        if (!isWriteAllowed(request)) {
+        final boolean isValidApiKey = isValidApiKey(request);
+        if (!isValidApiKey) {
+            metricsRecorder.markMeterForTag(metricTagPrefix, MeasurementTag.NO_API_KEY);
+        }
+
+        if (apiConfig.isCacheWriteSecured() && !isValidApiKey) {
+            metricsRecorder.markMeterForTag(metricTagPrefix, MeasurementTag.ERROR_UNAUTHORIZED);
             return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
         }
 
@@ -129,13 +135,8 @@ public Mono<ServerResponse> save(final ServerRequest request) {
         return finalizeResult(responseMono, request, timerContext);
     }
 
-    private boolean isWriteAllowed(final ServerRequest request) {
-        final boolean isValidApiKey = StringUtils.equals(request.headers().firstHeader(API_KEY_HEADER),
-                apiConfig.getApiKey());
-        if (!isValidApiKey) {
-            metricsRecorder.markMeterForTag(metricTagPrefix, MeasurementTag.UNAUTHORIZED_WRITE);
-        }
-        return !apiConfig.isCacheWriteSecured() || isValidApiKey;
+    private boolean isValidApiKey(final ServerRequest request) {
+        return StringUtils.equals(request.headers().firstHeader(API_KEY_HEADER), apiConfig.getApiKey());
     }
 
     private Function<PayloadTransfer, PayloadWrapper> payloadWrapperTransformer() {
diff --git a/src/main/java/org/prebid/cache/metrics/MeasurementTag.java b/src/main/java/org/prebid/cache/metrics/MeasurementTag.java
index 7f04e1d..53eb914 100644
--- a/src/main/java/org/prebid/cache/metrics/MeasurementTag.java
+++ b/src/main/java/org/prebid/cache/metrics/MeasurementTag.java
@@ -6,19 +6,20 @@
 public enum MeasurementTag {
     REQUEST_DURATION("pbc.${prefix}.request.duration"),
     REQUEST("pbc.${prefix}.request"),
+    NO_API_KEY("pbc.${prefix}.noApiKey"),
+    REQUEST_INVALID("pbc.request.invalid"),
     ERROR_UNKNOWN("pbc.${prefix}.err.unknown"),
     ERROR_TIMED_OUT("pbc.${prefix}.err.timedOut"),
     ERROR_MISSING_ID("pbc.${prefix}.err.missingId"),
     ERROR_BAD_REQUEST("pbc.${prefix}.err.badRequest"),
-    REQUEST_INVALID("pbc.request.invalid"),
+    ERROR_UNAUTHORIZED("pbc.${prefix}.err.unauthorized"),
+    ERROR_DB("pbc.${prefix}.err.db"),
     JSON("pbc.${prefix}.json"),
     XML("pbc.${prefix}.xml"),
-    ERROR_DB("pbc.${prefix}.err.db"),
     ERROR_SECONDARY_WRITE("pbc.err.secondaryWrite"),
     ERROR_EXISTING_ID("pbc.err.existingId"),
     PROXY_SUCCESS("pbc.proxy.success"),
-    PROXY_FAILURE("pbc.proxy.failure"),
-    UNAUTHORIZED_WRITE("pbc.${prefix}.unauthorizedWrite");
+    PROXY_FAILURE("pbc.proxy.failure");
 
     private final String tag;
 

From ea3eada823c1e2b9a3bdb167348443a8ae45b924 Mon Sep 17 00:00:00 2001
From: Oleksandr Zhevedenko <720803+Net-burst@users.noreply.github.com>
Date: Mon, 17 Feb 2025 21:42:21 -0500
Subject: [PATCH 3/3] Flip untrusted call metric to make it more obvious

---
 .../org/prebid/cache/handlers/cache/PostCacheHandler.java     | 4 ++--
 src/main/java/org/prebid/cache/metrics/MeasurementTag.java    | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java b/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
index ddfa6ca..313eff8 100644
--- a/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
+++ b/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java
@@ -87,8 +87,8 @@ public PostCacheHandler(final ReactiveRepository<PayloadWrapper, String> reposit
 
     public Mono<ServerResponse> save(final ServerRequest request) {
         final boolean isValidApiKey = isValidApiKey(request);
-        if (!isValidApiKey) {
-            metricsRecorder.markMeterForTag(metricTagPrefix, MeasurementTag.NO_API_KEY);
+        if (isValidApiKey) {
+            metricsRecorder.markMeterForTag(metricTagPrefix, MeasurementTag.REQUEST_TRUSTED);
         }
 
         if (apiConfig.isCacheWriteSecured() && !isValidApiKey) {
diff --git a/src/main/java/org/prebid/cache/metrics/MeasurementTag.java b/src/main/java/org/prebid/cache/metrics/MeasurementTag.java
index 53eb914..4b87e9e 100644
--- a/src/main/java/org/prebid/cache/metrics/MeasurementTag.java
+++ b/src/main/java/org/prebid/cache/metrics/MeasurementTag.java
@@ -6,7 +6,7 @@
 public enum MeasurementTag {
     REQUEST_DURATION("pbc.${prefix}.request.duration"),
     REQUEST("pbc.${prefix}.request"),
-    NO_API_KEY("pbc.${prefix}.noApiKey"),
+    REQUEST_TRUSTED("pbc.${prefix}.trustedRequest"),
     REQUEST_INVALID("pbc.request.invalid"),
     ERROR_UNKNOWN("pbc.${prefix}.err.unknown"),
     ERROR_TIMED_OUT("pbc.${prefix}.err.timedOut"),
