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

added metric for tagging #332

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ public void processRequest(final InputStream inputStream, final OutputStream out
// A response will be output on all paths, though CloudFormation will
// not block on invoking the handlers, but rather listen for callbacks
writeResponse(outputStream, handlerResponse, request);
publishExceptionCodeAndCountMetrics(request == null ? null : request.getAction(), handlerResponse.getErrorCode());
publishExceptionCodeAndCountMetrics(handlerResponse.getStatus(), request == null ? null : request.getAction(),
handlerResponse.getErrorCode(), handlerResponse.getMessage());
}
}

Expand Down Expand Up @@ -496,9 +497,13 @@ private void publishExceptionMetric(final Action action, final Throwable ex, fin
/*
* null-safe exception metrics delivery
*/
private void publishExceptionCodeAndCountMetrics(final Action action, final HandlerErrorCode handlerErrorCode) {
private void publishExceptionCodeAndCountMetrics(final OperationStatus status,
final Action action,
final HandlerErrorCode handlerErrorCode,
final String message) {
if (this.metricsPublisherProxy != null) {
this.metricsPublisherProxy.publishExceptionByErrorCodeAndCountBulkMetrics(Instant.now(), action, handlerErrorCode);
this.metricsPublisherProxy.publishExceptionByErrorCodeAndCountBulkMetrics(status, Instant.now(), action,
handlerErrorCode, message);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ public class Metric {
public static final String METRIC_NAME_HANDLER_EXCEPTION = "HandlerException";
public static final String METRIC_NAME_HANDLER_EXCEPTION_BY_ERROR_CODE = "HandlerExceptionByErrorCode";
public static final String METRIC_NAME_HANDLER_EXCEPTION_BY_EXCEPTION_COUNT = "HandlerExceptionByExceptionCount";
public static final String METRIC_NAME_HANDLER_EXCEPTION_DUE_TO_TAGGING = "HandlerExceptionByTagging";
public static final String METRIC_NAME_HANDLER_DURATION = "HandlerInvocationDuration";
public static final String METRIC_NAME_HANDLER_INVOCATION_COUNT = "HandlerInvocationCount";
public static final String ACCESS_DENIED_EXCEPTION_MESSAGE = "not authorized";

public static final String DIMENSION_KEY_ACTION_TYPE = "Action";
public static final String DIMENSION_KEY_EXCEPTION_TYPE = "ExceptionType";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.time.Instant;
import software.amazon.cloudformation.Action;
import software.amazon.cloudformation.proxy.HandlerErrorCode;
import software.amazon.cloudformation.proxy.OperationStatus;

public abstract class MetricsPublisher {

Expand All @@ -42,9 +43,11 @@ public void publishExceptionMetric(final Instant timestamp,
final HandlerErrorCode handlerErrorCode) {
}

public void publishExceptionByErrorCodeAndCountBulkMetrics(final Instant timestamp,
public void publishExceptionByErrorCodeAndCountBulkMetrics(final OperationStatus status,
final Instant timestamp,
final Action action,
final HandlerErrorCode handlerErrorCode) {
final HandlerErrorCode handlerErrorCode,
final String message) {
}

public void publishInvocationMetric(final Instant timestamp, final Action action) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
*/
package software.amazon.cloudformation.metrics;

import static software.amazon.cloudformation.metrics.Metric.ACCESS_DENIED_EXCEPTION_MESSAGE;
import com.google.common.collect.Sets;
import java.time.Instant;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatch.model.Dimension;
Expand All @@ -28,6 +30,7 @@
import software.amazon.cloudformation.injection.CloudWatchProvider;
import software.amazon.cloudformation.proxy.HandlerErrorCode;
import software.amazon.cloudformation.proxy.Logger;
import software.amazon.cloudformation.proxy.OperationStatus;

public class MetricsPublisherImpl extends MetricsPublisher {
private final CloudWatchProvider cloudWatchProvider;
Expand Down Expand Up @@ -69,27 +72,38 @@ public void publishExceptionMetric(final Instant timestamp,
}

@Override
public void publishExceptionByErrorCodeAndCountBulkMetrics(final Instant timestamp,
public void publishExceptionByErrorCodeAndCountBulkMetrics(final OperationStatus status,
final Instant timestamp,
final Action action,
final HandlerErrorCode handlerErrorCode) {
final HandlerErrorCode handlerErrorCode,
final String message) {
Set<MetricDatum> bulkData = new HashSet<>();
final String actionName = action == null ? "NO_ACTION" : action.name();
final String messageLowerCase = message == null ? "" : message.toLowerCase(Locale.ENGLISH);

// By Error Code dimensions

EnumSet.allOf(HandlerErrorCode.class).forEach(
errorCode -> bulkData.add(MetricDatum.builder().metricName(Metric.METRIC_NAME_HANDLER_EXCEPTION_BY_ERROR_CODE)
.unit(StandardUnit.COUNT).value(errorCode == handlerErrorCode ? 1.0 : 0.0)
.dimensions(Sets.newHashSet(
Dimension.builder().name(Metric.DIMENSION_KEY_ACTION_TYPE).value(action == null ? "NO_ACTION" : action.name())
.build(),
EnumSet.allOf(HandlerErrorCode.class)
.forEach(errorCode -> bulkData.add(MetricDatum.builder()
.metricName(Metric.METRIC_NAME_HANDLER_EXCEPTION_BY_ERROR_CODE).unit(StandardUnit.COUNT)
.value(errorCode == handlerErrorCode ? 1.0 : 0.0)
.dimensions(Sets.newHashSet(Dimension.builder().name(Metric.DIMENSION_KEY_ACTION_TYPE).value(actionName).build(),
Dimension.builder().name(Metric.DIMENSION_KEY_HANDLER_ERROR_CODE).value(errorCode.name()).build()))
.timestamp(timestamp).build()));

// By Count dimensions
bulkData.add(MetricDatum.builder().metricName(Metric.METRIC_NAME_HANDLER_EXCEPTION_BY_EXCEPTION_COUNT)
.unit(StandardUnit.COUNT).value(handlerErrorCode == null ? 0.0 : 1.0).dimensions(Dimension.builder()
.name(Metric.DIMENSION_KEY_ACTION_TYPE).value(action == null ? "NO_ACTION" : action.name()).build())
.timestamp(timestamp).build());
.unit(StandardUnit.COUNT).value(handlerErrorCode == null ? 0.0 : 1.0)
.dimensions(Dimension.builder().name(Metric.DIMENSION_KEY_ACTION_TYPE).value(actionName).build()).timestamp(timestamp)
.build());

boolean authorizationError = status == OperationStatus.FAILED
&& messageLowerCase.contains(ACCESS_DENIED_EXCEPTION_MESSAGE) && messageLowerCase.contains("tag");

bulkData.add(MetricDatum.builder().metricName(Metric.METRIC_NAME_HANDLER_EXCEPTION_DUE_TO_TAGGING)
.unit(StandardUnit.COUNT).value(authorizationError ? 1.0 : 0.0)
.dimensions(Dimension.builder().name(Metric.DIMENSION_KEY_ACTION_TYPE).value(actionName).build()).timestamp(timestamp)
.build());

publishBulkMetrics(bulkData.toArray(new MetricDatum[bulkData.size()]));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ public void publishExceptionMetric(final Instant timestamp,
.forEach(metricsPublisher -> metricsPublisher.publishExceptionMetric(timestamp, action, e, handlerErrorCode));
}

public void publishExceptionByErrorCodeAndCountBulkMetrics(final Instant timestamp,
public void publishExceptionByErrorCodeAndCountBulkMetrics(final OperationStatus status,
final Instant timestamp,
final Action action,
final HandlerErrorCode handlerErrorCode) {
final HandlerErrorCode handlerErrorCode,
final String message) {
metricsPublishers.stream().forEach(metricsPublisher -> metricsPublisher
.publishExceptionByErrorCodeAndCountBulkMetrics(timestamp, action, handlerErrorCode));
.publishExceptionByErrorCodeAndCountBulkMetrics(status, timestamp, action, handlerErrorCode, message));
}

public void publishInvocationMetric(final Instant timestamp, final Action action) {
Expand Down
16 changes: 8 additions & 8 deletions src/test/java/software/amazon/cloudformation/WrapperTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ public void invokeHandler_nullResponse_returnsFailure(final String requestDataPa
// validation failure metric should be published for final error handling
verify(providerMetricsPublisher).publishExceptionMetric(any(Instant.class), any(), any(TerminalException.class),
any(HandlerErrorCode.class));
verify(providerMetricsPublisher).publishExceptionByErrorCodeAndCountBulkMetrics(any(Instant.class), any(),
any(HandlerErrorCode.class));
verify(providerMetricsPublisher).publishExceptionByErrorCodeAndCountBulkMetrics(any(OperationStatus.class),
any(Instant.class), any(), any(HandlerErrorCode.class), any());

// all metrics should be published even on terminal failure
verify(providerMetricsPublisher).publishInvocationMetric(any(Instant.class), eq(action));
Expand Down Expand Up @@ -417,8 +417,8 @@ public void invokeHandler_InProgress_returnsInProgress(final String requestDataP

}

verify(providerMetricsPublisher).publishExceptionByErrorCodeAndCountBulkMetrics(any(Instant.class), eq(action),
any());
verify(providerMetricsPublisher).publishExceptionByErrorCodeAndCountBulkMetrics(any(), any(Instant.class), eq(action),
any(), any());

// validation failure metric should not be published
verifyNoMoreInteractions(providerMetricsPublisher);
Expand Down Expand Up @@ -459,8 +459,8 @@ public void reInvokeHandler_InProgress_returnsInProgress(final String requestDat
// all metrics should be published, once for a single invocation
verify(providerMetricsPublisher).publishInvocationMetric(any(Instant.class), eq(action));
verify(providerMetricsPublisher).publishDurationMetric(any(Instant.class), eq(action), anyLong());
verify(providerMetricsPublisher).publishExceptionByErrorCodeAndCountBulkMetrics(any(Instant.class), eq(action),
any());
verify(providerMetricsPublisher).publishExceptionByErrorCodeAndCountBulkMetrics(any(), any(Instant.class), eq(action),
any(), any());

// validation failure metric should not be published
verifyNoMoreInteractions(providerMetricsPublisher);
Expand Down Expand Up @@ -825,8 +825,8 @@ public void invokeHandler_metricPublisherThrowable_returnsFailureResponse() thro
// verify initialiseRuntime was called and initialised dependencies
verifyInitialiseRuntime();

verify(providerMetricsPublisher).publishExceptionByErrorCodeAndCountBulkMetrics(any(Instant.class), any(Action.class),
any(HandlerErrorCode.class));
verify(providerMetricsPublisher).publishExceptionByErrorCodeAndCountBulkMetrics(any(OperationStatus.class),
any(Instant.class), any(Action.class), any(HandlerErrorCode.class), any(String.class));

// no further calls to metrics publisher should occur
verifyNoMoreInteractions(providerMetricsPublisher);
Expand Down