Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement hooks metrics submission #1305

Merged
merged 1 commit into from
Jun 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion src/main/java/org/prebid/server/auction/ExchangeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@
import org.prebid.server.exception.PreBidException;
import org.prebid.server.execution.Timeout;
import org.prebid.server.hooks.execution.HookStageExecutor;
import org.prebid.server.hooks.execution.model.ExecutionAction;
import org.prebid.server.hooks.execution.model.ExecutionStatus;
import org.prebid.server.hooks.execution.model.GroupExecutionOutcome;
import org.prebid.server.hooks.execution.model.HookExecutionOutcome;
import org.prebid.server.hooks.execution.model.HookId;
import org.prebid.server.hooks.execution.model.HookStageExecutionResult;
import org.prebid.server.hooks.execution.model.Stage;
import org.prebid.server.hooks.execution.model.StageExecutionOutcome;
Expand Down Expand Up @@ -92,6 +95,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -176,7 +180,8 @@ public ExchangeService(long expectedCacheTime,
*/
public Future<BidResponse> holdAuction(AuctionContext context) {
return processAuctionRequest(context)
.map(bidResponse -> enrichWithHooksDebugInfo(bidResponse, context));
.map(bidResponse -> enrichWithHooksDebugInfo(bidResponse, context))
.map(bidResponse -> updateHooksMetrics(context, bidResponse));
}

private Future<BidResponse> processAuctionRequest(AuctionContext context) {
Expand Down Expand Up @@ -1478,6 +1483,59 @@ private static ExtModulesTraceInvocationResult toTraceInvocationResult(HookExecu
.build();
}

private <T> T updateHooksMetrics(AuctionContext context, T result) {
final EnumMap<Stage, StageExecutionOutcome> stageOutcomes =
context.getHookExecutionContext().getStageOutcomes();

final Account account = context.getAccount();

stageOutcomes.forEach((stage, outcome) -> updateHooksStageMetrics(account, stage, outcome));

// account might be null if request is rejected by the entrypoint hook
if (account != null) {
final String accountId = account.getId();

stageOutcomes.values().stream()
.map(StageExecutionOutcome::getGroups)
.flatMap(Collection::stream)
.map(GroupExecutionOutcome::getHooks)
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(
outcome -> outcome.getHookId().getModuleCode(),
Collectors.summingLong(HookExecutionOutcome::getExecutionTime)))
.forEach((moduleCode, executionTime) ->
metrics.updateAccountModuleDurationMetric(accountId, moduleCode, executionTime));
}

return result;
}

private void updateHooksStageMetrics(Account account, Stage stage, StageExecutionOutcome stageOutcome) {
stageOutcome.getGroups().stream()
.flatMap(groupOutcome -> groupOutcome.getHooks().stream())
.forEach(hookOutcome -> updateHookInvocationMetrics(account, stage, hookOutcome));
}

private void updateHookInvocationMetrics(Account account, Stage stage, HookExecutionOutcome hookOutcome) {
final HookId hookId = hookOutcome.getHookId();
final ExecutionStatus status = hookOutcome.getStatus();
final ExecutionAction action = hookOutcome.getAction();
final String moduleCode = hookId.getModuleCode();

metrics.updateHooksMetrics(
moduleCode,
stage,
hookId.getHookImplCode(),
status,
hookOutcome.getExecutionTime(),
action);

// account might be null if request is rejected by the entrypoint hook
if (account != null) {
metrics.updateAccountHooksMetrics(account.getId(), moduleCode, status, action);
}
}

private <T> List<T> nullIfEmpty(List<T> value) {
return CollectionUtils.isEmpty(value) ? null : value;
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/prebid/server/metric/AccountMetrics.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class AccountMetrics extends UpdatableMetrics {
private final RequestMetrics requestsMetrics;
private final CacheMetrics cacheMetrics;
private final ResponseMetrics responseMetrics;
private final HooksMetrics hooksMetrics;

AccountMetrics(MetricRegistry metricRegistry, CounterType counterType, String account) {
super(Objects.requireNonNull(metricRegistry), Objects.requireNonNull(counterType),
Expand All @@ -32,6 +33,7 @@ class AccountMetrics extends UpdatableMetrics {
requestsMetrics = new RequestMetrics(metricRegistry, counterType, createPrefix(account));
cacheMetrics = new CacheMetrics(metricRegistry, counterType, createPrefix(account));
responseMetrics = new ResponseMetrics(metricRegistry, counterType, createPrefix(account));
hooksMetrics = new HooksMetrics(metricRegistry, counterType, createPrefix(account));
}

private static String createPrefix(String account) {
Expand Down Expand Up @@ -61,4 +63,8 @@ CacheMetrics cache() {
ResponseMetrics response() {
return responseMetrics;
}

HooksMetrics hooks() {
return hooksMetrics;
}
}
32 changes: 32 additions & 0 deletions src/main/java/org/prebid/server/metric/HookImplMetrics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.prebid.server.metric;

import com.codahale.metrics.MetricRegistry;

import java.util.Objects;
import java.util.function.Function;

class HookImplMetrics extends UpdatableMetrics {

private final HookSuccessMetrics successMetrics;

HookImplMetrics(MetricRegistry metricRegistry, CounterType counterType, String prefix, String hookImplCode) {
super(
Objects.requireNonNull(metricRegistry),
Objects.requireNonNull(counterType),
nameCreator(createPrefix(Objects.requireNonNull(prefix), Objects.requireNonNull(hookImplCode))));

successMetrics = new HookSuccessMetrics(metricRegistry, counterType, createPrefix(prefix, hookImplCode));
}

private static Function<MetricName, String> nameCreator(String prefix) {
return metricName -> String.format("%s.%s", prefix, metricName.toString());
}

private static String createPrefix(String prefix, String stage) {
return String.format("%s.hook.%s", prefix, stage);
}

HookSuccessMetrics success() {
return successMetrics;
}
}
24 changes: 24 additions & 0 deletions src/main/java/org/prebid/server/metric/HookSuccessMetrics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.prebid.server.metric;

import com.codahale.metrics.MetricRegistry;

import java.util.Objects;
import java.util.function.Function;

class HookSuccessMetrics extends UpdatableMetrics {

HookSuccessMetrics(MetricRegistry metricRegistry, CounterType counterType, String prefix) {
super(
Objects.requireNonNull(metricRegistry),
Objects.requireNonNull(counterType),
nameCreator(createPrefix(Objects.requireNonNull(prefix))));
}

private static Function<MetricName, String> nameCreator(String prefix) {
return metricName -> String.format("%s.%s", prefix, metricName.toString());
}

private static String createPrefix(String prefix) {
return String.format("%s.success", prefix);
}
}
55 changes: 55 additions & 0 deletions src/main/java/org/prebid/server/metric/HooksMetrics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.prebid.server.metric;

import com.codahale.metrics.MetricRegistry;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

class HooksMetrics extends UpdatableMetrics {

// not thread-safe maps are intentionally used here because it's harmless in this particular case - eventually
// this all boils down to metrics lookup by underlying metric registry and that operation is guaranteed to be
// thread-safe
private final Function<String, ModuleMetrics> moduleMetricsCreator;
private final Map<String, ModuleMetrics> moduleMetrics;

HooksMetrics(MetricRegistry metricRegistry, CounterType counterType, String prefix) {
super(
Objects.requireNonNull(metricRegistry),
Objects.requireNonNull(counterType),
nameCreator(createPrefix(Objects.requireNonNull(prefix))));

moduleMetricsCreator = moduleCode ->
new ModuleMetrics(metricRegistry, counterType, createPrefix(prefix), moduleCode);
moduleMetrics = new HashMap<>();
}

HooksMetrics(MetricRegistry metricRegistry, CounterType counterType) {
super(
Objects.requireNonNull(metricRegistry),
Objects.requireNonNull(counterType),
nameCreator(createPrefix()));

moduleMetricsCreator = moduleCode ->
new ModuleMetrics(metricRegistry, counterType, createPrefix(), moduleCode);
moduleMetrics = new HashMap<>();
}

private static Function<MetricName, String> nameCreator(String prefix) {
return metricName -> String.format("%s.%s", prefix, metricName.toString());
}

private static String createPrefix(String prefix) {
return String.format("%s.%s", prefix, createPrefix());
}

private static String createPrefix() {
return "modules";
}

ModuleMetrics module(String moduleCode) {
return moduleMetrics.computeIfAbsent(moduleCode, moduleMetricsCreator);
}
}
12 changes: 11 additions & 1 deletion src/main/java/org/prebid/server/metric/MetricName.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,17 @@ public enum MetricName {
initialize,
update,
hit,
miss;
miss,

// hooks
call,
success,
noop,
reject,
unknown,
failure,
execution_error("execution-error"),
duration;

private final String name;

Expand Down
79 changes: 79 additions & 0 deletions src/main/java/org/prebid/server/metric/Metrics.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import com.codahale.metrics.MetricRegistry;
import com.iab.openrtb.request.Imp;
import org.prebid.server.hooks.execution.model.ExecutionAction;
import org.prebid.server.hooks.execution.model.ExecutionStatus;
import org.prebid.server.hooks.execution.model.Stage;
import org.prebid.server.metric.model.AccountMetricsVerbosityLevel;

import java.util.ArrayList;
Expand Down Expand Up @@ -48,6 +51,7 @@ public class Metrics extends UpdatableMetrics {
private final TimeoutNotificationMetrics timeoutNotificationMetrics;
private final CurrencyRatesMetrics currencyRatesMetrics;
private final Map<MetricName, SettingsCacheMetrics> settingsCacheMetrics;
private final HooksMetrics hooksMetrics;

public Metrics(MetricRegistry metricRegistry, CounterType counterType,
AccountMetricsVerbosity accountMetricsVerbosity) {
Expand Down Expand Up @@ -77,6 +81,7 @@ public Metrics(MetricRegistry metricRegistry, CounterType counterType,
timeoutNotificationMetrics = new TimeoutNotificationMetrics(metricRegistry, counterType);
currencyRatesMetrics = new CurrencyRatesMetrics(metricRegistry, counterType);
settingsCacheMetrics = new HashMap<>();
hooksMetrics = new HooksMetrics(metricRegistry, counterType);
}

RequestStatusMetrics forRequestType(MetricName requestType) {
Expand Down Expand Up @@ -127,6 +132,10 @@ SettingsCacheMetrics forSettingsCacheType(MetricName type) {
return settingsCacheMetrics.computeIfAbsent(type, settingsCacheMetricsCreator);
}

HooksMetrics hooks() {
return hooksMetrics;
}

public void updateAppAndNoCookieAndImpsRequestedMetrics(boolean isApp, boolean liveUidsPresent, int numImps) {
if (isApp) {
incCounter(MetricName.app_requests);
Expand Down Expand Up @@ -504,4 +513,74 @@ public void updateSettingsCacheRefreshErrorMetric(MetricName cacheType, MetricNa
public void updateSettingsCacheEventMetric(MetricName cacheType, MetricName event) {
forSettingsCacheType(cacheType).incCounter(event);
}

public void updateHooksMetrics(
String moduleCode,
Stage stage,
String hookImplCode,
ExecutionStatus status,
Long executionTime,
ExecutionAction action) {

final HookImplMetrics hookImplMetrics = hooks().module(moduleCode).stage(stage).hookImpl(hookImplCode);

hookImplMetrics.incCounter(MetricName.call);
if (status == ExecutionStatus.success) {
hookImplMetrics.success().incCounter(HookMetricMapper.fromAction(action));
} else {
hookImplMetrics.incCounter(HookMetricMapper.fromStatus(status));
}
hookImplMetrics.updateTimer(MetricName.duration, executionTime);
}

public void updateAccountHooksMetrics(
String accountId,
String moduleCode,
ExecutionStatus status,
ExecutionAction action) {

if (accountMetricsVerbosity.forAccount(accountId).isAtLeast(AccountMetricsVerbosityLevel.detailed)) {
final ModuleMetrics accountModuleMetrics = forAccount(accountId).hooks().module(moduleCode);

accountModuleMetrics.incCounter(MetricName.call);
if (status == ExecutionStatus.success) {
accountModuleMetrics.success().incCounter(HookMetricMapper.fromAction(action));
} else {
accountModuleMetrics.incCounter(MetricName.failure);
}
}
}

public void updateAccountModuleDurationMetric(String accountId, String moduleCode, Long executionTime) {
if (accountMetricsVerbosity.forAccount(accountId).isAtLeast(AccountMetricsVerbosityLevel.detailed)) {
forAccount(accountId).hooks().module(moduleCode).updateTimer(MetricName.duration, executionTime);
}
}

private static class HookMetricMapper {

private static final EnumMap<ExecutionStatus, MetricName> STATUS_TO_METRIC =
new EnumMap<>(ExecutionStatus.class);
private static final EnumMap<ExecutionAction, MetricName> ACTION_TO_METRIC =
new EnumMap<>(ExecutionAction.class);

static {
STATUS_TO_METRIC.put(ExecutionStatus.failure, MetricName.failure);
STATUS_TO_METRIC.put(ExecutionStatus.timeout, MetricName.timeout);
STATUS_TO_METRIC.put(ExecutionStatus.invocation_failure, MetricName.execution_error);
STATUS_TO_METRIC.put(ExecutionStatus.execution_failure, MetricName.execution_error);

ACTION_TO_METRIC.put(ExecutionAction.no_action, MetricName.noop);
ACTION_TO_METRIC.put(ExecutionAction.update, MetricName.update);
ACTION_TO_METRIC.put(ExecutionAction.reject, MetricName.reject);
}

static MetricName fromStatus(ExecutionStatus status) {
return STATUS_TO_METRIC.getOrDefault(status, MetricName.unknown);
}

static MetricName fromAction(ExecutionAction action) {
return ACTION_TO_METRIC.getOrDefault(action, MetricName.unknown);
}
}
}
Loading