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

CloudWatch: Math expression in alarm doesn't respect period #32221

Open
1 task
hakenmt opened this issue Nov 20, 2024 · 2 comments
Open
1 task

CloudWatch: Math expression in alarm doesn't respect period #32221

hakenmt opened this issue Nov 20, 2024 · 2 comments
Labels
@aws-cdk/aws-cloudwatch Related to Amazon CloudWatch bug This issue is a bug. effort/small Small work item – less than a day of effort p2

Comments

@hakenmt
Copy link

hakenmt commented Nov 20, 2024

Describe the bug

I'm defining an alarm as follows:

let latencyImpactAlarm: Alarm = new Alarm(
        this,
        val + "LatencyImpact",
        {
          alarmName: val + "-node-high-latency-impact",
          actionsEnabled: false,
          datapointsToAlarm: 3,
          evaluationPeriods: 5,
          metric: new MathExpression({
            period: Duration.seconds(60),
            expression: 'TIME_SERIES(0) + ((INSIGHT_RULE_METRIC("' +
              latencyRule.ruleName +
              '", "MaxContributorValue") / m1) * 100)',
            usingMetrics: {
              "m1": new Metric({
                namespace: "AWS/ApplicationELB",
                metricName: "RequestCount",
                dimensionsMap: {
                  "LoadBalancer": value
                },
                statistic: "Sum",
                period: Duration.seconds(60)
              })
            }
          }),
          threshold: .1,
          comparisonOperator:
            ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
        },
      );

This produces CFN as follows:

"Metrics": [
     {
      "Expression": "TIME_SERIES(0) + ((INSIGHT_RULE_METRIC(\"HighLatencyRequestsPerNode-app-multi--ALBAE-7sFFT5bABDxM-2fa0f6aeb46f1279\", \"MaxContributorValue\") / m1) * 100)",
      "Id": "expr_1"
     },
     {
      "Id": "m1",
      "MetricStat": {
       "Metric": {
        "Dimensions": [
         {
          "Name": "LoadBalancer",
          "Value": "app/multi--ALBAE-7sFFT5bABDxM/2fa0f6aeb46f1279"
         }
        ],
        "MetricName": "RequestCount",
        "Namespace": "AWS/ApplicationELB"
       },
       "Period": 60,
       "Stat": "Sum"
      },
      "ReturnData": false
     }
    ],

When deployed, this causes an error: Resource handler returned message: "Error in expression 'expr_1': Parameter Query Period is invalid. Please specify a Period.

Even though the period is set, it is not included in the synth'd CFN template. If you add in the period manually, the resource successfully deploys.

{
      "Expression": "TIME_SERIES(0) + ((INSIGHT_RULE_METRIC(\"HighLatencyRequestsPerNode-app-multi--ALBAE-7sFFT5bABDxM-2fa0f6aeb46f1279\", \"MaxContributorValue\") / m1) * 100)",
      "Id": "expr_1",
      "Period": 60
     },

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

I expect the period field to be included in the resulting CFN.

Current Behavior

It does not.

Reproduction Steps

Provided above.

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.138.0

Framework Version

No response

Node.js Version

20

OS

darwin

Language

TypeScript

Language Version

No response

Other information

No response

@hakenmt hakenmt added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Nov 20, 2024
@github-actions github-actions bot added the @aws-cdk/aws-cloudwatch Related to Amazon CloudWatch label Nov 20, 2024
@ashishdhingra ashishdhingra self-assigned this Nov 20, 2024
@ashishdhingra ashishdhingra added p2 needs-reproduction This issue needs reproduction. and removed needs-triage This issue or PR still needs to be triaged. labels Nov 20, 2024
@ashishdhingra
Copy link
Contributor

Reproducible using below customer provided code:

import * as cdk from 'aws-cdk-lib';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';

export class CdktestStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const alarm = new cloudwatch.Alarm(this, 'MyAlarm', {
      alarmName: 'TestAlarm',
      actionsEnabled: false,
      datapointsToAlarm: 3,
      evaluationPeriods: 5,
      metric: new cloudwatch.MathExpression({
        period: cdk.Duration.seconds(60),
        expression: 'TIME_SERIES(0) + ((INSIGHT_RULE_METRIC("' +
              'testrulename' +
              '", "MaxContributorValue") / m1) * 100)',
        usingMetrics: {
          "m1": new cloudwatch.Metric({
            namespace: "AWS/ApplicationELB",
                metricName: "RequestCount",
                dimensionsMap: {
                  "LoadBalancer": "test"
                },
                statistic: "Sum",
                period: cdk.Duration.seconds(60)
          })
        }
      }),
      threshold: 1,
      comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD
    });
  }
}

Running cdk synth works fine and generates the below CloudFormation template:

Resources:
  MyAlarm696658B6:
    Type: AWS::CloudWatch::Alarm
    Properties:
      ActionsEnabled: false
      AlarmName: TestAlarm
      ComparisonOperator: GreaterThanOrEqualToThreshold
      DatapointsToAlarm: 3
      EvaluationPeriods: 5
      Metrics:
        - Expression: TIME_SERIES(0) + ((INSIGHT_RULE_METRIC("testrulename", "MaxContributorValue") / m1) * 100)
          Id: expr_1
        - Id: m1
          MetricStat:
            Metric:
              Dimensions:
                - Name: LoadBalancer
                  Value: test
              MetricName: RequestCount
              Namespace: AWS/ApplicationELB
            Period: 60
            Stat: Sum
          ReturnData: false
      Threshold: 1
    Metadata:
      aws:cdk:path: CdktestStack/MyAlarm/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:H4sIAAAAAAAA/yXGQQ6DIBAAwLd4h60a03Bt+gP7ALNdaEQREhbKwfB3o55meuieCtoGC0vSq3T2C/snIa0CC0/kQtYFE82wvxzGTbx//ko9NxoOOZKpwgdtYOHHv1PQtzA0C1srY/bJbgbG2wMtdOBxbQAAAA==
    Metadata:
      aws:cdk:path: CdktestStack/CDKMetadata/Default
Parameters:
  BootstrapVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /cdk-bootstrap/hnb659fds/version
    Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]

Running cdk deploy gives the below error:

✨  Synthesis time: 3.88s

CdktestStack: start: Building 8a0193553528ae2ff8bc78613dd9272f1ab325842a9536f50ae03bd70f3da6bf:<<ACCOUNT_ID>>-us-east-2
CdktestStack: success: Built 8a0193553528ae2ff8bc78613dd9272f1ab325842a9536f50ae03bd70f3da6bf:<<ACCOUNT_ID>>-us-east-2
CdktestStack: start: Publishing 8a0193553528ae2ff8bc78613dd9272f1ab325842a9536f50ae03bd70f3da6bf:<<ACCOUNT_ID>>-us-east-2
CdktestStack: success: Published 8a0193553528ae2ff8bc78613dd9272f1ab325842a9536f50ae03bd70f3da6bf:<<ACCOUNT_ID>>-us-east-2
CdktestStack: deploying... [1/1]
CdktestStack: creating CloudFormation changeset...
2:08:33 PM | CREATE_FAILED        | AWS::CloudWatch::Alarm | MyAlarm696658B6
Resource handler returned message: "Error in expression 'expr_1': Parameter Query Period is invalid. Please specify a Period. (Service: AmazonCloudWatch; Status Code: 400; Error Code: ValidationException; Request ID: 33fa0563-08e4-4c71-946a-6f18e0
fe19a9; Proxy: null) (Service: CloudWatch, Status Code: 400, Request ID: 33fa0563-08e4-4c71-946a-6f18e0fe19a9)" (RequestToken: d12a4313-3f5d-335d-bad7-d44554d3ccdc, HandlerErrorCode: GeneralServiceException)

❌  CdktestStack failed: Error: The stack named CdktestStack failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE: Resource handler returned message: "Error in expression 'expr_1': Parameter Query Period is invalid. Please specify a Period. (Service: AmazonCloudWatch; Status Code: 400; Error Code: ValidationException; Request ID: 33fa0563-08e4-4c71-946a-6f18e0fe19a9; Proxy: null) (Service: CloudWatch, Status Code: 400, Request ID: 33fa0563-08e4-4c71-946a-6f18e0fe19a9)" (RequestToken: d12a4313-3f5d-335d-bad7-d44554d3ccdc, HandlerErrorCode: GeneralServiceException)

Looks like in PR #7644, it allowed to set Period when using MathExpression without submetrics. So below CDK code:

export class CdktestStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    new cloudwatch.Alarm(this, 'Alarm', {
      alarmName: 'TestAlarm',
      actionsEnabled: false,
      datapointsToAlarm: 3,
      evaluationPeriods: 5,
      metric: new cloudwatch.MathExpression({
        expression: 'INSIGHT_RULE_METRIC("SomeId", UniqueContributors)',
        usingMetrics: {},
        period: cdk.Duration.seconds(60)
      }),
      threshold: 1,
    });
  }
}

synthesizes to below CloudFormation template:

Resources:
  Alarm7103F465:
    Type: AWS::CloudWatch::Alarm
    Properties:
      ActionsEnabled: false
      AlarmName: TestAlarm
      ComparisonOperator: GreaterThanOrEqualToThreshold
      DatapointsToAlarm: 3
      EvaluationPeriods: 5
      Metrics:
        - Expression: INSIGHT_RULE_METRIC("SomeId", UniqueContributors)
          Id: expr_1
          Period: 60
      Threshold: 1
    Metadata:
      aws:cdk:path: CdktestStack/Alarm/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:H4sIAAAAAAAA/yXGQQ6DIBAAwLd4h60a03Bt+gP7ALNdaEQREhbKwfB3o55meuieCtoGC0vSq3T2C/snIa0CC0/kQtYFE82wvxzGTbx//ko9NxoOOZKpwgdtYOHHv1PQtzA0C1srY/bJbgbG2wMtdOBxbQAAAA==
    Metadata:
      aws:cdk:path: CdktestStack/CDKMetadata/Default
Parameters:
  BootstrapVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /cdk-bootstrap/hnb659fds/version
    Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]

@hakenmt You could try to use raw property override as a workaround (demonstrated below):

import * as cdk from 'aws-cdk-lib';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';

export class CdktestStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const alarm = new cloudwatch.Alarm(this, 'MyAlarm', {
      alarmName: 'TestAlarm',
      actionsEnabled: false,
      datapointsToAlarm: 3,
      evaluationPeriods: 5,
      metric: new cloudwatch.MathExpression({
        period: cdk.Duration.seconds(60),
        expression: 'TIME_SERIES(0) + ((INSIGHT_RULE_METRIC("' +
              'testrulename' +
              '", "MaxContributorValue") / m1) * 100)',
        usingMetrics: {
          "m1": new cloudwatch.Metric({
            namespace: "AWS/ApplicationELB",
                metricName: "RequestCount",
                dimensionsMap: {
                  "LoadBalancer": "test"
                },
                statistic: "Sum",
                period: cdk.Duration.seconds(60)
          })
        }
      }),
      threshold: 1,
      comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD
    });

    const cfnAlarm = alarm.node.defaultChild as cloudwatch.CfnAlarm;
    cfnAlarm.addPropertyOverride('Metrics.0.Period', 60);
  }
}

@ashishdhingra ashishdhingra added effort/small Small work item – less than a day of effort and removed needs-reproduction This issue needs reproduction. labels Nov 20, 2024
@ashishdhingra ashishdhingra removed their assignment Nov 20, 2024
@hakenmt
Copy link
Author

hakenmt commented Nov 20, 2024

Thanks, yes, ended up with that workaround after submitting this bug report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-cloudwatch Related to Amazon CloudWatch bug This issue is a bug. effort/small Small work item – less than a day of effort p2
Projects
None yet
Development

No branches or pull requests

2 participants