mirror of
https://github.com/google/nomulus.git
synced 2025-08-02 16:02:10 +02:00
Add metrics for registrar console requests
Cardinality of this metric: clientId: there are currently 650 (on sandbox, because of OTE), and 200 on production. explicitClientId: 2 roles: 2 now, might be 3 soon if we add vendors status: 2 So we're talking about a cardinality of 2,000-8,000. Less when you consider that registrars only seldom actually need to access the console (certainly not daily or even weekly). Compare with, e.g., the /epp/processing_time from the above EppMetrics.java which has: Epp commands: 26 (manual counting) client IDs: 200 on prod status: the actual status CODE of the command. Can have many values, but looking at the past few weeks' metrics I counted 20 Note that not every command results in every status. Looking a few weeks back we can see around 80-100 (commands+status) combination. buckets: 16 so that's over 250,000-1,000,000 cardinality, on a very high-volume metric. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=218699280
This commit is contained in:
parent
f6d9b46622
commit
97aa98eb35
11 changed files with 223 additions and 25 deletions
|
@ -26,11 +26,13 @@ java_library(
|
|||
"//java/google/registry/util",
|
||||
"//third_party/objectify:objectify-v4_1",
|
||||
"@com_google_appengine_api_1_0_sdk",
|
||||
"@com_google_auto_value",
|
||||
"@com_google_code_findbugs_jsr305",
|
||||
"@com_google_dagger",
|
||||
"@com_google_flogger",
|
||||
"@com_google_flogger_system_backend",
|
||||
"@com_google_guava",
|
||||
"@com_google_monitoring_client_metrics",
|
||||
"@com_google_re2j",
|
||||
"@io_bazel_rules_closure//closure/templates",
|
||||
"@javax_inject",
|
||||
|
|
|
@ -75,6 +75,7 @@ public final class ConsoleUiAction implements Runnable {
|
|||
|
||||
@Inject HttpServletRequest req;
|
||||
@Inject Response response;
|
||||
@Inject RegistrarConsoleMetrics registrarConsoleMetrics;
|
||||
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
|
||||
@Inject UserService userService;
|
||||
@Inject XsrfTokenManager xsrfTokenManager;
|
||||
|
@ -134,15 +135,19 @@ public final class ConsoleUiAction implements Runnable {
|
|||
data.put("username", user.getNickname());
|
||||
data.put("logoutUrl", userService.createLogoutURL(PATH));
|
||||
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
|
||||
ImmutableSetMultimap<String, Role> roleMap = registrarAccessor.getAllClientIdWithRoles();
|
||||
ImmutableSetMultimap<Role, String> roleMapInverse = roleMap.inverse();
|
||||
// TODO(guyben):just return all the clientIDs in a single list, and add an "isAdmin" or "roles"
|
||||
// item
|
||||
data.put("ownerClientIds", roleMapInverse.get(OWNER));
|
||||
data.put(
|
||||
"adminClientIds", Sets.difference(roleMapInverse.get(ADMIN), roleMapInverse.get(OWNER)));
|
||||
// We set the initual value to the value that will show if guessClientId throws.
|
||||
String clientId = "<null>";
|
||||
try {
|
||||
String clientId = paramClientId.orElse(registrarAccessor.guessClientId());
|
||||
clientId = paramClientId.orElse(registrarAccessor.guessClientId());
|
||||
data.put("clientId", clientId);
|
||||
|
||||
ImmutableSetMultimap<Role, String> roleMap =
|
||||
registrarAccessor.getAllClientIdWithRoles().inverse();
|
||||
data.put("ownerClientIds", roleMap.get(OWNER));
|
||||
data.put("adminClientIds", Sets.difference(roleMap.get(ADMIN), roleMap.get(OWNER)));
|
||||
|
||||
// We want to load the registrar even if we won't use it later (even if we remove the
|
||||
// requireFeeExtension) - to make sure the user indeed has access to the guessed registrar.
|
||||
//
|
||||
|
@ -162,7 +167,13 @@ public final class ConsoleUiAction implements Runnable {
|
|||
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
|
||||
.setData(data)
|
||||
.render());
|
||||
registrarConsoleMetrics.registerConsoleRequest(
|
||||
clientId, paramClientId.isPresent(), roleMap.get(clientId), "FORBIDDEN");
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
registrarConsoleMetrics.registerConsoleRequest(
|
||||
clientId, paramClientId.isPresent(), roleMap.get(clientId), "UNEXPECTED ERROR");
|
||||
throw e;
|
||||
}
|
||||
|
||||
String payload = TOFU_SUPPLIER.get()
|
||||
|
@ -171,5 +182,7 @@ public final class ConsoleUiAction implements Runnable {
|
|||
.setData(data)
|
||||
.render();
|
||||
response.setPayload(payload);
|
||||
registrarConsoleMetrics.registerConsoleRequest(
|
||||
clientId, paramClientId.isPresent(), roleMap.get(clientId), "SUCCESS");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.registrar;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.monitoring.metrics.IncrementableMetric;
|
||||
import com.google.monitoring.metrics.LabelDescriptor;
|
||||
import com.google.monitoring.metrics.MetricRegistryImpl;
|
||||
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.Role;
|
||||
import javax.inject.Inject;
|
||||
|
||||
final class RegistrarConsoleMetrics {
|
||||
|
||||
private static final ImmutableSet<LabelDescriptor> CONSOLE_LABEL_DESCRIPTORS =
|
||||
ImmutableSet.of(
|
||||
LabelDescriptor.create("clientId", "target registrar client ID"),
|
||||
LabelDescriptor.create("explicitClientId", "whether the client ID is set explicitly"),
|
||||
LabelDescriptor.create("role", "Role[s] of the user making the request"),
|
||||
LabelDescriptor.create("status", "whether the request is successful"));
|
||||
|
||||
static final IncrementableMetric consoleRequestMetric =
|
||||
MetricRegistryImpl.getDefault()
|
||||
.newIncrementableMetric(
|
||||
"/console/registrar/console_requests",
|
||||
"Count of /registrar requests",
|
||||
"count",
|
||||
CONSOLE_LABEL_DESCRIPTORS);
|
||||
|
||||
private static final ImmutableSet<LabelDescriptor> SETTINGS_LABEL_DESCRIPTORS =
|
||||
ImmutableSet.of(
|
||||
LabelDescriptor.create("clientId", "target registrar client ID"),
|
||||
LabelDescriptor.create("action", "action performed"),
|
||||
LabelDescriptor.create("role", "Role[s] of the user making the request"),
|
||||
LabelDescriptor.create("status", "whether the request is successful"));
|
||||
|
||||
static final IncrementableMetric settingsRequestMetric =
|
||||
MetricRegistryImpl.getDefault()
|
||||
.newIncrementableMetric(
|
||||
"/console/registrar/setting_requests",
|
||||
"Count of /registrar-settings requests",
|
||||
"count",
|
||||
SETTINGS_LABEL_DESCRIPTORS);
|
||||
|
||||
@Inject
|
||||
public RegistrarConsoleMetrics() {}
|
||||
|
||||
void registerConsoleRequest(
|
||||
String clientId, boolean explicitClientId, ImmutableSet<Role> roles, String status) {
|
||||
consoleRequestMetric.increment(
|
||||
clientId, String.valueOf(explicitClientId), String.valueOf(roles), status);
|
||||
}
|
||||
|
||||
void registerSettingsRequest(
|
||||
String clientId, String action, ImmutableSet<Role> roles, String status) {
|
||||
settingsRequestMetric.increment(clientId, action, String.valueOf(roles), status);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
|
|||
import static google.registry.security.JsonResponseHelper.Status.ERROR;
|
||||
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
|
@ -80,6 +81,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
|||
|
||||
@Inject JsonActionRunner jsonActionRunner;
|
||||
@Inject AppEngineServiceUtils appEngineServiceUtils;
|
||||
@Inject RegistrarConsoleMetrics registrarConsoleMetrics;
|
||||
@Inject SendEmailUtils sendEmailUtils;
|
||||
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
|
||||
@Inject AuthResult authResult;
|
||||
|
@ -114,34 +116,55 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
|||
@SuppressWarnings("unchecked")
|
||||
Map<String, ?> args = (Map<String, Object>)
|
||||
Optional.<Object>ofNullable(input.get(ARGS_PARAM)).orElse(ImmutableMap.of());
|
||||
|
||||
logger.atInfo().log("Received request '%s' on registrar '%s' with args %s", op, clientId, args);
|
||||
String status = "SUCCESS";
|
||||
try {
|
||||
switch (op) {
|
||||
case "update":
|
||||
return update(args, clientId);
|
||||
return update(args, clientId).toJsonResponse();
|
||||
case "read":
|
||||
return read(clientId);
|
||||
return read(clientId).toJsonResponse();
|
||||
default:
|
||||
return JsonResponseHelper.create(ERROR, "Unknown or unsupported operation: " + op);
|
||||
throw new IllegalArgumentException("Unknown or unsupported operation: " + op);
|
||||
}
|
||||
} catch (FormFieldException e) {
|
||||
logger.atWarning().withCause(e).log(
|
||||
"Failed to perform operation '%s' on registrar '%s' for args %s", op, clientId, args);
|
||||
return JsonResponseHelper.createFormFieldError(e.getMessage(), e.getFieldName());
|
||||
} catch (Throwable e) {
|
||||
logger.atWarning().withCause(e).log(
|
||||
"Failed to perform operation '%s' on registrar '%s' for args %s", op, clientId, args);
|
||||
status = "ERROR: " + e.getClass().getSimpleName();
|
||||
if (e instanceof FormFieldException) {
|
||||
FormFieldException formFieldException = (FormFieldException) e;
|
||||
return JsonResponseHelper.createFormFieldError(
|
||||
formFieldException.getMessage(), formFieldException.getFieldName());
|
||||
}
|
||||
return JsonResponseHelper.create(
|
||||
ERROR, Optional.ofNullable(e.getMessage()).orElse("Unspecified error"));
|
||||
} finally {
|
||||
registrarConsoleMetrics.registerSettingsRequest(
|
||||
clientId, op, registrarAccessor.getAllClientIdWithRoles().get(clientId), status);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> read(String clientId) {
|
||||
return JsonResponseHelper.create(
|
||||
SUCCESS, "Success", registrarAccessor.getRegistrar(clientId).toJsonMap());
|
||||
@AutoValue
|
||||
abstract static class RegistrarResult {
|
||||
abstract String message();
|
||||
|
||||
abstract Registrar registrar();
|
||||
|
||||
Map<String, Object> toJsonResponse() {
|
||||
return JsonResponseHelper.create(SUCCESS, message(), registrar().toJsonMap());
|
||||
}
|
||||
|
||||
static RegistrarResult create(String message, Registrar registrar) {
|
||||
return new AutoValue_RegistrarSettingsAction_RegistrarResult(message, registrar);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> update(final Map<String, ?> args, String clientId) {
|
||||
private RegistrarResult read(String clientId) {
|
||||
return RegistrarResult.create("Success", registrarAccessor.getRegistrar(clientId));
|
||||
}
|
||||
|
||||
private RegistrarResult update(final Map<String, ?> args, String clientId) {
|
||||
return ofy()
|
||||
.transact(
|
||||
() -> {
|
||||
|
@ -196,8 +219,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
|||
// Email and return update.
|
||||
sendExternalUpdatesIfNecessary(
|
||||
registrar, contacts, updatedRegistrar, updatedContacts);
|
||||
return JsonResponseHelper.create(
|
||||
SUCCESS, "Saved " + clientId, updatedRegistrar.toJsonMap());
|
||||
return RegistrarResult.create("Saved " + clientId, updatedRegistrar);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue