full-dress-10026
04/24/2019, 5:14 PM.metrics
from a FargateService
?.metrics
property.white-balloon-205
lemon-spoon-91807
04/24/2019, 5:23 PMfull-dress-10026
04/24/2019, 5:23 PMlemon-spoon-91807
04/24/2019, 5:24 PMnew awsx.cloudwatch.Metric({ args })
full-dress-10026
04/24/2019, 5:25 PMlemon-spoon-91807
04/24/2019, 5:29 PMfull-dress-10026
04/24/2019, 5:30 PMlemon-spoon-91807
04/24/2019, 5:30 PMawsx.ecs.metrics.memoryUtilization({ service })
full-dress-10026
04/24/2019, 5:32 PMlemon-spoon-91807
04/24/2019, 5:32 PMfull-dress-10026
04/24/2019, 5:38 PMnew awsx.cloudwatch.LineGraphMetricWidget({
title: "Metrics Streams CPU",
metrics: [
awsx.ecs.metrics.cpuUtilization({
cluster: dashboardArgs.metricsStreamsService.cluster,
service: dashboardArgs.metricsStreamsService.service,
statistic: "Minimum",
label: "min"
}),
awsx.ecs.metrics.cpuUtilization({
cluster: dashboardArgs.metricsStreamsService.cluster,
service: dashboardArgs.metricsStreamsService.service,
statistic: "Maximum",
label: "max"
})
]
})
One of those would be created per service, resulting in a lot of copy/paste. Not sure if this is something that could be handled by this API.lemon-spoon-91807
04/24/2019, 5:39 PMfor
-loop over your servicesawsx.ecs.metrics.cpuUtilization({
cluster: dashboardArgs.metricsStreamsService.cluster,
service: dashboardArgs.metricsStreamsService.service,
awsx.ecs.metrics.cpuUtilization({
service: dashboardArgs.metricsStreamsService,
full-dress-10026
04/24/2019, 5:40 PMlemon-spoon-91807
04/24/2019, 5:40 PMfull-dress-10026
04/24/2019, 5:50 PMlemon-spoon-91807
04/24/2019, 5:50 PMfull-dress-10026
04/24/2019, 6:15 PMwidgets
? For example:
function fargateServiceCpuMemGraphs(service: awsx.ecs.FargateService) {
return service.service.name.apply(serviceName => {
return [
new awsx.cloudwatch.LineGraphMetricWidget({
title: `${serviceName} CPU`,
metrics: [
awsx.ecs.metrics.cpuUtilization({
service: service,
statistic: "Minimum",
label: "min"
}),
awsx.ecs.metrics.cpuUtilization({
service: service,
statistic: "Maximum",
label: "max"
})
]
}),
new awsx.cloudwatch.LineGraphMetricWidget({
title: `${serviceName} Memory`,
metrics: [
awsx.ecs.metrics.memoryUtilization({
service: service,
statistic: "Minimum",
label: "min"
}),
awsx.ecs.metrics.memoryUtilization({
service: service,
statistic: "Maximum",
label: "max"
})
]
})
];
});
}
new awsx.cloudwatch.Dashboard("cw-dashboard-" + env, {
name: `vm-scaler-${env}`,
widgets: pulumi.all([
fargateServiceCpuMemGraphs(dashboardArgs.workloadMetricsWorkerService),
fargateServiceCpuMemGraphs(dashboardArgs.workloadMetricsWorkerService)
]).apply(function ([graphs1, graphs2]) {
return graphs1.concat(graphs2);
})
});
lemon-spoon-91807
04/24/2019, 6:23 PMfull-dress-10026
04/24/2019, 6:23 PMfunction fargateServiceCpuMemGraphs(service: awsx.ecs.FargateService) {
const serviceName = service.service.name;
return [
new awsx.cloudwatch.LineGraphMetricWidget({
title: serviceName.apply(n => `${n} CPU`),
metrics: [
awsx.ecs.metrics.cpuUtilization({
service: service,
statistic: "Minimum",
label: "min"
}),
awsx.ecs.metrics.cpuUtilization({
service: service,
statistic: "Maximum",
label: "max"
})
]
}),
new awsx.cloudwatch.LineGraphMetricWidget({
title: serviceName.apply(n => `${n} Memory`),
metrics: [
awsx.ecs.metrics.memoryUtilization({
service: service,
statistic: "Minimum",
label: "min"
}),
awsx.ecs.metrics.memoryUtilization({
service: service,
statistic: "Maximum",
label: "max"
})
]
})
];
}
lemon-spoon-91807
04/24/2019, 6:23 PMtitle: pulumi.interpolate `${service.name} CPU`,
full-dress-10026
04/24/2019, 6:23 PMlemon-spoon-91807
04/24/2019, 6:24 PMservice: service,
is also redundant in JS. but it's a personal pref. you an say: service
full-dress-10026
04/24/2019, 6:25 PM${serviceName} CPU
),` gives Argument of type 'string' is not assignable to parameter of type 'TemplateStringsArray'
.
Coming from Clojure, I prefer the explicit syntax 🙂lemon-spoon-91807
04/24/2019, 6:25 PMpulumi.interpolate`${service.name} CPU`
foo(`${...} bar`)
`${...} bar`
is just a normal interpolationfoo
the actual template pieces and args, you do foo`${...} bar`
serviceName.apply(n => `${n} CPU`),
is also fineinterpolate
is doingfull-dress-10026
04/24/2019, 6:27 PMlemon-spoon-91807
04/24/2019, 6:27 PMpulumi.interpolate`${cluster.name} - ${service.name}`
pulumi.all([cluster.name, service.name]).apply(([cn, sn]) => `${sn} - {cn}`)
full-dress-10026
04/24/2019, 6:29 PMwidgetMatrix: [[r1c1 r1c2, ..., r1cN], [r2c1, r2c2, ... r2cN]]
lemon-spoon-91807
04/24/2019, 6:30 PMwidgets: [new RowWidget(r1c1, r1c2, ..., r1cN), new RowWidet(r2c1, r2c2, ... r2cN)]
full-dress-10026
04/24/2019, 6:32 PMlemon-spoon-91807
04/24/2019, 6:32 PMfull-dress-10026
04/24/2019, 6:33 PMlemon-spoon-91807
04/24/2019, 6:33 PMnew RowWidget(...list)
🙂full-dress-10026
04/24/2019, 6:37 PMfunction rows(rs: awsx.cloudwatch.Widget[][]) {
return rs.map(cols => new awsx.cloudwatch.RowWidget(...cols))
}
lemon-spoon-91807
04/24/2019, 6:41 PMfull-dress-10026
04/24/2019, 7:50 PMRowWidget
with 5 LineGraphMetricWidget
and then several more row widgets with 2 LineGraphMetricWidget
each. Example:
[[r1c1, r1c2, r1c3, r1c4, r1c5]
[r2c1, r2c2]
[r3c1, r3c2]]
But in the CloudWatch UI, it renders like this:
[[r1c1, r1c2, r1c3, r1c4]
[r1c5, r2c1]
[r2c2, r3c1]
[r3c2]]
I would've expected this:
[[r1c1, r1c2, r1c3, r1c4]
[r1c5]
[r2c1, r2c2]
[r3c1, r3c2]]
lemon-spoon-91807
04/24/2019, 8:37 PMfull-dress-10026
04/24/2019, 8:38 PMlemon-spoon-91807
04/24/2019, 8:39 PM[Dashboard]s are represented by a grid of columns 24 wide, with an unlimited number of rows.
The width of the widget in grid units (in a 24-column grid). The default is 6.
Represents a horizontal sequence of [Widget]s in the [Dashboard]. Widgets are laid out horizontally in the grid until it would go past the max width of 24 columns. When that happens, the widgets will wrap to the next available grid row.
full-dress-10026
04/24/2019, 8:41 PMlemon-spoon-91807
04/24/2019, 8:41 PMfull-dress-10026
04/24/2019, 8:42 PMimport * as awsx from "@pulumi/awsx";
import * as pulumi from "@pulumi/pulumi";
interface DashArgs {
metricsStreamsService: awsx.ecs.FargateService
aggregateStreamsService: awsx.ecs.FargateService
modelExecutorService: awsx.ecs.FargateService
modelUpdaterService: awsx.ecs.FargateService
workloadMetricsWorkerService: awsx.ecs.FargateService
appIonsService: awsx.ecs.FargateService,
appIonsLb: awsx.elasticloadbalancingv2.ApplicationLoadBalancer
}
function fargateServiceCpuMemGraphs(service: awsx.ecs.FargateService) {
const serviceName = service.service.name;
return [
new awsx.cloudwatch.LineGraphMetricWidget({
title: pulumi.interpolate`${serviceName} CPU`,
metrics: [
awsx.ecs.metrics.cpuUtilization({
service: service,
statistic: "Minimum",
label: "min"
}),
awsx.ecs.metrics.cpuUtilization({
service: service,
statistic: "Maximum",
label: "max"
})
]
}),
new awsx.cloudwatch.LineGraphMetricWidget({
title: pulumi.interpolate`${serviceName} Memory`,
metrics: [
awsx.ecs.metrics.memoryUtilization({
service: service,
statistic: "Minimum",
label: "min"
}),
awsx.ecs.metrics.memoryUtilization({
service: service,
statistic: "Maximum",
label: "max"
})
]
})
];
}
function rows(rs: awsx.cloudwatch.Widget[][]) {
return rs.map(cols => new awsx.cloudwatch.RowWidget(...cols))
}
export function createDashboard(env: string, dashboardArgs: DashArgs) {
// dashboardArgs.appIonsService.service.loadBalancers
new awsx.cloudwatch.Dashboard("cw-dashboard-" + env, {
name: `vm-scaler-${env}`,
widgets: rows([
fargateServiceCpuMemGraphs(dashboardArgs.appIonsService)
.concat([
new awsx.cloudwatch.LineGraphMetricWidget({
title: "HTTP Target Response Time",
metrics: [awsx.elasticloadbalancingv2.metrics.application.targetResponseTime(dashboardArgs.appIonsLb)]
}),
new awsx.cloudwatch.LineGraphMetricWidget({
title: "HTTP Requests",
metrics: [awsx.elasticloadbalancingv2.metrics.application.requestCount(dashboardArgs.appIonsLb)]
}),
new awsx.cloudwatch.LineGraphMetricWidget({
title: "HTTP 5XXs",
metrics: [awsx.elasticloadbalancingv2.metrics.application.httpCodeTarget5XXCount(dashboardArgs.appIonsLb)]
})]),
fargateServiceCpuMemGraphs(dashboardArgs.workloadMetricsWorkerService),
fargateServiceCpuMemGraphs(dashboardArgs.metricsStreamsService),
fargateServiceCpuMemGraphs(dashboardArgs.aggregateStreamsService),
fargateServiceCpuMemGraphs(dashboardArgs.modelExecutorService),
fargateServiceCpuMemGraphs(dashboardArgs.modelUpdaterService)
])
});
}
lemon-spoon-91807
04/24/2019, 8:44 PMfull-dress-10026
04/24/2019, 8:45 PMlemon-spoon-91807
04/24/2019, 8:46 PMfull-dress-10026
04/24/2019, 8:50 PMlemon-spoon-91807
04/24/2019, 8:54 PMfull-dress-10026
04/25/2019, 5:05 PM