1
0
mirror of https://github.com/google/nomulus synced 2026-05-13 11:21:46 +00:00

Add RDAP latency metrics (#3015)

* RDAP latency metrics

* refactor code

* refactors

* refactor

* record latency in RdapMetricInformation object

* lint

* fix tests

* add for tests

* formatter
This commit is contained in:
Juan Celhay
2026-04-21 15:00:25 -04:00
committed by GitHub
parent 3de790fb00
commit 653704811b
9 changed files with 76 additions and 2 deletions

View File

@@ -51,6 +51,7 @@ import google.registry.util.Clock;
import jakarta.inject.Inject;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
@@ -131,6 +132,7 @@ public abstract class RdapActionBase implements Runnable {
@Override
public void run() {
Instant startTime = clock.now();
metricInformationBuilder.setIncludeDeleted(includeDeletedParam.orElse(false));
metricInformationBuilder.setRole(rdapAuthorization.role());
metricInformationBuilder.setRequestMethod(requestMethod);
@@ -179,6 +181,9 @@ public abstract class RdapActionBase implements Runnable {
setError(SC_INTERNAL_SERVER_ERROR, "Internal Server Error", "An error was encountered");
logger.atSevere().withCause(e).log("Exception encountered while processing RDAP command.");
}
long processingTime = Duration.between(startTime, clock.now()).toMillis();
metricInformationBuilder.setProcessingTime(processingTime);
rdapMetrics.updateMetrics(metricInformationBuilder.build());
}

View File

@@ -14,6 +14,8 @@
package google.registry.rdap;
import static com.google.monitoring.metrics.EventMetric.DEFAULT_FITTER;
import com.google.auto.value.AutoBuilder;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
@@ -133,6 +135,16 @@ public class RdapMetrics {
LABEL_DESCRIPTORS_FOR_RETRIEVAL_COUNTS,
FIBONACCI_FITTER);
@VisibleForTesting
static final EventMetric requestTime =
MetricRegistryImpl.getDefault()
.newEventMetric(
"/rdap/request_time",
"RDAP Request Time",
"milliseconds",
LABEL_DESCRIPTORS_FOR_RESPONSES,
DEFAULT_FITTER);
@Inject
public RdapMetrics() {}
@@ -181,6 +193,15 @@ public class RdapMetrics {
getLabelStringForPrefixLength(rdapMetricInformation.prefixLength()),
rdapMetricInformation.includeDeleted() ? "YES" : "NO");
}
if (rdapMetricInformation.processingTime().isPresent()) {
requestTime.record(
rdapMetricInformation.processingTime().get(),
rdapMetricInformation.endpointType().toString(),
rdapMetricInformation.searchType().toString(),
rdapMetricInformation.wildcardType().toString(),
String.valueOf(rdapMetricInformation.statusCode()),
rdapMetricInformation.incompletenessWarningType().toString());
}
}
/**
@@ -202,6 +223,8 @@ public class RdapMetrics {
* than were actually returned in the response; absent if a search was not performed.
* @param numHostsRetrieved Number of hosts retrieved from the database; this might be more than
* were actually returned in the response; absent if a search was not performed.
* @param processingTime The processing time for the request in milliseconds; absent if not
* recorded.
*/
public record RdapMetricInformation(
EndpointType endpointType,
@@ -215,7 +238,8 @@ public class RdapMetrics {
int statusCode,
IncompletenessWarningType incompletenessWarningType,
Optional<Long> numDomainsRetrieved,
Optional<Long> numHostsRetrieved) {
Optional<Long> numHostsRetrieved,
Optional<Long> processingTime) {
@AutoBuilder
interface Builder {
@@ -243,9 +267,12 @@ public class RdapMetrics {
Builder setNumHostsRetrieved(long numHostsRetrieved);
Builder setProcessingTime(long processingTime);
RdapMetricInformation build();
}
static Builder builder() {
return new AutoBuilder_RdapMetrics_RdapMetricInformation_Builder()
.setSearchType(SearchType.NONE)

View File

@@ -21,6 +21,7 @@ import static google.registry.rdap.RdapTestHelper.parseJsonObject;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.HEAD;
import static google.registry.testing.DatabaseHelper.createTld;
import static org.joda.time.Duration.millis;
import static org.mockito.Mockito.verify;
import google.registry.rdap.RdapMetrics.EndpointType;
@@ -31,6 +32,7 @@ import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
import google.registry.request.Action;
import google.registry.request.auth.Auth;
import google.registry.testing.FakeClock;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -63,6 +65,9 @@ class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTest.RdapT
if (pathSearchString.equals("RuntimeException")) {
throw new RuntimeException();
}
if (pathSearchString.equals("advanceClock")) {
((FakeClock) clock).advanceBy(millis(50));
}
return new ReplyPayloadBase(BoilerplateType.OTHER) {
@JsonableElement String key = "value";
};
@@ -130,6 +135,7 @@ class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTest.RdapT
.setRequestMethod(Action.Method.GET)
.setStatusCode(200)
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE)
.setProcessingTime(0L)
.build());
}
@@ -149,6 +155,7 @@ class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTest.RdapT
.setRequestMethod(Action.Method.GET)
.setStatusCode(400)
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE)
.setProcessingTime(0L)
.build());
}
@@ -172,4 +179,24 @@ class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTest.RdapT
assertThat(payload).contains("\n");
assertThat(parseJsonObject(payload)).isEqualTo(loadJsonFile("rdapjson_toplevel.json"));
}
@Test
void testMetrics_recordsProcessingTime() {
generateActualJson("advanceClock");
verify(rdapMetrics)
.updateMetrics(
RdapMetrics.RdapMetricInformation.builder()
.setEndpointType(EndpointType.HELP)
.setSearchType(SearchType.NONE)
.setWildcardType(WildcardType.INVALID)
.setPrefixLength(0)
.setIncludeDeleted(false)
.setRegistrarSpecified(false)
.setRole(RdapAuthorization.Role.PUBLIC)
.setRequestMethod(Action.Method.GET)
.setStatusCode(200)
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE)
.setProcessingTime(50L)
.build());
}
}

View File

@@ -435,6 +435,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
.setRequestMethod(Action.Method.GET)
.setStatusCode(200)
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE)
.setProcessingTime(0L)
.build());
}

View File

@@ -235,6 +235,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
.setRequestMethod(Action.Method.GET)
.setStatusCode(200)
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE)
.setProcessingTime(0L)
.build());
}
}

View File

@@ -82,6 +82,7 @@ class RdapHelpActionTest extends RdapActionBaseTestCase<RdapHelpAction> {
.setRequestMethod(Action.Method.GET)
.setStatusCode(200)
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE)
.setProcessingTime(0L)
.build());
}
}

View File

@@ -37,6 +37,7 @@ class RdapMetricsTest {
RdapMetrics.responses.reset();
RdapMetrics.numberOfDomainsRetrieved.reset();
RdapMetrics.numberOfHostsRetrieved.reset();
RdapMetrics.requestTime.reset();
}
private RdapMetrics.RdapMetricInformation.Builder getBuilder() {
@@ -274,4 +275,13 @@ class RdapMetricsTest {
assertThat(RdapMetrics.numberOfDomainsRetrieved).hasNoOtherValues();
assertThat(RdapMetrics.numberOfHostsRetrieved).hasNoOtherValues();
}
@Test
void testRecordProcessingTime() {
rdapMetrics.updateMetrics(getBuilder().setProcessingTime(100L).build());
assertThat(RdapMetrics.requestTime)
.hasDataSetForLabels(ImmutableSet.of(100L), "DOMAINS", "NONE", "INVALID", "200", "COMPLETE")
.and()
.hasNoOtherValues();
}
}

View File

@@ -287,6 +287,7 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
.setRequestMethod(Action.Method.GET)
.setStatusCode(200)
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE)
.setProcessingTime(0L)
.build());
}
}

View File

@@ -90,7 +90,8 @@ public abstract class RdapSearchActionTestCase<A extends RdapSearchActionBase>
.setRole(metricRole)
.setRequestMethod(requestMethod)
.setStatusCode(metricStatusCode)
.setIncompletenessWarningType(incompletenessWarningType);
.setIncompletenessWarningType(incompletenessWarningType)
.setProcessingTime(0L);
numDomainsRetrieved.ifPresent(builder::setNumDomainsRetrieved);
numHostsRetrieved.ifPresent(builder::setNumHostsRetrieved);
verify(rdapMetrics).updateMetrics(builder.build());