Skip to content

Instantly share code, notes, and snippets.

@ssippe
Created March 21, 2024 02:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ssippe/1e3a3455eafdd6f57ce7001fcb4858ee to your computer and use it in GitHub Desktop.
Save ssippe/1e3a3455eafdd6f57ce7001fcb4858ee to your computer and use it in GitHub Desktop.
Create a dashboard per asg that beats the 3hr aws CloudWatch Metrics Insights limit
using Amazon.AutoScaling.Model;
using Amazon.AutoScaling;
using Amazon.CloudWatch.Model;
using Amazon;
using Amazon.CloudWatch;
const string Namespace = "CWAgent";
const string MetricName = "TCPv4 Connections Established";
var response = await GetMetrics();
var asgs = GetAsgForMetric(response);
var asgEnvTable = await GetAsgEbEnvs(asgs);
var asgInstanceDic = GetAsgInstanceDic(response);
var widgets = asgEnvTable.OrderByDescending(f=>f.EbEnv).Select((row, idx) => GetDashboardWidgetObj(asgInstanceDic[row.Asg], row.Asg, row.EbEnv, idx)).ToList();
var dashboardObj = GetDashboardObj(widgets);
var dashboardJsonString = System.Text.Json.JsonSerializer.Serialize(dashboardObj);
await CreateDashboard($"TCP_{DateTime.Now.ToString("yyyy-MM-dd")}", dashboardJsonString);
static async Task<IReadOnlyList<(string Asg, string EbEnv)>> GetAsgEbEnvs(IEnumerable<string> asgs)
{
var asgEbEnvs = await GetAsgEbEnvsByCurrentAsg();
var table = asgs.Select(asg => (asg, asgEbEnvs.SingleOrDefault(ae => ae.Asg == asg).EbEnv)).ToList();
return table;
}
static async Task<ListMetricsResponse> ListMetricsUntilDone(ListMetricsRequest req, AmazonCloudWatchClient client)
{
ListMetricsResponse? mainRespone = null;
while (true)
{
var response = await client.ListMetricsAsync(req);
if (mainRespone == null)
{
mainRespone = response;
}
else
{
mainRespone.Metrics.AddRange(response.Metrics);
}
if (string.IsNullOrEmpty(response.NextToken))
{
return mainRespone;
}
req.NextToken = response.NextToken;
}
}
static async Task<ListMetricsResponse> GetMetrics()
{
using var client = new Amazon.CloudWatch.AmazonCloudWatchClient(RegionEndpoint.APSoutheast2);
var request = new Amazon.CloudWatch.Model.ListMetricsRequest
{
Namespace = Namespace,
MetricName = MetricName,
};
var response = await ListMetricsUntilDone(request, client);
return response;
}
static IReadOnlyList<string> GetAsgForMetric(ListMetricsResponse response)
{
var asgs = response.Metrics.Select(m => m.Dimensions.Single(d => d.Name == "AutoScalingGroupName").Value).Distinct().ToList();
return asgs;
}
static async Task<IReadOnlyList<(string Asg, string EbEnv)>> GetAsgEbEnvsByCurrentAsg()
{
using var client = new AmazonAutoScalingClient(RegionEndpoint.APSoutheast2);
var response = await client.DescribeAutoScalingGroupsAsync(new DescribeAutoScalingGroupsRequest());
var asgEbEnvs = response.AutoScalingGroups.Select(asg => (asg.AutoScalingGroupName, asg.Tags.SingleOrDefault(t => t.Key == "elasticbeanstalk:environment-name")?.Value)).ToList();
return asgEbEnvs;
}
static IReadOnlyDictionary<string, IEnumerable<string>> GetAsgInstanceDic(ListMetricsResponse response) =>
response.Metrics.GroupBy(m => m.Dimensions.Single(d => d.Name == "AutoScalingGroupName").Value).ToDictionary(g => g.Key, g => g.Select(m => m.Dimensions.Single(d => d.Name == "InstanceId").Value));
static object GetDashboardObj(IEnumerable<object> widgets) => new { widgets };
static object GetDashboardWidgetObj(IEnumerable<string> instanceIds, string asg, string name, int idx)
{
const int height = 10;
var obj = new
{
metrics = instanceIds.Select(instanceId => new[] { "CWAgent", "TCPv4 Connections Established", "InstanceId", instanceId, "AutoScalingGroupName", asg, "objectname", "TCPv4" }),
title = $"Max(TCPv4 Conn Est) {asg} {name}",
stat = "Maximum",
view = "timeSeries",
stacked = false,
region = "ap-southeast-2",
};
return new
{
properties = obj,
type = "metric",
x = 0,
y = height * idx,
width = 24,
height = height
};
}
static async Task CreateDashboard(string dashboardName, string dashboardBody)
{
using var client = new AmazonCloudWatchClient(RegionEndpoint.APSoutheast2);
var request = new PutDashboardRequest
{
DashboardName = dashboardName,
DashboardBody = dashboardBody
};
var response = await client.PutDashboardAsync(request);
Console.WriteLine(response);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment