Skip to content

Commit

Permalink
feat(aws-cloudwatch): query results widget
Browse files Browse the repository at this point in the history
Add a `QueryWidget` to generate a dashboard widget
showing the results of a query from Logs Insights.
This was a missing feature which is available in
the console.
Also make `ILogGroup` extend `cloudwatch.IQueryLogGroup`
so it can be passed as a property for a `QueryWidget`.

closes aws#3681
  • Loading branch information
Oliver Gavin authored and OliverGavin committed Apr 25, 2020
1 parent 1423c53 commit 300a79f
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 9 deletions.
12 changes: 12 additions & 0 deletions packages/@aws-cdk/aws-cloudwatch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,18 @@ dashboard.addWidgets(new TextWidget({
}));
```

### Query results widget

A query results widget shows the results of a query from Logs Insights:

```ts
dashboard.addWidgets(new QueryWidget({
logGroup: LogGroup.fromLogGroupName(stack, 'MyLogGroup', 'my-log-group'),
queryString: `fields @message
| filter @message like /Error/`
}));
```

### Dashboard Layout

The widgets on a dashboard are visually laid out in a grid that is 24 columns
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-cloudwatch/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './graph';
export * from './layout';
export * from './metric';
export * from './metric-types';
export * from './query';
export * from './text';
export * from './widget';

Expand Down
83 changes: 83 additions & 0 deletions packages/@aws-cdk/aws-cloudwatch/lib/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as cdk from '@aws-cdk/core';
import { ConcreteWidget } from './widget';

/**
* Allows any object providing a logGroupName to be supplied to a QueryWidget such as an ILogGroup.
*/
export interface IQueryLogGroup {
/**
* The name of this log group
*/
readonly logGroupName: string;
}

/**
* Properties for a Query widget
*/
export interface QueryWidgetProps {
/**
* Title for the widget
*
* @default No title
*/
readonly title?: string;

/**
* Log group to query
*/
readonly logGroup: IQueryLogGroup; // ILogGroup cannot be used without creating cyclic dependencies.

/**
* Query for log insights
*/
readonly queryString: string;

/**
* The region the metrics of this widget should be taken from
*
* @default Current region
*/
readonly region?: string;

/**
* Width of the widget, in a grid of 24 units wide
*
* @default 6
*/
readonly width?: number;

/**
* Height of the widget
*
* @default 6
*/
readonly height?: number;
}

/**
* Display query results from Logs Insights
*/
export class QueryWidget extends ConcreteWidget {
private readonly props: QueryWidgetProps;

constructor(props: QueryWidgetProps) {
super(props.width || 6, props.height || 6);
this.props = props;
}

public toJson(): any[] {
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: `SOURCE '${this.props.logGroup.logGroupName}' | ${this.props.queryString}`,
},
}];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@
"QueueName"
]
},
"\"]]}}]}"
"\"]]}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":17,\"properties\":{\"view\":\"table\",\"title\":\"Errors in my log group\",\"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 @@ -48,5 +48,11 @@ dashboard.addWidgets(new cloudwatch.SingleValueWidget({
title: 'Current messages in queue',
metrics: [metric],
}));
dashboard.addWidgets(new cloudwatch.QueryWidget({
title: 'Errors in my log group',
logGroup: {logGroupName: 'my-log-group'},
queryString: `fields @message
| filter @message like /Error/`,
}));

app.synth();
30 changes: 29 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, Metric, Shading, SingleValueWidget } from '../lib';
import { Alarm, AlarmWidget, Color, GraphWidget, Metric, QueryWidget, Shading, SingleValueWidget } from '../lib';

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

'query result widget'(test: Test) {
// GIVEN
const stack = new Stack();
const logGroup = {logGroupName: 'my-log-group'};
const queryString = `fields @message
| filter @message like /Error/`;

// WHEN
const widget = new QueryWidget({
logGroup,
queryString,
});

// THEN
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'log',
width: 6,
height: 6,
properties: {
view: 'table',
region: { Ref: 'AWS::Region' },
query: `SOURCE '${logGroup.logGroupName}' | ${queryString}`,
},
}]);

test.done();
},

'alarm widget'(test: Test) {
// GIVEN
const stack = new Stack();
Expand Down
8 changes: 1 addition & 7 deletions packages/@aws-cdk/aws-logs/lib/log-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,13 @@ import { MetricFilter } from './metric-filter';
import { FilterPattern, IFilterPattern } from './pattern';
import { ILogSubscriptionDestination, SubscriptionFilter } from './subscription-filter';

export interface ILogGroup extends IResource {
export interface ILogGroup extends IResource, cloudwatch.IQueryLogGroup {
/**
* The ARN of this log group
* @attribute
*/
readonly logGroupArn: string;

/**
* The name of this log group
* @attribute
*/
readonly logGroupName: string;

/**
* Create a new Log Stream for this Log Group
*
Expand Down

0 comments on commit 300a79f

Please sign in to comment.