From d217b376e841ee89e5ca7517e5220a0ec3d61d4d Mon Sep 17 00:00:00 2001 From: abdul-ashour Date: Tue, 11 May 2021 16:46:15 +0100 Subject: [PATCH] feat: use custom namespace rather than stack-name --- README.md | 4 +-- src/index.js | 13 ++++++-- src/index.test.js | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8c3edf5..784786f 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ provider: plugins: - serverless-plugin-aws-alerts - + custom: alerts: stages: # Optionally - select which stages to deploy alarms to @@ -293,7 +293,7 @@ custom: pattern: '{$.level > 40}' ``` -> Note: For custom log metrics, namespace property will automatically be set to stack name (e.g. `fooservice-dev`). +> Note: For custom log metrics, namespace property will automatically be set to stack name if it is not set in the definition(e.g. `fooservice-dev`). ## Custom Naming You can define custom naming template for the alarms. `nameTemplate` property under `alerts` configures naming template for all the alarms, while placing `nameTemplate` under alarm definition configures (overwrites) it for that specific alarm only. Naming template provides interpolation capabilities, where supported placeholders are: diff --git a/src/index.js b/src/index.js index 3df1227..5da567a 100644 --- a/src/index.js +++ b/src/index.js @@ -99,6 +99,14 @@ class AlertsPlugin { return this.getAlarms(alarms, definitions); } + getNameSpace(definition, stackName) { + if (!definition.namespace && definition.pattern) { + return stackName; + } + + return definition.namespace; + } + getAlarmCloudFormation(alertTopics, definition, functionName, functionRef) { if (!functionRef) { return; @@ -140,7 +148,7 @@ class AlertsPlugin { const stackName = this.awsProvider.naming.getStackName(); - const namespace = definition.pattern ? stackName : definition.namespace; + const namespace = this.getNameSpace(definition, stackName); const metricId = definition.pattern ? this.naming.getPatternMetricName(definition.metric, functionRef) @@ -354,7 +362,8 @@ class AlertsPlugin { const logMetricCFRefOK = `${logMetricCFRefBase}OK`; const cfLogName = this.providerNaming.getLogGroupLogicalId(functionName); - const metricNamespace = this.providerNaming.getStackName(); + const stackName = this.providerNaming.getStackName(); + const metricNamespace = this.getNameSpace(alarm, stackName); const logGroupName = this.providerNaming.getLogGroupName(functionObj.name); const metricName = this.naming.getPatternMetricName( alarm.metric, diff --git a/src/index.test.js b/src/index.test.js index 29d477a..993b14a 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -782,6 +782,86 @@ describe('#index', () => { }); }); + it('should use custom namespace if it is set in the definition', () => { + let config = { + definitions: { + bunyanErrors: { + metric: 'BunyanErrors', + namespace: 'CustomNameSpace', + threshold: 0, + statistic: 'Sum', + period: 60, + evaluationPeriods: 1, + datapointsToAlarm: 1, + comparisonOperator: 'GreaterThanOrEqualToThreshold', + pattern: '{$.level > 40}', + }, + }, + function: ['bunyanErrors'], + }; + + const plugin = pluginFactory(config); + + config = plugin.getConfig(); + const definitions = plugin.getDefinitions(config); + const alertTopics = plugin.compileAlertTopics(config); + + plugin.compileAlarms(config, definitions, alertTopics); + expect( + plugin.serverless.service.provider.compiledCloudFormationTemplate + .Resources + ).toEqual({ + FooBunyanErrorsAlarm: { + Type: 'AWS::CloudWatch::Alarm', + Properties: { + Namespace: 'CustomNameSpace', + MetricName: 'BunyanErrorsFooLambdaFunction', + Threshold: 0, + Statistic: 'Sum', + Period: 60, + EvaluationPeriods: 1, + DatapointsToAlarm: 1, + ComparisonOperator: 'GreaterThanOrEqualToThreshold', + OKActions: [], + AlarmActions: [], + InsufficientDataActions: [], + Dimensions: [], + TreatMissingData: 'missing', + }, + }, + FooLambdaFunctionBunyanErrorsLogMetricFilterALERT: { + Type: 'AWS::Logs::MetricFilter', + DependsOn: 'foo', + Properties: { + FilterPattern: '{$.level > 40}', + LogGroupName: '/aws/lambda/foo', + MetricTransformations: [ + { + MetricValue: 1, + MetricNamespace: 'CustomNameSpace', + MetricName: 'BunyanErrorsFooLambdaFunction', + }, + ], + }, + }, + FooLambdaFunctionBunyanErrorsLogMetricFilterOK: { + Type: 'AWS::Logs::MetricFilter', + DependsOn: 'foo', + Properties: { + FilterPattern: '', + LogGroupName: '/aws/lambda/foo', + MetricTransformations: [ + { + MetricValue: 0, + MetricNamespace: 'CustomNameSpace', + MetricName: 'BunyanErrorsFooLambdaFunction', + }, + ], + }, + }, + }); + }); + it('should use globally defined nameTemplate when it`s not provided in definitions', () => { let config = { nameTemplate: '$[functionName]-global',