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

feat(aws-cloudwatch): log query widget visualisation types #9694

Merged
merged 8 commits into from
Aug 18, 2020
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-cloudwatch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ A `LogQueryWidget` shows the results of a query from Logs Insights:
```ts
dashboard.addWidgets(new LogQueryWidget({
logGroupNames: ['my-log-group'],
view: LogQueryVisualizationType.TABLE,
// The lines will be automatically combined using '\n|'.
queryLines: [
'fields @message',
Expand Down
54 changes: 48 additions & 6 deletions packages/@aws-cdk/aws-cloudwatch/lib/log-query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
import * as cdk from '@aws-cdk/core';
import { ConcreteWidget } from './widget';

/**
* Types of view
*/
export enum LogQueryVisualizationType {
/**
* Table view
*/
TABLE = 'table',
/**
* Line view
*/
LINE = 'line',
/**
* Stacked area view
*/
STACKEDAREA = 'stackedarea',
/**
* Bar view
*/
BAR = 'bar',
/**
* Pie view
*/
PIE = 'pie',
}

/**
* Properties for a Query widget
*/
Expand Down Expand Up @@ -43,6 +69,13 @@ export interface LogQueryWidgetProps {
*/
readonly region?: string;

/**
* The type of view to use
*
* @default LogQueryVisualizationType.TABLE
*/
readonly view?: LogQueryVisualizationType;

/**
* Width of the widget, in a grid of 24 units wide
*
Expand Down Expand Up @@ -83,18 +116,27 @@ export class LogQueryWidget extends ConcreteWidget {
? this.props.queryLines.join('\n| ')
: this.props.queryString;

const properties: any = {
view: this.props.view? this.props.view : LogQueryVisualizationType.TABLE,
title: this.props.title,
region: this.props.region || cdk.Aws.REGION,
query: `${sources} | ${query}`,
};

// adding stacked property in case of LINE or STACKEDAREA
if (this.props.view === LogQueryVisualizationType.LINE || this.props.view === LogQueryVisualizationType.STACKEDAREA) {
// assign the right native view value. both types share the same value
properties.view = 'timeSeries',
properties.stacked = this.props.view === LogQueryVisualizationType.STACKEDAREA ? true : false;
}

return [{
type: 'log',
width: this.width,
height: this.height,
x: this.x,
y: this.y,
properties: {
view: 'table',
title: this.props.title,
region: this.props.region || cdk.Aws.REGION,
query: `${sources} | ${query}`,
},
properties: properties,
}];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":23,\"properties\":{\"view\":\"bar\",\"title\":\"Errors in my log group - bar\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":29,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - line\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":false}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":35,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - stacked\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":true}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":41,\"properties\":{\"view\":\"pie\",\"title\":\"Errors in my log group - pie\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}}]}"
]
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as cloudwatch from '../lib';

const app = new cdk.App();

const stack = new cdk.Stack(app, 'aws-cdk-cloudwatch');
const stack = new cdk.Stack(app, 'aws-cdk-cloudwatch-alarms');

const queue = new cdk.CfnResource(stack, 'queue', { type: 'AWS::SQS::Queue' });

Expand Down Expand Up @@ -54,5 +54,33 @@ dashboard.addWidgets(new cloudwatch.LogQueryWidget({
queryString: `fields @message
| filter @message like /Error/`,
}));
dashboard.addWidgets(new cloudwatch.LogQueryWidget({
title: 'Errors in my log group - bar',
view: cloudwatch.LogQueryVisualizationType.BAR,
logGroupNames: ['my-log-group'],
queryString: `fields @message
| filter @message like /Error/`,
}));
dashboard.addWidgets(new cloudwatch.LogQueryWidget({
title: 'Errors in my log group - line',
view: cloudwatch.LogQueryVisualizationType.LINE,
logGroupNames: ['my-log-group'],
queryString: `fields @message
| filter @message like /Error/`,
}));
dashboard.addWidgets(new cloudwatch.LogQueryWidget({
title: 'Errors in my log group - stacked',
view: cloudwatch.LogQueryVisualizationType.STACKEDAREA,
logGroupNames: ['my-log-group'],
queryString: `fields @message
| filter @message like /Error/`,
}));
dashboard.addWidgets(new cloudwatch.LogQueryWidget({
title: 'Errors in my log group - pie',
view: cloudwatch.LogQueryVisualizationType.PIE,
logGroupNames: ['my-log-group'],
queryString: `fields @message
| filter @message like /Error/`,
}));

app.synth();
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,31 @@
[
"(((ALARM(",
{
"Fn::GetAtt": [ "Alarm1F9009D71", "Arn" ]
"Fn::GetAtt": [
"Alarm1F9009D71",
"Arn"
]
},
") OR OK(",
{
"Fn::GetAtt": [ "Alarm2A7122E13", "Arn" ]
"Fn::GetAtt": [
"Alarm2A7122E13",
"Arn"
]
},
") OR ALARM(",
{
"Fn::GetAtt": [ "Alarm32341D8D9", "Arn" ]
"Fn::GetAtt": [
"Alarm32341D8D9",
"Arn"
]
},
")) AND (NOT (INSUFFICIENT_DATA(",
{
"Fn::GetAtt":[ "Alarm4671832C8", "Arn" ]
"Fn::GetAtt": [
"Alarm4671832C8",
"Arn"
]
},
")))) OR FALSE)"
]
Expand Down
124 changes: 123 additions & 1 deletion packages/@aws-cdk/aws-cloudwatch/test/test.graphs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Stack } from '@aws-cdk/core';
import { Test } from 'nodeunit';
import { Alarm, AlarmWidget, Color, GraphWidget, LegendPosition, LogQueryWidget, Metric, Shading, SingleValueWidget } from '../lib';
import { Alarm, AlarmWidget, Color, GraphWidget, LegendPosition, LogQueryWidget, Metric, Shading, SingleValueWidget, LogQueryVisualizationType } from '../lib';

export = {
'add stacked property to graphs'(test: Test) {
Expand Down Expand Up @@ -142,6 +142,128 @@ export = {
test.done();
},

'query result widget - bar'(test: Test) {
// GIVEN
const stack = new Stack();
const logGroup = {logGroupName: 'my-log-group'};

// WHEN
const widget = new LogQueryWidget({
logGroupNames: [logGroup.logGroupName],
view: LogQueryVisualizationType.BAR,
queryLines: [
'fields @message',
'filter @message like /Error/',
],
});

// THEN
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'log',
width: 6,
height: 6,
properties: {
view: 'bar',
region: { Ref: 'AWS::Region' },
query: `SOURCE '${logGroup.logGroupName}' | fields @message\n| filter @message like /Error/`,
},
}]);

test.done();
},

'query result widget - pie'(test: Test) {
// GIVEN
const stack = new Stack();
const logGroup = {logGroupName: 'my-log-group'};

// WHEN
const widget = new LogQueryWidget({
logGroupNames: [logGroup.logGroupName],
view: LogQueryVisualizationType.PIE,
queryLines: [
'fields @message',
'filter @message like /Error/',
],
});

// THEN
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'log',
width: 6,
height: 6,
properties: {
view: 'pie',
region: { Ref: 'AWS::Region' },
query: `SOURCE '${logGroup.logGroupName}' | fields @message\n| filter @message like /Error/`,
},
}]);

test.done();
},

'query result widget - line'(test: Test) {
// GIVEN
const stack = new Stack();
const logGroup = {logGroupName: 'my-log-group'};

// WHEN
const widget = new LogQueryWidget({
logGroupNames: [logGroup.logGroupName],
view: LogQueryVisualizationType.LINE,
queryLines: [
'fields @message',
'filter @message like /Error/',
],
});

// THEN
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'log',
width: 6,
height: 6,
properties: {
view: 'timeSeries',
stacked: false,
region: { Ref: 'AWS::Region' },
query: `SOURCE '${logGroup.logGroupName}' | fields @message\n| filter @message like /Error/`,
},
}]);

test.done();
},

'query result widget - stackedarea'(test: Test) {
// GIVEN
const stack = new Stack();
const logGroup = {logGroupName: 'my-log-group'};

// WHEN
const widget = new LogQueryWidget({
logGroupNames: [logGroup.logGroupName],
view: LogQueryVisualizationType.STACKEDAREA,
queryLines: [
'fields @message',
'filter @message like /Error/',
],
});

// THEN
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'log',
width: 6,
height: 6,
properties: {
view: 'timeSeries',
stacked: true,
region: { Ref: 'AWS::Region' },
query: `SOURCE '${logGroup.logGroupName}' | fields @message\n| filter @message like /Error/`,
},
}]);

test.done();
},

'alarm widget'(test: Test) {
// GIVEN
const stack = new Stack();
Expand Down