@ddegtyarev/aws-tools
Version:
This project contains AWS API integration tools for use in Vertex AI SDK.
209 lines (208 loc) • 8.27 kB
JavaScript
// src/tools/awsCloudWatchGetMetrics.ts
import { CloudWatchClient, GetMetricDataCommand } from '@aws-sdk/client-cloudwatch';
import { validateParameters } from '../utils/validation.js';
function generateMetricsSummary(datapoints, namespace, metricName) {
if (!datapoints || datapoints.length === 0) {
return `No ${metricName} metrics found for ${namespace}.`;
}
const values = datapoints.map(dp => dp.Value).filter(v => v !== undefined && v !== null);
if (values.length === 0) {
return `No valid ${metricName} data points found for ${namespace}.`;
}
const min = Math.min(...values);
const max = Math.max(...values);
const avg = values.reduce((sum, val) => sum + val, 0) / values.length;
const total = values.reduce((sum, val) => sum + val, 0);
const timeRange = `${datapoints[0]?.Timestamp} to ${datapoints[datapoints.length - 1]?.Timestamp}`;
return `${metricName} metrics for ${namespace} (${timeRange}): ` +
`Min: ${min.toFixed(2)}, Max: ${max.toFixed(2)}, Average: ${avg.toFixed(2)}, Total: ${total.toFixed(2)}. ` +
`Data points: ${datapoints.length}.`;
}
function generateVegaLiteChart(datapoints, namespace, metricName) {
if (!datapoints || datapoints.length === 0) {
return {};
}
// Transform datapoints for Vega-Lite
const chartData = datapoints.map(dp => ({
timestamp: dp.Timestamp,
value: dp.Value,
unit: dp.Unit
}));
const vegaLiteSpec = {
$schema: 'https://vega.github.io/schema/vega-lite/v5.json',
description: `${metricName} metrics for ${namespace}`,
width: 600,
height: 300,
data: {
values: chartData
},
mark: {
type: 'line',
point: true
},
encoding: {
x: {
field: 'timestamp',
type: 'temporal',
title: 'Time',
axis: {
format: '%Y-%m-%d',
labelAngle: -45
}
},
y: {
field: 'value',
type: 'quantitative',
title: metricName,
scale: {
zero: false
}
},
tooltip: [
{
field: 'timestamp',
type: 'temporal',
title: 'Time',
format: '%Y-%m-%d %H:%M:%S'
},
{
field: 'value',
type: 'quantitative',
title: metricName,
format: ',.2f'
},
{
field: 'unit',
type: 'nominal',
title: 'Unit'
}
]
},
config: {
axis: {
labelFontSize: 12,
titleFontSize: 14
},
title: {
fontSize: 16,
fontWeight: 'bold'
}
}
};
return vegaLiteSpec;
}
export const awsCloudWatchGetMetrics = {
name: 'awsCloudWatchGetMetrics',
description: 'Retrieve CloudWatch metrics for any AWS service with flexible dimensions and time periods. Essential for analyzing performance trends, usage patterns, and operational metrics.',
inputSchema: {
type: 'object',
properties: {
namespace: { type: 'string', description: 'AWS namespace (e.g., "AWS/Lambda", "AWS/EC2", "AWS/RDS")' },
metricName: { type: 'string', description: 'Metric name (e.g., "Invocations", "Duration", "Errors")' },
dimensions: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Dimension name (e.g., "FunctionName")' },
value: { type: 'string', description: 'Dimension value (e.g., specific function name)' },
},
required: ['name', 'value'],
},
description: 'Dimensions to filter the metric',
},
startTime: { type: 'string', description: 'Start time in ISO format (e.g., "2024-01-01T00:00:00Z")' },
endTime: { type: 'string', description: 'End time in ISO format (e.g., "2024-01-31T23:59:59Z")' },
period: { type: 'number', description: 'Period in seconds (300=5min, 3600=1hour, 86400=1day)' },
statistic: { type: 'string', enum: ['Sum', 'Average', 'Maximum', 'Minimum', 'SampleCount'], description: 'Statistic to retrieve' },
},
required: ['namespace', 'metricName', 'startTime', 'endTime', 'period', 'statistic'],
},
outputSchema: {
type: 'object',
properties: {
summary: { type: 'string', description: 'Text summary of the CloudWatch metrics' },
datapoints: {
type: 'array',
items: {
type: 'object',
properties: {
Timestamp: { type: 'string' },
Value: { type: 'number' },
Unit: { type: 'string' },
},
},
},
chart: { type: 'object', description: 'Vega-Lite TopLevelSpec object for generating an SVG chart' },
},
},
configSchema: {
type: 'object',
properties: {
credentials: {
type: 'object',
properties: {
accessKeyId: { type: 'string' },
secretAccessKey: { type: 'string' },
sessionToken: { type: 'string' },
},
required: ['accessKeyId', 'secretAccessKey'],
},
region: { type: 'string', description: 'AWS region' },
logger: { type: 'object' },
},
required: ['credentials', 'region'],
},
defaultConfig: {},
async invoke(input, config) {
const { logger } = config;
// Validate input and config against schemas
validateParameters(input, this.inputSchema, config, this.configSchema, logger);
const { namespace, metricName, dimensions, startTime, endTime, period, statistic } = input;
const { region } = config;
logger?.debug('awsCloudWatchGetMetrics input:', input);
const cloudWatchClient = new CloudWatchClient({ region, credentials: config.credentials });
const command = new GetMetricDataCommand({
MetricDataQueries: [
{
Id: 'm1',
MetricStat: {
Metric: {
Namespace: namespace,
MetricName: metricName,
Dimensions: dimensions?.map((d) => ({ Name: d.name, Value: d.value })),
},
Period: period,
Stat: statistic,
},
ReturnData: true,
},
],
StartTime: new Date(startTime),
EndTime: new Date(endTime),
});
try {
const data = await cloudWatchClient.send(command);
logger?.debug('awsCloudWatchGetMetrics raw data:', data);
const result = data.MetricDataResults?.[0];
const datapoints = result?.Timestamps?.map((t, i) => ({
Timestamp: t.toISOString(),
Value: result.Values?.[i],
Unit: result.Values?.[i] ? result.Label : '',
})) || [];
const summary = generateMetricsSummary(datapoints, namespace, metricName);
const chart = generateVegaLiteChart(datapoints, namespace, metricName);
const output = {
summary,
datapoints,
chart,
};
logger?.debug('awsCloudWatchGetMetrics output:', output);
return output;
}
catch (error) {
logger?.error('Error getting CloudWatch metrics:', error);
throw error;
}
},
};