diff --git a/src/main/java/org/prebid/cache/handlers/CacheHandler.java b/src/main/java/org/prebid/cache/handlers/CacheHandler.java index acc144d..95b42b2 100644 --- a/src/main/java/org/prebid/cache/handlers/CacheHandler.java +++ b/src/main/java/org/prebid/cache/handlers/CacheHandler.java @@ -9,6 +9,7 @@ import org.prebid.cache.exceptions.RequestParsingException; import org.prebid.cache.exceptions.ResourceNotFoundException; import org.prebid.cache.exceptions.UnsupportedMediaTypeException; +import org.prebid.cache.log.ConditionalLogger; import org.prebid.cache.metrics.MetricsRecorder; import org.prebid.cache.metrics.MetricsRecorder.MetricsRecorderTimer; import org.springframework.core.io.buffer.DataBufferLimitException; @@ -18,13 +19,12 @@ import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeoutException; @Slf4j abstract class CacheHandler extends MetricsHandler { + private static final int UNKNOWN_SIZE_VALUE = 1; - private static final double SAMPLING_RATE = 0.01; ServiceType type; static final String ID_KEY = "uuid"; static final String CACHE_HOST_KEY = "ch"; @@ -32,6 +32,14 @@ abstract class CacheHandler extends MetricsHandler { protected String metricTagPrefix; + private final ConditionalLogger conditionalLogger; + private final Double samplingRate; + + protected CacheHandler(Double samplingRate) { + this.samplingRate = samplingRate; + this.conditionalLogger = new ConditionalLogger(log); + } + protected enum PayloadType implements StringTypeConvertible { JSON("json"), XML("xml"); @@ -74,18 +82,16 @@ Mono validateErrorResult(final Mono mono) { private Mono handleErrorMetrics(final Throwable error, final ServerRequest request) { if (error instanceof ResourceNotFoundException) { - log.debug(error.getMessage()); + conditionalLogger.info(error.getMessage(), samplingRate); } else if (error instanceof BadRequestException) { log.error(error.getMessage()); } else if (error instanceof TimeoutException) { metricsRecorder.markMeterForTag(this.metricTagPrefix, MetricsRecorder.MeasurementTag.ERROR_TIMEDOUT); } else if (error instanceof DataBufferLimitException) { - if (ThreadLocalRandom.current().nextDouble() < SAMPLING_RATE) { - final Long contentLength = request.headers().contentLength() - .orElse(UNKNOWN_SIZE_VALUE); - - log.error("Request length: `{}` exceeds maximum size limit", contentLength); - } + final long contentLength = request.headers().contentLength().orElse(UNKNOWN_SIZE_VALUE); + conditionalLogger.error( + "Request length: `" + contentLength + "` exceeds maximum size limit", + samplingRate); } else { log.error("Error occurred while processing the request: '{}', cause: '{}'", ExceptionUtils.getMessage(error), ExceptionUtils.getMessage(error)); diff --git a/src/main/java/org/prebid/cache/handlers/GetCacheHandler.java b/src/main/java/org/prebid/cache/handlers/GetCacheHandler.java index eaa2fd2..5a2ff98 100644 --- a/src/main/java/org/prebid/cache/handlers/GetCacheHandler.java +++ b/src/main/java/org/prebid/cache/handlers/GetCacheHandler.java @@ -16,6 +16,7 @@ import org.prebid.cache.repository.ReactiveRepository; import org.prebid.cache.routers.ApiConfig; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; @@ -48,8 +49,10 @@ public GetCacheHandler(final ReactiveRepository reposito final ApiConfig apiConfig, final MetricsRecorder metricsRecorder, final PrebidServerResponseBuilder builder, - final CircuitBreaker webClientCircuitBreaker) { + final CircuitBreaker webClientCircuitBreaker, + @Value("${sampling.rate:0.01}") final Double samplingRate) { + super(samplingRate); this.metricsRecorder = metricsRecorder; this.type = ServiceType.FETCH; this.repository = repository; diff --git a/src/main/java/org/prebid/cache/handlers/PostCacheHandler.java b/src/main/java/org/prebid/cache/handlers/PostCacheHandler.java index 4532794..26740ae 100644 --- a/src/main/java/org/prebid/cache/handlers/PostCacheHandler.java +++ b/src/main/java/org/prebid/cache/handlers/PostCacheHandler.java @@ -21,6 +21,7 @@ import org.prebid.cache.repository.CacheConfig; import org.prebid.cache.repository.ReactiveRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; @@ -64,8 +65,10 @@ public PostCacheHandler(final ReactiveRepository reposit final MetricsRecorder metricsRecorder, final PrebidServerResponseBuilder builder, final Supplier currentDateProvider, - final CircuitBreaker webClientCircuitBreaker) { + final CircuitBreaker webClientCircuitBreaker, + @Value("${sampling.rate:0.01}") final Double samplingRate) { + super(samplingRate); this.metricsRecorder = metricsRecorder; this.type = ServiceType.SAVE; this.repository = repository; diff --git a/src/main/java/org/prebid/cache/log/ConditionalLogger.java b/src/main/java/org/prebid/cache/log/ConditionalLogger.java new file mode 100644 index 0000000..c64e7f4 --- /dev/null +++ b/src/main/java/org/prebid/cache/log/ConditionalLogger.java @@ -0,0 +1,37 @@ +package org.prebid.cache.log; + +import lombok.AllArgsConstructor; +import org.slf4j.Logger; + +import java.util.concurrent.ThreadLocalRandom; + +@AllArgsConstructor +public class ConditionalLogger { + + private final Logger logger; + + public void info(String message, double samplingRate) { + if (samplingRate >= 1.0d || ThreadLocalRandom.current().nextDouble() < samplingRate) { + logger.info(message); + } + } + + public void debug(String message, double samplingRate) { + if (samplingRate >= 1.0d || ThreadLocalRandom.current().nextDouble() < samplingRate) { + logger.debug(message); + } + } + + public void error(String message, double samplingRate) { + if (samplingRate >= 1.0d || ThreadLocalRandom.current().nextDouble() < samplingRate) { + logger.error(message); + } + } + + public void warn(String message, double samplingRate) { + if (samplingRate >= 1.0d || ThreadLocalRandom.current().nextDouble() < samplingRate) { + logger.warn(message); + } + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f31e239..b66649f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -29,6 +29,7 @@ cache: # logging logging.level.root: info logging.config: classpath:log4j2-console.xml +sampling.rate: 0.01 # metrics management: diff --git a/src/test/java/org/prebid/cache/handlers/GetCacheHandlerTests.java b/src/test/java/org/prebid/cache/handlers/GetCacheHandlerTests.java index 604612e..4573da7 100644 --- a/src/test/java/org/prebid/cache/handlers/GetCacheHandlerTests.java +++ b/src/test/java/org/prebid/cache/handlers/GetCacheHandlerTests.java @@ -16,6 +16,7 @@ import org.prebid.cache.repository.ReactiveRepository; import org.prebid.cache.routers.ApiConfig; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -41,6 +42,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.verify; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import static org.springframework.http.HttpHeaders.CONTENT_TYPE; @@ -78,14 +80,23 @@ class GetCacheHandlerTests extends CacheHandlerTests { @MockBean ReactiveRepository repository; + @Value("${sampling.rate:2.0}") + Double samplingRate; + GetCacheHandler handler; WireMockServer serverMock; @BeforeEach public void setup() { - handler = - new GetCacheHandler(repository, cacheConfig, apiConfig, metricsRecorder, responseBuilder, webClientCircuitBreaker); + handler = new GetCacheHandler( + repository, + cacheConfig, + apiConfig, + metricsRecorder, + responseBuilder, + webClientCircuitBreaker, + samplingRate); serverMock = new WireMockServer(8080); serverMock.start(); } diff --git a/src/test/java/org/prebid/cache/handlers/PostCacheHandlerTests.java b/src/test/java/org/prebid/cache/handlers/PostCacheHandlerTests.java index 5a21cc3..b74055c 100644 --- a/src/test/java/org/prebid/cache/handlers/PostCacheHandlerTests.java +++ b/src/test/java/org/prebid/cache/handlers/PostCacheHandlerTests.java @@ -21,6 +21,7 @@ import org.prebid.cache.repository.ReactiveRepository; import org.prebid.cache.routers.ApiConfig; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -39,7 +40,12 @@ import java.util.function.Consumer; import java.util.function.Supplier; -import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToIgnoreCase; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.BDDMockito.given; import static org.prebid.cache.util.AwaitilityUtil.awaitAndVerify; @@ -78,10 +84,19 @@ class PostCacheHandlerTests extends CacheHandlerTests { @MockBean ReactiveRepository repository; + @Value("${sampling.rate:2.0}") + Double samplingRate; + @Test void testVerifyError() { - PostCacheHandler handler = new PostCacheHandler(repository, cacheConfig, metricsRecorder, builder, - currentDateProvider, webClientCircuitBreaker); + PostCacheHandler handler = new PostCacheHandler( + repository, + cacheConfig, + metricsRecorder, + builder, + currentDateProvider, + webClientCircuitBreaker, + samplingRate); verifyJacksonError(handler); verifyRepositoryError(handler); } @@ -108,7 +123,7 @@ void testVerifySave() { given(repository.save(payloadWrapper)).willReturn(Mono.just(payloadWrapper)); final var handler = new PostCacheHandler(repository, cacheConfig, metricsRecorder, builder, - currentDateProvider, webClientCircuitBreaker); + currentDateProvider, webClientCircuitBreaker, samplingRate); final var payload = new PayloadTransfer("json", "2be04ba5-8f9b-4a1e-8100-d573c40312f8", "", 1800L, null, "prebid_"); @@ -141,7 +156,7 @@ void testSecondaryCacheSuccess() { .willReturn(aResponse().withBody("{\"responses\":[{\"uuid\":\"2be04ba5-8f9b-4a1e-8100-d573c40312f8\"}]}"))); final var handler = new PostCacheHandler(repository, cacheConfig, metricsRecorder, builder, - currentDateProvider, webClientCircuitBreaker); + currentDateProvider, webClientCircuitBreaker, samplingRate); final var payload = new PayloadTransfer("json", "2be04ba5-8f9b-4a1e-8100-d573c40312f8", "", 1800L, null, "prebid_"); @@ -176,7 +191,7 @@ void testExternalUUIDInvalid() { cacheConfig.getMinExpiry(), cacheConfig.getMaxExpiry(), false, Collections.emptyList(), cacheConfig.getSecondaryCachePath(), 100, 100, "example.com", "http"); final var handler = new PostCacheHandler(repository, cacheConfigLocal, metricsRecorder, builder, - currentDateProvider, webClientCircuitBreaker); + currentDateProvider, webClientCircuitBreaker, samplingRate); final var payload = new PayloadTransfer("json", "2be04ba5-8f9b-4a1e-8100-d573c40312f8", "", 1800L, null, "prebid_"); @@ -210,7 +225,7 @@ void testUUIDDuplication() { 5, cacheConfig.getMaxExpiry(), cacheConfig.isAllowExternalUUID(), Collections.emptyList(), cacheConfig.getSecondaryCachePath(), 100, 100, "example.com", "http"); final var handler = new PostCacheHandler(repository, cacheConfigLocal, metricsRecorder, builder, - currentDateProvider, webClientCircuitBreaker); + currentDateProvider, webClientCircuitBreaker, samplingRate); final var payload = new PayloadTransfer("json", "2be04ba5-8f9b-4a1e-8100-d573c40312f8", "", 1800L, null, "prebid_");