Skip to content

Commit

Permalink
Merge pull request #16 from nicka/issue/propercasing
Browse files Browse the repository at this point in the history
Added CloudWatch namespace propercasing and refactored CloudWatch dashboard
  • Loading branch information
nicka committed Aug 2, 2017
2 parents 02b3b31 + fa2f426 commit 4390209
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 130 deletions.
44 changes: 44 additions & 0 deletions cloudformation/__snapshots__/dashboard.test.js.snap
@@ -0,0 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Dashboard returns cloudformation dashboard body 1`] = `
Object {
"Fn::Join": Array [
"",
Array [
"{\\"widgets\\":[{\\"type\\":\\"metric\\",\\"x\\":0,\\"y\\":1,\\"width\\":6,\\"height\\":3,\\"properties\\":{\\"view\\":\\"singleValue\\",\\"metrics\\":[[\\"\${self:custom.cloudWatchNamespace}\\",\\"BuyPrice\\",\\"CryptoCurrency\\",\\"\${self:provider.environment.PREFERRED_CRYPTO_CURRENCY}\\",\\"Stage\\",\\"\${self:custom.stage}\\",\\"LocalCurrency\\",\\"\${self:provider.environment.PREFERRED_LOCAL_CURRENCY}\\",{\\"label\\":\\"Buy\\"}],[\\".\\",\\"SellPrice\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",{\\"label\\":\\"Sell\\"}]],\\"region\\":\\"\${self:provider.region}\\",\\"title\\":\\"Current price in \${self:provider.environment.PREFERRED_LOCAL_CURRENCY}\\"}},{\\"type\\":\\"metric\\",\\"x\\":0,\\"y\\":4,\\"width\\":24,\\"height\\":9,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"stacked\\":false,\\"metrics\\":[[\\"\${self:custom.cloudWatchNamespace}\\",\\"BuyPrice\\",\\"CryptoCurrency\\",\\"\${self:provider.environment.PREFERRED_CRYPTO_CURRENCY}\\",\\"Stage\\",\\"\${self:custom.stage}\\",\\"LocalCurrency\\",\\"\${self:provider.environment.PREFERRED_LOCAL_CURRENCY}\\",{\\"color\\":\\"#aec7e8\\",\\"label\\":\\"Buy actual\\"}],[\\".\\",\\"SellPrice\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",{\\"color\\":\\"#ffbb78\\",\\"label\\":\\"Sell actual\\"}],[\\".\\",\\"BuyPrice\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",{\\"period\\":3600,\\"color\\":\\"#1f77b4\\",\\"label\\":\\"Buy hourly average\\"}],[\\".\\",\\"SellPrice\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",{\\"period\\":3600,\\"color\\":\\"#ff7f0e\\",\\"label\\":\\"Sell hourly average\\"}],[\\".\\",\\"BuyPrice\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",{\\"period\\":86400,\\"label\\":\\"Buy daily average\\",\\"color\\":\\"#ff9896\\"}],[\\".\\",\\"SellPrice\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",\\".\\",{\\"period\\":86400,\\"label\\":\\"Sell daily average\\",\\"color\\":\\"#98df8a\\"}]],\\"region\\":\\"\${self:provider.region}\\",\\"title\\":\\"Buy / Sell \${self:provider.environment.PREFERRED_CRYPTO_CURRENCY}-\${self:provider.environment.PREFERRED_LOCAL_CURRENCY}\\"}},{\\"type\\":\\"metric\\",\\"x\\":0,\\"y\\":13,\\"width\\":6,\\"height\\":6,\\"properties\\":{\\"title\\":\\"Low Buy Price\\",\\"annotations\\":{\\"alarms\\":[\\"arn:aws:cloudwatch:\${self:provider.region}:",
Object {
"Ref": "AWS::AccountId",
},
":alarm:",
Object {
"Ref": "LowBuyPriceAlarm",
},
"\\"]},\\"view\\":\\"timeSeries\\",\\"stacked\\":false}},{\\"type\\":\\"metric\\",\\"x\\":6,\\"y\\":13,\\"width\\":6,\\"height\\":6,\\"properties\\":{\\"title\\":\\"Low Sell Price\\",\\"annotations\\":{\\"alarms\\":[\\"arn:aws:cloudwatch:\${self:provider.region}:",
Object {
"Ref": "AWS::AccountId",
},
":alarm:",
Object {
"Ref": "LowSellPriceAlarm",
},
"\\"]},\\"view\\":\\"timeSeries\\",\\"stacked\\":false}},{\\"type\\":\\"metric\\",\\"x\\":12,\\"y\\":13,\\"width\\":6,\\"height\\":6,\\"properties\\":{\\"title\\":\\"High Buy Price\\",\\"annotations\\":{\\"alarms\\":[\\"arn:aws:cloudwatch:\${self:provider.region}:",
Object {
"Ref": "AWS::AccountId",
},
":alarm:",
Object {
"Ref": "HighBuyPriceAlarm",
},
"\\"]},\\"view\\":\\"timeSeries\\",\\"stacked\\":false}},{\\"type\\":\\"metric\\",\\"x\\":18,\\"y\\":13,\\"width\\":6,\\"height\\":6,\\"properties\\":{\\"title\\":\\"High Sell Price\\",\\"annotations\\":{\\"alarms\\":[\\"arn:aws:cloudwatch:\${self:provider.region}:",
Object {
"Ref": "AWS::AccountId",
},
":alarm:",
Object {
"Ref": "HighSellPriceAlarm",
},
"\\"]},\\"view\\":\\"timeSeries\\",\\"stacked\\":false}}]}",
],
],
}
`;
179 changes: 54 additions & 125 deletions cloudformation/dashboard.js
@@ -1,20 +1,18 @@
/* eslint no-template-curly-in-string: "off" */
/* eslint-disable no-template-curly-in-string */

'use strict';

const label = (title, props) => ['.', title, '.', '.', '.', '.', '.', '.', props];
const alarmArn = cfAlarmResource => [
'arn:aws:cloudwatch:${self:provider.region}',
'-SPLIT-Ref:AWS::AccountId-SPLIT-',
'alarm',
`-SPLIT-Ref:${cfAlarmResource}-SPLIT-`,
].join(':');

module.exports.dashboard = () => {
let dashboardTemplate = JSON.stringify({
const json = JSON.stringify({
widgets: [
{
type: 'text',
x: 0,
y: 0,
width: 24,
height: 1,
properties: {
markdown: '## ${self:service}',
},
},
{
type: 'metric',
x: 0,
Expand All @@ -25,7 +23,7 @@ module.exports.dashboard = () => {
view: 'singleValue',
metrics: [
[
'${self:service}',
'${self:custom.cloudWatchNamespace}',
'BuyPrice',
'CryptoCurrency',
'${self:provider.environment.PREFERRED_CRYPTO_CURRENCY}',
Expand All @@ -37,19 +35,9 @@ module.exports.dashboard = () => {
label: 'Buy',
},
],
[
'.',
'SellPrice',
'.',
'.',
'.',
'.',
'.',
'.',
{
label: 'Sell',
},
],
label('SellPrice', {
label: 'Sell',
}),
],
region: '${self:provider.region}',
title: 'Current price in ${self:provider.environment.PREFERRED_LOCAL_CURRENCY}',
Expand All @@ -66,7 +54,7 @@ module.exports.dashboard = () => {
stacked: false,
metrics: [
[
'${self:service}',
'${self:custom.cloudWatchNamespace}',
'BuyPrice',
'CryptoCurrency',
'${self:provider.environment.PREFERRED_CRYPTO_CURRENCY}',
Expand All @@ -79,80 +67,30 @@ module.exports.dashboard = () => {
label: 'Buy actual',
},
],
[
'.',
'SellPrice',
'.',
'.',
'.',
'.',
'.',
'.',
{
color: '#ffbb78',
label: 'Sell actual',
},
],
[
'.',
'BuyPrice',
'.',
'.',
'.',
'.',
'.',
'.',
{
period: 3600,
color: '#1f77b4',
label: 'Buy hourly average',
},
],
[
'.',
'SellPrice',
'.',
'.',
'.',
'.',
'.',
'.',
{
period: 3600,
color: '#ff7f0e',
label: 'Sell hourly average',
},
],
[
'.',
'BuyPrice',
'.',
'.',
'.',
'.',
'.',
'.',
{
period: 86400,
label: 'Buy daily average',
color: '#ff9896',
},
],
[
'.',
'SellPrice',
'.',
'.',
'.',
'.',
'.',
'.',
{
period: 86400,
label: 'Sell daily average',
color: '#98df8a',
},
],
label('SellPrice', {
color: '#ffbb78',
label: 'Sell actual',
}),
label('BuyPrice', {
period: 3600,
color: '#1f77b4',
label: 'Buy hourly average',
}),
label('SellPrice', {
period: 3600,
color: '#ff7f0e',
label: 'Sell hourly average',
}),
label('BuyPrice', {
period: 86400,
label: 'Buy daily average',
color: '#ff9896',
}),
label('SellPrice', {
period: 86400,
label: 'Sell daily average',
color: '#98df8a',
}),
],
region: '${self:provider.region}',
title: 'Buy / Sell ${self:provider.environment.PREFERRED_CRYPTO_CURRENCY}-${self:provider.environment.PREFERRED_LOCAL_CURRENCY}',
Expand All @@ -167,9 +105,7 @@ module.exports.dashboard = () => {
properties: {
title: 'Low Buy Price',
annotations: {
alarms: [
'arn:aws:cloudwatch:${self:provider.region}:JOINREF:AWS::AccountIdJOIN:alarm:JOINREF:LowBuyPriceAlarmJOIN',
],
alarms: [alarmArn('LowBuyPriceAlarm')],
},
view: 'timeSeries',
stacked: false,
Expand All @@ -184,9 +120,7 @@ module.exports.dashboard = () => {
properties: {
title: 'Low Sell Price',
annotations: {
alarms: [
'arn:aws:cloudwatch:${self:provider.region}:JOINREF:AWS::AccountIdJOIN:alarm:JOINREF:LowSellPriceAlarmJOIN',
],
alarms: [alarmArn('LowSellPriceAlarm')],
},
view: 'timeSeries',
stacked: false,
Expand All @@ -201,9 +135,7 @@ module.exports.dashboard = () => {
properties: {
title: 'High Buy Price',
annotations: {
alarms: [
'arn:aws:cloudwatch:${self:provider.region}:JOINREF:AWS::AccountIdJOIN:alarm:JOINREF:HighBuyPriceAlarmJOIN',
],
alarms: [alarmArn('HighBuyPriceAlarm')],
},
view: 'timeSeries',
stacked: false,
Expand All @@ -218,9 +150,7 @@ module.exports.dashboard = () => {
properties: {
title: 'High Sell Price',
annotations: {
alarms: [
'arn:aws:cloudwatch:${self:provider.region}:JOINREF:AWS::AccountIdJOIN:alarm:JOINREF:HighSellPriceAlarmJOIN',
],
alarms: [alarmArn('HighSellPriceAlarm')],
},
view: 'timeSeries',
stacked: false,
Expand All @@ -229,20 +159,19 @@ module.exports.dashboard = () => {
],
});

// because of variable collisions with serverless, we can't use fn:sub
// so we need to split the template to use fn:join to ref the alarms
dashboardTemplate = dashboardTemplate.split('JOIN');
const lines = dashboardTemplate.map((line) => {
if (line.indexOf('REF:') > -1) {
return { Ref: line.replace('REF:', '') };
}
return line;
});
return {
'Fn::Join':
[
'Fn::Join': [
'',
lines,
/*
Because of variable collisions with serverless, we can't use Fn::Sub so we need to split the
template to use Fn::Join to Ref the alarms.
*/
json.split('-SPLIT-').map((line) => {
if (line.includes('Ref:')) {
return { Ref: line.replace('Ref:', '') };
}
return line;
}) // eslint-disable-line
],
};
};
7 changes: 7 additions & 0 deletions cloudformation/dashboard.test.js
@@ -0,0 +1,7 @@
import { dashboard } from './dashboard';

describe('Dashboard', () => {
test('returns cloudformation dashboard body', () => {
expect(dashboard()).toMatchSnapshot();
});
});
9 changes: 5 additions & 4 deletions cloudformation/template.yml
Expand Up @@ -41,7 +41,7 @@ Resources:
Value: ${self:provider.environment.STAGE}
EvaluationPeriods: 1
MetricName: BuyPrice
Namespace: ${self:service}
Namespace: ${self:custom.cloudWatchNamespace}
Period: 60
Statistic: Average
Threshold: ${self:provider.environment.LOW_BUY_PRICE_THRESHOLD}
Expand All @@ -63,7 +63,7 @@ Resources:
Value: ${self:provider.environment.STAGE}
EvaluationPeriods: 1
MetricName: BuyPrice
Namespace: ${self:service}
Namespace: ${self:custom.cloudWatchNamespace}
Period: 300
Statistic: Average
Threshold: ${self:provider.environment.HIGH_BUY_PRICE_THRESHOLD}
Expand All @@ -85,7 +85,7 @@ Resources:
Value: ${self:provider.environment.STAGE}
EvaluationPeriods: 1
MetricName: SellPrice
Namespace: ${self:service}
Namespace: ${self:custom.cloudWatchNamespace}
Period: 300
Statistic: Average
Threshold: ${self:provider.environment.LOW_SELL_PRICE_THRESHOLD}
Expand All @@ -107,12 +107,13 @@ Resources:
Value: ${self:provider.environment.STAGE}
EvaluationPeriods: 1
MetricName: SellPrice
Namespace: ${self:service}
Namespace: ${self:custom.cloudWatchNamespace}
Period: 60
Statistic: Average
Threshold: ${self:provider.environment.HIGH_SELL_PRICE_THRESHOLD}
Unit: Count

# CloudWatch Dashboard displaying custom metrics and alarm states
Dashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
Expand Down
2 changes: 1 addition & 1 deletion lib/cloudWatch.js
Expand Up @@ -20,7 +20,7 @@ export default class CloudWatch {

constructor() {
this.cloudwatch = new AWS.CloudWatch({ region: process.env.REGION || 'eu-central-1' });
this.namespace = process.env.SERVICE_NAME || 'coinboss';
this.namespace = process.env.CLOUDWATCH_NAMESPACE || 'Coinboss';
}

putPriceMetric(args) {
Expand Down
2 changes: 2 additions & 0 deletions serverless.yml
Expand Up @@ -5,6 +5,7 @@ plugins:
- serverless-webpack

custom:
cloudWatchNamespace: Coinboss
highBuyPriceTopicName: ${self:service}-high-buy-price-${self:custom.stage}
lowBuyPriceTopicName: ${self:service}-low-buy-price-${self:custom.stage}
highSellPriceTopicName: ${self:service}-high-sell-price-${self:custom.stage}
Expand All @@ -31,6 +32,7 @@ provider:
BUY_AMOUNT: ${env:BUY_AMOUNT}
SELL_AMOUNT: ${env:SELL_AMOUNT}
# Alarm settings
CLOUDWATCH_NAMESPACE: ${self:custom.cloudWatchNamespace}
LOW_BUY_PRICE_THRESHOLD: ${env:LOW_BUY_PRICE_THRESHOLD}
HIGH_BUY_PRICE_THRESHOLD: ${env:HIGH_BUY_PRICE_THRESHOLD}
LOW_SELL_PRICE_THRESHOLD: ${env:LOW_SELL_PRICE_THRESHOLD}
Expand Down

0 comments on commit 4390209

Please sign in to comment.