的第 4 版 (V4) 适用于 .NET 的 Amazon SDK 已经发布!
有关重大更改和迁移应用程序的信息,请参阅迁移主题。
本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
CloudWatch 使用示例 适用于 .NET 的 Amazon SDK (v4)
以下代码示例向您展示了如何使用和 适用于 .NET 的 Amazon SDK (v4) 来执行操作和实现常见场景。 CloudWatch
基本功能是向您展示如何在服务中执行基本操作的代码示例。
操作是大型程序的代码摘录,必须在上下文中运行。您可以通过操作了解如何调用单个服务函数,还可以通过函数相关场景的上下文查看操作。
场景是向您演示如何通过在一个服务中调用多个函数或与其他 Amazon Web Services 服务结合来完成特定任务的代码示例。
每个示例都包含一个指向完整源代码的链接,您可以从中找到有关如何在上下文中设置和运行代码的说明。
开始使用
以下代码示例展示了如何开始使用 CloudWatch。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 using Amazon.CloudWatch; using Amazon.CloudWatch.Model; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace CloudWatchActions; public static class HelloCloudWatch { static async Task Main(string[] args) { // Use the AWS .NET Core Setup package to set up dependency injection for the Amazon CloudWatch service. // Use your AWS profile name, or leave it blank to use the default profile. using var host = Host.CreateDefaultBuilder(args) .ConfigureServices((_, services) => services.AddAWSService<IAmazonCloudWatch>() ).Build(); // Now the client is available for injection. var cloudWatchClient = host.Services.GetRequiredService<IAmazonCloudWatch>(); // You can use await and any of the async methods to get a response. var metricNamespace = "AWS/Billing"; var response = await cloudWatchClient.ListMetricsAsync(new ListMetricsRequest { Namespace = metricNamespace }); Console.WriteLine($"Hello Amazon CloudWatch! Following are some metrics available in the {metricNamespace} namespace:"); Console.WriteLine(); if (response.Metrics != null) { foreach (var metric in response.Metrics.Take(5)) { Console.WriteLine($"\tMetric: {metric.MetricName}"); Console.WriteLine($"\tNamespace: {metric.Namespace}"); Console.WriteLine( $"\tDimensions: {string.Join(", ", metric.Dimensions.Select(m => $"{m.Name}:{m.Value}"))}"); Console.WriteLine(); } } } }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考ListMetrics中的。
-
基本功能
以下代码示例展示了如何:
列出 CloudWatch 命名空间和指标。
开始 OpenTelemetry 充实,将传入的 OTLP 指标与生成这些指标的资源 CloudWatch 相关联。
查看 OTLP 指标如何到达 CloudWatch 指标终端节点。通过 OTLP 提取指标不是 Amazon SDK 操作。
创建评估 PromQL 查询的警报。
检查警报的贡献者,即查询匹配的各个序列。
获取指标的统计数据并在仪表板上绘制图表。
在维护时段内将警报设为静音,然后进行清理。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 在命令提示符中运行交互式场景。
public class CloudWatchScenario { /* Before running this .NET code example, set up your development environment, including your credentials. This scenario demonstrates the Amazon CloudWatch OpenTelemetry (OTel) experience. CloudWatch ingests OpenTelemetry metrics natively, and this example walks through what you do with them: turning on enrichment so CloudWatch can correlate incoming OTLP metrics with the resources that produced them, alarming on those metrics with a PromQL query, and finding out which individual series drove the alarm. A PromQL alarm works differently from a classic metric alarm. Rather than watching one metric and counting breaching periods, it evaluates a query that can match many series at once, and tracks each matching series separately as a contributor. Note that sending OTLP metrics to CloudWatch is not an AWS SDK operation. Metrics arrive over the OTLP protocol through the CloudWatch agent, an OpenTelemetry Collector, or an ADOT SDK. Everything this scenario does is configuration and querying around that ingestion path. This .NET example performs the following tasks: 1. List metrics and namespaces from CloudWatch. 2. Start OpenTelemetry enrichment for the account. 3. Explain how OTLP metrics reach CloudWatch. 4. Create an alarm that evaluates a PromQL query. 5. Inspect the contributors to the PromQL alarm. 6. Get metric statistics and chart the metric on a dashboard. 7. Mute the alarm for a maintenance window. 8. Clean up resources. */ private static ILogger logger = null!; private static CloudWatchWrapper _cloudWatchWrapper = null!; private static CloudWatchOTelWrapper _otelWrapper = null!; private static IConfiguration _configuration = null!; private const string DefaultQuery = "avg by (host) (system_cpu_utilization) > 80"; // Valid evaluation intervals are 10, 20, 30, or any multiple of 60 up to 3600 seconds. private const int EvaluationInterval = 60; private const int PendingPeriod = 300; private const int RecoveryPeriod = 120; private static string _alarmName = null!; private static string _dashboardName = null!; private static string _muteRuleName = null!; // Tracks whether this run turned enrichment on, so that cleanup only turns off // enrichment that this run started. private static bool _startedEnrichment; private static bool _dashboardCreated; private static string _region = null!; static async Task Main(string[] args) { // Set up dependency injection for the Amazon service. using var host = Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => logging.AddFilter("System", LogLevel.Debug) .AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information) .AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace)) .ConfigureServices((_, services) => services.AddAWSService<IAmazonCloudWatch>() .AddTransient<CloudWatchWrapper>() .AddTransient<CloudWatchOTelWrapper>() ) .Build(); _configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("settings.json") // Load settings from .json file. .AddJsonFile("settings.local.json", true) // Optionally, load local settings. .Build(); logger = LoggerFactory.Create(builder => { builder.AddConsole(); }) .CreateLogger<CloudWatchScenario>(); _cloudWatchWrapper = host.Services.GetRequiredService<CloudWatchWrapper>(); _otelWrapper = host.Services.GetRequiredService<CloudWatchOTelWrapper>(); // A metric widget must name its region, because a dashboard can chart // metrics from several. _region = host.Services.GetRequiredService<IAmazonCloudWatch>() .Config.RegionEndpoint.SystemName; // Suffix the resource names so repeated runs do not collide. var suffix = Random.Shared.Next(1000, 9999).ToString(); _alarmName = $"doc-example-promql-alarm-{suffix}"; _dashboardName = $"doc-example-dashboard-{suffix}"; _muteRuleName = $"doc-example-mute-rule-{suffix}"; Console.WriteLine(new string('-', 80)); Console.WriteLine("Welcome to the Amazon CloudWatch Basics scenario."); Console.WriteLine(new string('-', 80)); Console.WriteLine( "\nCloudWatch now ingests OpenTelemetry metrics natively. This scenario walks through" + "\nthat experience: it turns on OTel enrichment so CloudWatch can correlate incoming" + "\nOTLP metrics with the resources that produced them, alarms on those metrics with a" + "\nPromQL query, and shows you which individual series drove the alarm." + "\n" + "\nA PromQL alarm works differently from a classic metric alarm. Rather than watching" + "\none metric and counting breaching periods, it evaluates a query that can match many" + "\nseries at once, and tracks each one separately as a contributor.\n"); try { var namespaces = await ListMetricsAndNamespaces(); await StartOTelEnrichment(); ExplainOtlpIngestion(); await CreatePromQlAlarm(); await InspectAlarmContributors(); await GetStatisticsAndChartMetric(namespaces); await MuteAlarmForMaintenance(); await CleanUp(); Console.WriteLine(new string('-', 80)); Console.WriteLine("CloudWatch Basics scenario is complete."); Console.WriteLine(new string('-', 80)); } catch (Exception ex) { Console.WriteLine(new string('-', 80)); logger.LogError(ex, "There was a problem executing the scenario."); await CleanUp(); Console.WriteLine(new string('-', 80)); } } /// <summary> /// List the metrics and namespaces already present in the account, to orient the /// reader before any configuration happens. /// </summary> /// <returns>The distinct namespaces found.</returns> private static async Task<List<string>> ListMetricsAndNamespaces() { Console.WriteLine(new string('-', 80)); Console.WriteLine("1. List metrics and namespaces"); Console.WriteLine( "\nBefore configuring anything, let's see what CloudWatch is already collecting in" + "\nthis account by calling ListMetrics.\n"); var metrics = await _cloudWatchWrapper.ListMetrics(); // Order by metric count descending, so the most-populated namespace comes first. // Step 6 charts a metric from that namespace, and a busy namespace is the one most // likely to have datapoints worth looking at. var namespaceCounts = metrics .GroupBy(m => m.Namespace) .Select(g => new { Namespace = g.Key, Count = g.Count() }) .OrderByDescending(n => n.Count) .ToList(); var namespaces = namespaceCounts.Select(n => n.Namespace).ToList(); Console.WriteLine($"\tFound {metrics.Count} metrics across {namespaces.Count} namespaces:"); foreach (var entry in namespaceCounts.Take(10)) { Console.WriteLine($"\t {entry.Namespace} ({entry.Count} metrics)"); } if (!namespaces.Any()) { Console.WriteLine( "\tNo metrics found in this account. The statistics and dashboard steps later on" + "\n\tneed an existing metric, so they will be skipped."); } Console.WriteLine(new string('-', 80)); return namespaces; } /// <summary> /// Start OTel enrichment, but only if it is not already running. Enrichment is what /// makes CloudWatch attach AWS resource context to incoming OTLP metrics. /// </summary> private static async Task StartOTelEnrichment() { Console.WriteLine(new string('-', 80)); Console.WriteLine("2. Start OpenTelemetry enrichment"); Console.WriteLine( "\nEnrichment is what lets CloudWatch attach AWS resource context to the OTLP metrics" + "\nyou send it. Without it, your metrics arrive as opaque series with no connection to" + "\nthe resources that emitted them." + "\n" + "\nWe check the current state first, and only start enrichment if it isn't already on.\n"); var status = await _otelWrapper.GetOTelEnrichmentStatus(); Console.WriteLine($"\tEnrichment status: {status}"); if (status != OTelEnrichmentStatus.Running) { // Record the attempt before making it. We already know enrichment was not running, // so stopping it during cleanup is always safe, and a call that starts enrichment // but then fails to report back (a timeout, say) would otherwise leave it running. _startedEnrichment = true; await _otelWrapper.StartOTelEnrichment(); status = await _otelWrapper.GetOTelEnrichmentStatus(); Console.WriteLine($"\tEnrichment status: {status}"); Console.WriteLine( "\n\tNote: this run started enrichment, so the cleanup step will stop it again."); } else { Console.WriteLine( "\n\tEnrichment was already running, so we will leave it alone. The cleanup step" + "\n\twill not stop it, because other workloads in this account may depend on it."); } Console.WriteLine(new string('-', 80)); } /// <summary> /// Explain that OTLP metric ingestion is not an AWS SDK operation. This step makes no /// service call; naming the gap explicitly is the point. /// </summary> private static void ExplainOtlpIngestion() { Console.WriteLine(new string('-', 80)); Console.WriteLine("3. Send OTLP metrics to CloudWatch"); Console.WriteLine( "\nThis step is not an AWS SDK operation, and that's worth being explicit about." + "\nMetrics reach CloudWatch over the OTLP protocol, through the CloudWatch agent, an" + "\nOpenTelemetry Collector, or an ADOT SDK. There is no PutOTelMetrics API to call." + "\n" + "\nPoint your collector at the CloudWatch metrics endpoint, which follows the pattern" + "\n\thttps://monitoring.<region>.amazonaws.com/v1/metrics" + "\n" + "\nThe endpoint is HTTP/1.1 only and does not support gRPC, so use an otlphttp" + "\nexporter rather than otlp. The metrics endpoint signs as \"monitoring\".\n"); Console.WriteLine(new string('-', 80)); } /// <summary> /// Create an alarm whose evaluation is a PromQL query. /// </summary> private static async Task CreatePromQlAlarm() { Console.WriteLine(new string('-', 80)); Console.WriteLine("4. Create a PromQL alarm"); Console.WriteLine( "\nNow we alarm on those metrics. The comparison goes inside the query itself: a" + "\nPromQL alarm has no separate threshold, comparison operator, statistic, or period.\n"); Console.WriteLine($"Enter a PromQL query, or press <ENTER> for the default\n[{DefaultQuery}]:"); var input = Console.ReadLine(); var query = string.IsNullOrWhiteSpace(input) ? DefaultQuery : input.Trim(); await _otelWrapper.PutPromQLMetricAlarm(_alarmName, query, EvaluationInterval, PendingPeriod, RecoveryPeriod); Console.WriteLine($"\tCreated alarm {_alarmName}:"); Console.WriteLine($"\t query: {query}"); Console.WriteLine($"\t evaluationInterval: {EvaluationInterval} seconds"); Console.WriteLine($"\t pendingPeriod: {PendingPeriod} seconds"); Console.WriteLine($"\t recoveryPeriod: {RecoveryPeriod} seconds"); Console.WriteLine( "\n\tA PromQL alarm starts in the OK state rather than INSUFFICIENT_DATA, which is" + "\n\tanother way it differs from a classic alarm."); Console.WriteLine(new string('-', 80)); } /// <summary> /// Show which individual series the alarm's query matched. This is the step with no /// classic-alarm equivalent. /// </summary> private static async Task InspectAlarmContributors() { Console.WriteLine(new string('-', 80)); Console.WriteLine("5. Inspect the alarm's contributors"); Console.WriteLine( "\nEach contributor is one series the query matched, identified by its label set." + "\nThis is how you find out which host is unhealthy rather than only that something" + "\nis. Classic alarms have no equivalent.\n"); var contributors = await _otelWrapper.DescribeAlarmContributors(_alarmName); if (!contributors.Any()) { Console.WriteLine( "\tNo contributors yet. The query matched no series, which usually means no OTel" + "\n\tmetrics with these labels have arrived. Once your collector is sending data," + "\n\teach matching series appears here with its labels and why it breached."); } else { Console.WriteLine($"\tFound {contributors.Count} contributors:"); foreach (var contributor in contributors) { var labels = string.Join(", ", contributor.ContributorAttributes.Select(a => $"{a.Key}={a.Value}")); Console.WriteLine($"\t {contributor.ContributorId}: {labels}"); Console.WriteLine($"\t reason: {contributor.StateReason}"); } } Console.WriteLine(new string('-', 80)); } /// <summary> /// Get statistics for an existing metric and chart it on a dashboard, so the reader can /// see what the alarm is evaluating. /// </summary> /// <param name="namespaces">The namespaces discovered in step 1.</param> private static async Task GetStatisticsAndChartMetric(List<string> namespaces) { Console.WriteLine(new string('-', 80)); Console.WriteLine("6. Get statistics and chart the metric on a dashboard"); Console.WriteLine("\nStatistics and dashboards are how you see what the alarm is evaluating.\n"); if (!namespaces.Any()) { Console.WriteLine("\tSkipping statistics and dashboard because no metrics exist yet."); Console.WriteLine(new string('-', 80)); return; } var metricNamespace = namespaces.First(); var metrics = await _cloudWatchWrapper.ListMetrics(metricNamespace); var metric = metrics.FirstOrDefault(); if (metric != null) { var datapoints = await _cloudWatchWrapper.GetMetricStatistics( metricNamespace, metric.MetricName, new List<string> { "Average", "Maximum" }, metric.Dimensions, 1, 3600); Console.WriteLine( $"\tStatistics for {metricNamespace} {metric.MetricName} over the last day:"); Console.WriteLine($"\t Datapoints: {datapoints.Count}"); foreach (var datapoint in datapoints.Take(3)) { Console.WriteLine( $"\t {datapoint.Timestamp:u} average {datapoint.Average}, maximum {datapoint.Maximum}"); } var dashboardBody = BuildDashboardBody(metricNamespace, metric, _region); var validationMessages = await _cloudWatchWrapper.PutDashboard(_dashboardName, dashboardBody); _dashboardCreated = true; if (validationMessages.Any()) { foreach (var message in validationMessages) { Console.WriteLine($"\tDashboard validation message: {message.Message}"); } } Console.WriteLine($"\tCreated dashboard {_dashboardName}."); var dashboard = await _cloudWatchWrapper.GetDashboard(_dashboardName); Console.WriteLine($"\tRead the dashboard back, {dashboard.Length} characters of widget JSON."); } else { Console.WriteLine($"\tNo metrics found in namespace {metricNamespace}, skipping."); } Console.WriteLine(new string('-', 80)); } /// <summary> /// Build a single-widget dashboard body that charts the given metric. /// </summary> /// <param name="metricNamespace">The namespace of the metric to chart.</param> /// <param name="metric">The metric to chart.</param> /// <param name="region">The region the metric is in. A metric widget must name its /// region, because a dashboard can chart metrics from several.</param> internal static string BuildDashboardBody(string metricNamespace, Metric metric, string region) { var dimensionParts = string.Concat( metric.Dimensions.Select(d => $", \"{d.Name}\", \"{d.Value}\"")); return $@"{{ ""widgets"": [ {{ ""type"": ""text"", ""x"": 0, ""y"": 0, ""width"": 24, ""height"": 2, ""properties"": {{ ""markdown"": ""This dashboard was created programmatically by an AWS SDK code example."" }} }}, {{ ""type"": ""metric"", ""x"": 0, ""y"": 2, ""width"": 12, ""height"": 6, ""properties"": {{ ""metrics"": [[ ""{metricNamespace}"", ""{metric.MetricName}""{dimensionParts} ]], ""view"": ""timeSeries"", ""stat"": ""Average"", ""period"": 300, ""region"": ""{region}"", ""title"": ""{metric.MetricName}"" }} }} ] }}"; } /// <summary> /// Create a mute rule so the alarm's actions are suppressed during a maintenance /// window, then read it back and find it in the account's rules. /// </summary> private static async Task MuteAlarmForMaintenance() { Console.WriteLine(new string('-', 80)); Console.WriteLine("7. Mute the alarm for a maintenance window"); Console.WriteLine( "\nWhile a mute rule is active the targeted alarms keep evaluating and keep changing" + "\nstate, but their actions do not fire. This is the supported way to suppress" + "\nnotifications during planned maintenance, instead of disabling alarm actions and" + "\nhoping someone remembers to turn them back on.\n"); // The expression is a five-field cron expression, // cron(Minutes Hours Day-of-month Month Day-of-week). Note that this is five fields, // not the six that Amazon EventBridge uses. For a one-time window, use // at(yyyy-MM-ddThh:mm), with no seconds. The duration is an ISO 8601 duration from // PT1M to P15D, so PT2H rather than 2h. const string expression = "cron(0 2 * * SUN)"; const string duration = "PT2H"; const string timezone = "America/Los_Angeles"; await _otelWrapper.PutAlarmMuteRule(_muteRuleName, expression, duration, timezone, new List<string> { _alarmName }); Console.WriteLine($"\tCreated mute rule {_muteRuleName}:"); Console.WriteLine($"\t schedule: {expression} for {duration}"); Console.WriteLine($"\t timezone: {timezone}"); Console.WriteLine($"\t targets: {_alarmName}"); Console.WriteLine( "\n\tNote the two formats here. The expression is a five-field cron expression, five" + "\n\trather than the six Amazon EventBridge uses. The duration is an ISO 8601" + "\n\tduration, so 'PT2H' and not '2h'." + "\n" + "\n\tAlso note that MuteTargets is set explicitly. If you leave it out, the rule" + "\n\tapplies to every alarm in the account."); var muteRule = await _otelWrapper.GetAlarmMuteRule(_muteRuleName); Console.WriteLine( $"\tRead the rule back: status {muteRule.Status}, mute type {muteRule.MuteType}."); var summaries = await _otelWrapper.ListAlarmMuteRules(_alarmName); Console.WriteLine($"\tFound {summaries.Count} mute rules targeting this alarm."); // Mute rule summaries carry no name field, only an ARN, so match on the ARN suffix. var match = summaries.FirstOrDefault(s => s.AlarmMuteRuleArn.EndsWith($"/{_muteRuleName}") || s.AlarmMuteRuleArn.EndsWith($":{_muteRuleName}")); if (match != null) { Console.WriteLine($"\t matched by ARN: {match.AlarmMuteRuleArn} ({match.Status})"); } Console.WriteLine(new string('-', 80)); } /// <summary> /// Delete the resources the scenario created. Each deletion is attempted independently /// so that one failure does not leave the remaining resources behind. /// </summary> private static async Task CleanUp() { Console.WriteLine(new string('-', 80)); Console.WriteLine("8. Clean up"); Console.WriteLine("\nDelete the resources this scenario created? (y/n)"); var response = Console.ReadLine(); if (!string.Equals(response?.Trim(), "y", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine( "\tSkipping cleanup. Note that the alarm, dashboard, and mute rule are still in" + "\n\tyour account, and enrichment may still be running."); Console.WriteLine(new string('-', 80)); return; } try { await _otelWrapper.DeleteAlarmMuteRule(_muteRuleName); Console.WriteLine($"\tDeleted mute rule {_muteRuleName}."); } catch (Exception ex) { Console.WriteLine($"\tCould not delete the mute rule: {ex.Message}"); } try { await _cloudWatchWrapper.DeleteAlarms(new List<string> { _alarmName }); Console.WriteLine($"\tDeleted alarm {_alarmName}."); } catch (Exception ex) { Console.WriteLine($"\tCould not delete the alarm: {ex.Message}"); } if (_dashboardCreated) { try { await _cloudWatchWrapper.DeleteDashboards(new List<string> { _dashboardName }); Console.WriteLine($"\tDeleted dashboard {_dashboardName}."); } catch (Exception ex) { Console.WriteLine($"\tCould not delete the dashboard: {ex.Message}"); } } if (_startedEnrichment) { try { await _otelWrapper.StopOTelEnrichment(); Console.WriteLine("\tStopped OTel enrichment, because this run started it."); } catch (Exception ex) { Console.WriteLine($"\tCould not stop OTel enrichment: {ex.Message}"); } } else { Console.WriteLine( "\tLeft OTel enrichment running, because it was already on before this run."); } Console.WriteLine(new string('-', 80)); } }场景在 CloudWatch OpenTelemetry 操作中使用的包装器方法。
/// <summary> /// Wrapper class for the OpenTelemetry features of Amazon CloudWatch: turning on OTel /// enrichment so that CloudWatch vended metrics are queryable with PromQL, alarming on a /// PromQL query, inspecting the individual series (contributors) that put a PromQL alarm /// into ALARM, and muting alarm actions on a schedule. /// /// Note that OTLP metric ingestion is not an AWS SDK operation. To send OpenTelemetry /// metrics to CloudWatch, point an OpenTelemetry collector or the AWS Distro for /// OpenTelemetry (ADOT) SDK at the CloudWatch OTLP metrics endpoint, /// https://monitoring.{region}.amazonaws.com/v1/metrics. The operations here cover /// everything you do after those metrics land in CloudWatch. /// </summary> public class CloudWatchOTelWrapper { private readonly IAmazonCloudWatch _amazonCloudWatch; private readonly ILogger<CloudWatchOTelWrapper> _logger; /// <summary> /// Constructor for the CloudWatch OpenTelemetry wrapper. /// </summary> /// <param name="amazonCloudWatch">The injected CloudWatch client.</param> /// <param name="logger">The injected logger for the wrapper.</param> public CloudWatchOTelWrapper(IAmazonCloudWatch amazonCloudWatch, ILogger<CloudWatchOTelWrapper> logger) { _logger = logger; _amazonCloudWatch = amazonCloudWatch; }场景用于指标、统计数据和仪表板操作的包装器方法。
/// <summary> /// Wrapper class for Amazon CloudWatch methods. /// </summary> public class CloudWatchWrapper { private readonly IAmazonCloudWatch _amazonCloudWatch; private readonly ILogger<CloudWatchWrapper> _logger; /// <summary> /// Constructor for the CloudWatch wrapper. /// </summary> /// <param name="amazonCloudWatch">The injected CloudWatch client.</param> /// <param name="logger">The injected logger for the wrapper.</param> public CloudWatchWrapper(IAmazonCloudWatch amazonCloudWatch, ILogger<CloudWatchWrapper> logger) { _logger = logger; _amazonCloudWatch = amazonCloudWatch; } /// <summary> /// List metrics available, optionally within a namespace. /// </summary> /// <param name="metricNamespace">Optional CloudWatch namespace to use when listing metrics.</param> /// <param name="filter">Optional dimension filter.</param> /// <param name="metricName">Optional metric name filter.</param> /// <returns>The list of metrics.</returns> public async Task<List<Metric>> ListMetrics(string? metricNamespace = null, DimensionFilter? filter = null, string? metricName = null) { var results = new List<Metric>(); var paginateMetrics = _amazonCloudWatch.Paginators.ListMetrics( new ListMetricsRequest { Namespace = metricNamespace, Dimensions = filter != null ? new List<DimensionFilter> { filter } : null, MetricName = metricName }); // Get the entire list using the paginator. await foreach (var metric in paginateMetrics.Metrics) { results.Add(metric); } return results; } /// <summary> /// Wrapper to get statistics for a specific CloudWatch metric. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metricName">The name of the metric.</param> /// <param name="statistics">The list of statistics to include.</param> /// <param name="dimensions">The list of dimensions to include.</param> /// <param name="days">The number of days in the past to include.</param> /// <param name="period">The period for the data.</param> /// <returns>A list of DataPoint objects for the statistics.</returns> public async Task<List<Datapoint>> GetMetricStatistics(string metricNamespace, string metricName, List<string> statistics, List<Dimension> dimensions, int days, int period) { var metricStatistics = await _amazonCloudWatch.GetMetricStatisticsAsync( new GetMetricStatisticsRequest() { Namespace = metricNamespace, MetricName = metricName, Dimensions = dimensions, Statistics = statistics, StartTime = DateTime.UtcNow.AddDays(-days), EndTime = DateTime.UtcNow, Period = period }); return metricStatistics.Datapoints ?? new List<Datapoint>(); } /// <summary> /// Wrapper to create or add to a dashboard with metrics. /// </summary> /// <param name="dashboardName">The name for the dashboard.</param> /// <param name="dashboardBody">The metric data in JSON for the dashboard.</param> /// <returns>A list of validation messages for the dashboard.</returns> public async Task<List<DashboardValidationMessage>> PutDashboard(string dashboardName, string dashboardBody) { // Updating a dashboard replaces all contents. // Best practice is to include a text widget indicating this dashboard was created programmatically. var dashboardResponse = await _amazonCloudWatch.PutDashboardAsync( new PutDashboardRequest() { DashboardName = dashboardName, DashboardBody = dashboardBody }); return dashboardResponse.DashboardValidationMessages ?? new List<DashboardValidationMessage>(); } /// <summary> /// Get information on a dashboard. /// </summary> /// <param name="dashboardName">The name of the dashboard.</param> /// <returns>A JSON object with dashboard information.</returns> public async Task<string> GetDashboard(string dashboardName) { var dashboardResponse = await _amazonCloudWatch.GetDashboardAsync( new GetDashboardRequest() { DashboardName = dashboardName }); return dashboardResponse.DashboardBody; } /// <summary> /// Get a list of dashboards. /// </summary> /// <returns>A list of DashboardEntry objects.</returns> public async Task<List<DashboardEntry>> ListDashboards() { var results = new List<DashboardEntry>(); var paginateDashboards = _amazonCloudWatch.Paginators.ListDashboards( new ListDashboardsRequest()); // Get the entire list using the paginator. await foreach (var data in paginateDashboards.DashboardEntries) { results.Add(data); } return results; } /// <summary> /// Wrapper to add metric data to a CloudWatch metric. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metricData">A data object for the metric data.</param> /// <returns>True if successful.</returns> public async Task<bool> PutMetricData(string metricNamespace, List<MetricDatum> metricData) { var putDataResponse = await _amazonCloudWatch.PutMetricDataAsync( new PutMetricDataRequest() { MetricData = metricData, Namespace = metricNamespace, }); return putDataResponse.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Get an image for a metric graphed over time. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metric">The name of the metric.</param> /// <param name="stat">The name of the stat to chart.</param> /// <param name="period">The period to use for the chart.</param> /// <returns>A memory stream for the chart image.</returns> public async Task<MemoryStream> GetTimeSeriesMetricImage(string metricNamespace, string metric, string stat, int period) { var metricImageWidget = new { title = "Example Metric Graph", view = "timeSeries", stacked = false, period = period, width = 1400, height = 600, metrics = new List<List<object>> { new() { metricNamespace, metric, new { stat } } } }; var metricImageWidgetString = JsonSerializer.Serialize(metricImageWidget); var imageResponse = await _amazonCloudWatch.GetMetricWidgetImageAsync( new GetMetricWidgetImageRequest() { MetricWidget = metricImageWidgetString }); return imageResponse.MetricWidgetImage; } /// <summary> /// Save a metric image to a file. /// </summary> /// <param name="memoryStream">The MemoryStream for the metric image.</param> /// <param name="metricName">The name of the metric.</param> /// <returns>The path to the file.</returns> public string SaveMetricImage(MemoryStream memoryStream, string metricName) { var metricFileName = $"{metricName}_{DateTime.Now.Ticks}.png"; using var sr = new StreamReader(memoryStream); // Writes the memory stream to a file. File.WriteAllBytes(metricFileName, memoryStream.ToArray()); var filePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, metricFileName); return filePath; } /// <summary> /// Get data for CloudWatch metrics. /// </summary> /// <param name="minutesOfData">The number of minutes of data to include.</param> /// <param name="useDescendingTime">True to return the data descending by time.</param> /// <param name="endDateUtc">The end date for the data, in UTC.</param> /// <param name="maxDataPoints">The maximum data points to include.</param> /// <param name="dataQueries">Optional data queries to include.</param> /// <returns>A list of the requested metric data.</returns> public async Task<List<MetricDataResult>> GetMetricData(int minutesOfData, bool useDescendingTime, DateTime? endDateUtc = null, int maxDataPoints = 0, List<MetricDataQuery>? dataQueries = null) { var metricData = new List<MetricDataResult>(); // If no end time is provided, use the current time for the end time. endDateUtc ??= DateTime.UtcNow; var timeZoneOffset = TimeZoneInfo.Local.GetUtcOffset(endDateUtc.Value.ToLocalTime()); var startTimeUtc = endDateUtc.Value.AddMinutes(-minutesOfData); // The timezone string should be in the format +0000, so use the timezone offset to format it correctly. var timeZoneString = $"{timeZoneOffset.Hours:D2}{timeZoneOffset.Minutes:D2}"; // Add the plus sign for positive offsets. timeZoneString = timeZoneString.StartsWith('-') ? timeZoneString : "+" + timeZoneString; var paginatedMetricData = _amazonCloudWatch.Paginators.GetMetricData( new GetMetricDataRequest() { StartTime = startTimeUtc, EndTime = endDateUtc.Value, LabelOptions = new LabelOptions { Timezone = timeZoneString }, ScanBy = useDescendingTime ? ScanBy.TimestampDescending : ScanBy.TimestampAscending, MaxDatapoints = maxDataPoints, MetricDataQueries = dataQueries, }); if (paginatedMetricData.MetricDataResults != null) { await foreach (var data in paginatedMetricData.MetricDataResults) { metricData.Add(data); } } return metricData; } /// <summary> /// Add a metric alarm to send an email when the metric passes a threshold. /// </summary> /// <param name="alarmDescription">A description of the alarm.</param> /// <param name="alarmName">The name for the alarm.</param> /// <param name="comparison">The type of comparison to use.</param> /// <param name="metricName">The name of the metric for the alarm.</param> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="threshold">The threshold value for the alarm.</param> /// <param name="alarmActions">Optional actions to execute when in an alarm state.</param> /// <returns>True if successful.</returns> public async Task<bool> PutMetricEmailAlarm(string alarmDescription, string alarmName, ComparisonOperator comparison, string metricName, string metricNamespace, double threshold, List<string> alarmActions = null!) { try { var putEmailAlarmResponse = await _amazonCloudWatch.PutMetricAlarmAsync( new PutMetricAlarmRequest() { AlarmActions = alarmActions, AlarmDescription = alarmDescription, AlarmName = alarmName, ComparisonOperator = comparison, Threshold = threshold, Namespace = metricNamespace, MetricName = metricName, EvaluationPeriods = 1, Period = 10, Statistic = new Statistic("Maximum"), DatapointsToAlarm = 1, TreatMissingData = "ignore" }); return putEmailAlarmResponse.HttpStatusCode == HttpStatusCode.OK; } catch (LimitExceededException lex) { _logger.LogError(lex, $"Unable to add alarm {alarmName}. Alarm quota has already been reached."); } return false; } /// <summary> /// Add specific email actions to a list of action strings for a CloudWatch alarm. /// </summary> /// <param name="accountId">The AccountId for the alarm.</param> /// <param name="region">The region for the alarm.</param> /// <param name="emailTopicName">An Amazon Simple Notification Service (SNS) topic for the alarm email.</param> /// <param name="alarmActions">Optional list of existing alarm actions to append to.</param> /// <returns>A list of string actions for an alarm.</returns> public List<string> AddEmailAlarmAction(string accountId, string region, string emailTopicName, List<string>? alarmActions = null) { alarmActions ??= new List<string>(); var snsAlarmAction = $"arn:aws:sns:{region}:{accountId}:{emailTopicName}"; alarmActions.Add(snsAlarmAction); return alarmActions; } /// <summary> /// Describe the current alarms, optionally filtered by state. /// </summary> /// <param name="stateValue">Optional filter for alarm state.</param> /// <returns>The list of alarm data.</returns> public async Task<List<MetricAlarm>> DescribeAlarms(StateValue? stateValue = null) { List<MetricAlarm> alarms = new List<MetricAlarm>(); var paginatedDescribeAlarms = _amazonCloudWatch.Paginators.DescribeAlarms( new DescribeAlarmsRequest() { StateValue = stateValue }); await foreach (var data in paginatedDescribeAlarms.MetricAlarms) { alarms.Add(data); } return alarms; } /// <summary> /// Describe the current alarms for a specific metric. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metricName">The name of the metric.</param> /// <returns>The list of alarm data.</returns> public async Task<List<MetricAlarm>> DescribeAlarmsForMetric(string metricNamespace, string metricName) { var alarmsResult = await _amazonCloudWatch.DescribeAlarmsForMetricAsync( new DescribeAlarmsForMetricRequest() { Namespace = metricNamespace, MetricName = metricName }); return alarmsResult.MetricAlarms ?? new List<MetricAlarm>(); } /// <summary> /// Describe the history of an alarm for a number of days in the past. /// </summary> /// <param name="alarmName">The name of the alarm.</param> /// <param name="historyDays">The number of days in the past.</param> /// <returns>The list of alarm history data.</returns> public async Task<List<AlarmHistoryItem>> DescribeAlarmHistory(string alarmName, int historyDays) { List<AlarmHistoryItem> alarmHistory = new List<AlarmHistoryItem>(); var paginatedAlarmHistory = _amazonCloudWatch.Paginators.DescribeAlarmHistory( new DescribeAlarmHistoryRequest() { AlarmName = alarmName, EndDate = DateTime.UtcNow, HistoryItemType = HistoryItemType.StateUpdate, StartDate = DateTime.UtcNow.AddDays(-historyDays) }); await foreach (var data in paginatedAlarmHistory.AlarmHistoryItems) { alarmHistory.Add(data); } return alarmHistory; } /// <summary> /// Delete a list of alarms from CloudWatch. /// </summary> /// <param name="alarmNames">A list of names of alarms to delete.</param> /// <returns>True if successful.</returns> public async Task<bool> DeleteAlarms(List<string> alarmNames) { var deleteAlarmsResult = await _amazonCloudWatch.DeleteAlarmsAsync( new DeleteAlarmsRequest() { AlarmNames = alarmNames }); return deleteAlarmsResult.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Disable the actions for a list of alarms from CloudWatch. /// </summary> /// <param name="alarmNames">A list of names of alarms.</param> /// <returns>True if successful.</returns> public async Task<bool> DisableAlarmActions(List<string> alarmNames) { var disableAlarmActionsResult = await _amazonCloudWatch.DisableAlarmActionsAsync( new DisableAlarmActionsRequest() { AlarmNames = alarmNames }); return disableAlarmActionsResult.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Enable the actions for a list of alarms from CloudWatch. /// </summary> /// <param name="alarmNames">A list of names of alarms.</param> /// <returns>True if successful.</returns> public async Task<bool> EnableAlarmActions(List<string> alarmNames) { var enableAlarmActionsResult = await _amazonCloudWatch.EnableAlarmActionsAsync( new EnableAlarmActionsRequest() { AlarmNames = alarmNames }); return enableAlarmActionsResult.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Add an anomaly detector for a single metric. /// </summary> /// <param name="anomalyDetector">A single metric anomaly detector.</param> /// <returns>True if successful.</returns> public async Task<bool> PutAnomalyDetector(SingleMetricAnomalyDetector anomalyDetector) { var putAlarmDetectorResult = await _amazonCloudWatch.PutAnomalyDetectorAsync( new PutAnomalyDetectorRequest() { SingleMetricAnomalyDetector = anomalyDetector }); return putAlarmDetectorResult.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Describe anomaly detectors for a metric and namespace. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metricName">The metric of the anomaly detectors.</param> /// <returns>The list of detectors.</returns> public async Task<List<AnomalyDetector>> DescribeAnomalyDetectors(string metricNamespace, string metricName) { List<AnomalyDetector> detectors = new List<AnomalyDetector>(); var paginatedDescribeAnomalyDetectors = _amazonCloudWatch.Paginators.DescribeAnomalyDetectors( new DescribeAnomalyDetectorsRequest() { MetricName = metricName, Namespace = metricNamespace }); await foreach (var data in paginatedDescribeAnomalyDetectors.AnomalyDetectors) { detectors.Add(data); } return detectors; } /// <summary> /// Delete a single metric anomaly detector. /// </summary> /// <param name="anomalyDetector">The anomaly detector to delete.</param> /// <returns>True if successful.</returns> public async Task<bool> DeleteAnomalyDetector(SingleMetricAnomalyDetector anomalyDetector) { var deleteAnomalyDetectorResponse = await _amazonCloudWatch.DeleteAnomalyDetectorAsync( new DeleteAnomalyDetectorRequest() { SingleMetricAnomalyDetector = anomalyDetector }); return deleteAnomalyDetectorResponse.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Delete a list of CloudWatch dashboards. /// </summary> /// <param name="dashboardNames">List of dashboard names to delete.</param> /// <returns>True if successful.</returns> public async Task<bool> DeleteDashboards(List<string> dashboardNames) { var deleteDashboardsResponse = await _amazonCloudWatch.DeleteDashboardsAsync( new DeleteDashboardsRequest() { DashboardNames = dashboardNames }); return deleteDashboardsResponse.HttpStatusCode == HttpStatusCode.OK; } }场景的 settings.json 值示例。
{ "dashboardName": "example-new-dashboard", "exampleAlarmName": "example-metric-alarm", "accountId": "1234567890", "region": "us-east-1", "emailTopic": "Default_CloudWatch_Alarms_Topic", "customMetricNamespace": "example-namespace", "customMetricName": "example-custom-metric", "dashboardExampleBody": { "widgets": [ { "height": 6, "width": 6, "y": 0, "x": 0, "type": "text", "properties": { "markdown": "# Code Example Dashboard \nThis dashboard was created by example code.\n" } }, { "height": 8, "width": 8, "y": 0, "x": 6, "type": "metric", "properties": { "metrics": [ [ "AWS/Billing", "EstimatedCharges", "Currency", "USD", { "region": "us-east-1" } ] ], "view": "timeSeries", "region": "us-east-1", "stat": "Maximum", "period": 86400, "yAxis": { "left": { "min": 0, "max": 100 } }, "stacked": false, "title": "Estimated Billing", "setPeriodToTimeRange": false, "liveData": true, "sparkline": true, "trend": true } }, { "height": 8, "width": 8, "y": 0, "x": 14, "type": "metric", "properties": { "metrics": [ [ "AWS/Usage", "CallCount", "Type", "API", "Resource", "ListMetrics", "Service", "CloudWatch", "Class", "None" ], [ "...", "GetMetricStatistics", ".", ".", ".", "." ], [ "...", "GetMetricData", ".", ".", ".", "." ], [ "...", "PutDashboard", ".", ".", ".", "." ], [ "...", "PutMetricData", ".", ".", ".", "." ] ], "view": "timeSeries", "yAxis": { "left": { "min": 0, "max": 200 } }, "stacked": false, "region": "us-east-1", "stat": "Sum", "period": 300, "title": "CloudWatch Usage", "setPeriodToTimeRange": false, "liveData": true, "sparkline": true, "trend": true } } ] } }-
有关 API 详细信息,请参阅《适用于 .NET 的 Amazon SDK API Reference》中的以下主题。
-
操作
以下代码示例演示了如何使用 DeleteAlarmMuteRule。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Delete an alarm mute rule. The alarms it targeted resume firing their actions. /// </summary> /// <param name="name">The name of the mute rule.</param> /// <returns>True if successful.</returns> public async Task<bool> DeleteAlarmMuteRule(string name) { var response = await _amazonCloudWatch.DeleteAlarmMuteRuleAsync( new DeleteAlarmMuteRuleRequest { AlarmMuteRuleName = name }); _logger.LogInformation($"Deleted alarm mute rule {name}."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DeleteAlarmMuteRule中的。
-
以下代码示例演示了如何使用 DeleteAlarms。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Delete a list of alarms from CloudWatch. /// </summary> /// <param name="alarmNames">A list of names of alarms to delete.</param> /// <returns>True if successful.</returns> public async Task<bool> DeleteAlarms(List<string> alarmNames) { var deleteAlarmsResult = await _amazonCloudWatch.DeleteAlarmsAsync( new DeleteAlarmsRequest() { AlarmNames = alarmNames }); return deleteAlarmsResult.HttpStatusCode == HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DeleteAlarms中的。
-
以下代码示例演示了如何使用 DeleteAnomalyDetector。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Delete a single metric anomaly detector. /// </summary> /// <param name="anomalyDetector">The anomaly detector to delete.</param> /// <returns>True if successful.</returns> public async Task<bool> DeleteAnomalyDetector(SingleMetricAnomalyDetector anomalyDetector) { var deleteAnomalyDetectorResponse = await _amazonCloudWatch.DeleteAnomalyDetectorAsync( new DeleteAnomalyDetectorRequest() { SingleMetricAnomalyDetector = anomalyDetector }); return deleteAnomalyDetectorResponse.HttpStatusCode == HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DeleteAnomalyDetector中的。
-
以下代码示例演示了如何使用 DeleteDashboards。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Delete a list of CloudWatch dashboards. /// </summary> /// <param name="dashboardNames">List of dashboard names to delete.</param> /// <returns>True if successful.</returns> public async Task<bool> DeleteDashboards(List<string> dashboardNames) { var deleteDashboardsResponse = await _amazonCloudWatch.DeleteDashboardsAsync( new DeleteDashboardsRequest() { DashboardNames = dashboardNames }); return deleteDashboardsResponse.HttpStatusCode == HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DeleteDashboards中的。
-
以下代码示例演示了如何使用 DescribeAlarmContributors。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Get the contributors for a PromQL alarm. Each contributor is one series that the /// alarm's query matched, identified by its label set. This is how you find out which /// hosts, services, or pods are breaching, rather than only that something is. /// </summary> /// <param name="alarmName">The name of the PromQL alarm.</param> /// <returns>The list of contributors.</returns> public async Task<List<AlarmContributor>> DescribeAlarmContributors(string alarmName) { var results = new List<AlarmContributor>(); string? nextToken = null; do { var response = await _amazonCloudWatch.DescribeAlarmContributorsAsync( new DescribeAlarmContributorsRequest { AlarmName = alarmName, NextToken = nextToken }); if (response.AlarmContributors != null) { results.AddRange(response.AlarmContributors); } nextToken = response.NextToken; } while (!string.IsNullOrEmpty(nextToken)); _logger.LogInformation($"Got {results.Count} contributors for alarm {alarmName}."); return results; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DescribeAlarmContributors中的。
-
以下代码示例演示了如何使用 DescribeAlarmHistory。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Describe the history of an alarm for a number of days in the past. /// </summary> /// <param name="alarmName">The name of the alarm.</param> /// <param name="historyDays">The number of days in the past.</param> /// <returns>The list of alarm history data.</returns> public async Task<List<AlarmHistoryItem>> DescribeAlarmHistory(string alarmName, int historyDays) { List<AlarmHistoryItem> alarmHistory = new List<AlarmHistoryItem>(); var paginatedAlarmHistory = _amazonCloudWatch.Paginators.DescribeAlarmHistory( new DescribeAlarmHistoryRequest() { AlarmName = alarmName, EndDate = DateTime.UtcNow, HistoryItemType = HistoryItemType.StateUpdate, StartDate = DateTime.UtcNow.AddDays(-historyDays) }); await foreach (var data in paginatedAlarmHistory.AlarmHistoryItems) { alarmHistory.Add(data); } return alarmHistory; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DescribeAlarmHistory中的。
-
以下代码示例演示了如何使用 DescribeAlarms。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Describe the current alarms, optionally filtered by state. /// </summary> /// <param name="stateValue">Optional filter for alarm state.</param> /// <returns>The list of alarm data.</returns> public async Task<List<MetricAlarm>> DescribeAlarms(StateValue? stateValue = null) { List<MetricAlarm> alarms = new List<MetricAlarm>(); var paginatedDescribeAlarms = _amazonCloudWatch.Paginators.DescribeAlarms( new DescribeAlarmsRequest() { StateValue = stateValue }); await foreach (var data in paginatedDescribeAlarms.MetricAlarms) { alarms.Add(data); } return alarms; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DescribeAlarms中的。
-
以下代码示例演示了如何使用 DescribeAlarmsForMetric。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Describe the current alarms for a specific metric. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metricName">The name of the metric.</param> /// <returns>The list of alarm data.</returns> public async Task<List<MetricAlarm>> DescribeAlarmsForMetric(string metricNamespace, string metricName) { var alarmsResult = await _amazonCloudWatch.DescribeAlarmsForMetricAsync( new DescribeAlarmsForMetricRequest() { Namespace = metricNamespace, MetricName = metricName }); return alarmsResult.MetricAlarms ?? new List<MetricAlarm>(); }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DescribeAlarmsForMetric中的。
-
以下代码示例演示了如何使用 DescribeAnomalyDetectors。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Describe anomaly detectors for a metric and namespace. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metricName">The metric of the anomaly detectors.</param> /// <returns>The list of detectors.</returns> public async Task<List<AnomalyDetector>> DescribeAnomalyDetectors(string metricNamespace, string metricName) { List<AnomalyDetector> detectors = new List<AnomalyDetector>(); var paginatedDescribeAnomalyDetectors = _amazonCloudWatch.Paginators.DescribeAnomalyDetectors( new DescribeAnomalyDetectorsRequest() { MetricName = metricName, Namespace = metricNamespace }); await foreach (var data in paginatedDescribeAnomalyDetectors.AnomalyDetectors) { detectors.Add(data); } return detectors; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DescribeAnomalyDetectors中的。
-
以下代码示例演示了如何使用 DisableAlarmActions。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Disable the actions for a list of alarms from CloudWatch. /// </summary> /// <param name="alarmNames">A list of names of alarms.</param> /// <returns>True if successful.</returns> public async Task<bool> DisableAlarmActions(List<string> alarmNames) { var disableAlarmActionsResult = await _amazonCloudWatch.DisableAlarmActionsAsync( new DisableAlarmActionsRequest() { AlarmNames = alarmNames }); return disableAlarmActionsResult.HttpStatusCode == HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考DisableAlarmActions中的。
-
以下代码示例演示了如何使用 EnableAlarmActions。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Enable the actions for a list of alarms from CloudWatch. /// </summary> /// <param name="alarmNames">A list of names of alarms.</param> /// <returns>True if successful.</returns> public async Task<bool> EnableAlarmActions(List<string> alarmNames) { var enableAlarmActionsResult = await _amazonCloudWatch.EnableAlarmActionsAsync( new EnableAlarmActionsRequest() { AlarmNames = alarmNames }); return enableAlarmActionsResult.HttpStatusCode == HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考EnableAlarmActions中的。
-
以下代码示例演示了如何使用 GetAlarmMuteRule。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Get the full configuration of an alarm mute rule, including its schedule, the /// alarms it targets, and whether it is currently SCHEDULED, ACTIVE, or EXPIRED. /// </summary> /// <param name="name">The name of the mute rule.</param> /// <returns>The mute rule.</returns> public async Task<GetAlarmMuteRuleResponse> GetAlarmMuteRule(string name) { var response = await _amazonCloudWatch.GetAlarmMuteRuleAsync( new GetAlarmMuteRuleRequest { AlarmMuteRuleName = name }); _logger.LogInformation($"Mute rule {response.Name} is {response.Status}."); return response; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考GetAlarmMuteRule中的。
-
以下代码示例演示了如何使用 GetDashboard。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Get information on a dashboard. /// </summary> /// <param name="dashboardName">The name of the dashboard.</param> /// <returns>A JSON object with dashboard information.</returns> public async Task<string> GetDashboard(string dashboardName) { var dashboardResponse = await _amazonCloudWatch.GetDashboardAsync( new GetDashboardRequest() { DashboardName = dashboardName }); return dashboardResponse.DashboardBody; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考GetDashboard中的。
-
以下代码示例演示了如何使用 GetMetricData。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Get data for CloudWatch metrics. /// </summary> /// <param name="minutesOfData">The number of minutes of data to include.</param> /// <param name="useDescendingTime">True to return the data descending by time.</param> /// <param name="endDateUtc">The end date for the data, in UTC.</param> /// <param name="maxDataPoints">The maximum data points to include.</param> /// <param name="dataQueries">Optional data queries to include.</param> /// <returns>A list of the requested metric data.</returns> public async Task<List<MetricDataResult>> GetMetricData(int minutesOfData, bool useDescendingTime, DateTime? endDateUtc = null, int maxDataPoints = 0, List<MetricDataQuery>? dataQueries = null) { var metricData = new List<MetricDataResult>(); // If no end time is provided, use the current time for the end time. endDateUtc ??= DateTime.UtcNow; var timeZoneOffset = TimeZoneInfo.Local.GetUtcOffset(endDateUtc.Value.ToLocalTime()); var startTimeUtc = endDateUtc.Value.AddMinutes(-minutesOfData); // The timezone string should be in the format +0000, so use the timezone offset to format it correctly. var timeZoneString = $"{timeZoneOffset.Hours:D2}{timeZoneOffset.Minutes:D2}"; // Add the plus sign for positive offsets. timeZoneString = timeZoneString.StartsWith('-') ? timeZoneString : "+" + timeZoneString; var paginatedMetricData = _amazonCloudWatch.Paginators.GetMetricData( new GetMetricDataRequest() { StartTime = startTimeUtc, EndTime = endDateUtc.Value, LabelOptions = new LabelOptions { Timezone = timeZoneString }, ScanBy = useDescendingTime ? ScanBy.TimestampDescending : ScanBy.TimestampAscending, MaxDatapoints = maxDataPoints, MetricDataQueries = dataQueries, }); if (paginatedMetricData.MetricDataResults != null) { await foreach (var data in paginatedMetricData.MetricDataResults) { metricData.Add(data); } } return metricData; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考GetMetricData中的。
-
以下代码示例演示了如何使用 GetMetricStatistics。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Wrapper to get statistics for a specific CloudWatch metric. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metricName">The name of the metric.</param> /// <param name="statistics">The list of statistics to include.</param> /// <param name="dimensions">The list of dimensions to include.</param> /// <param name="days">The number of days in the past to include.</param> /// <param name="period">The period for the data.</param> /// <returns>A list of DataPoint objects for the statistics.</returns> public async Task<List<Datapoint>> GetMetricStatistics(string metricNamespace, string metricName, List<string> statistics, List<Dimension> dimensions, int days, int period) { var metricStatistics = await _amazonCloudWatch.GetMetricStatisticsAsync( new GetMetricStatisticsRequest() { Namespace = metricNamespace, MetricName = metricName, Dimensions = dimensions, Statistics = statistics, StartTime = DateTime.UtcNow.AddDays(-days), EndTime = DateTime.UtcNow, Period = period }); return metricStatistics.Datapoints ?? new List<Datapoint>(); }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考GetMetricStatistics中的。
-
以下代码示例演示了如何使用 GetMetricWidgetImage。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Get an image for a metric graphed over time. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metric">The name of the metric.</param> /// <param name="stat">The name of the stat to chart.</param> /// <param name="period">The period to use for the chart.</param> /// <returns>A memory stream for the chart image.</returns> public async Task<MemoryStream> GetTimeSeriesMetricImage(string metricNamespace, string metric, string stat, int period) { var metricImageWidget = new { title = "Example Metric Graph", view = "timeSeries", stacked = false, period = period, width = 1400, height = 600, metrics = new List<List<object>> { new() { metricNamespace, metric, new { stat } } } }; var metricImageWidgetString = JsonSerializer.Serialize(metricImageWidget); var imageResponse = await _amazonCloudWatch.GetMetricWidgetImageAsync( new GetMetricWidgetImageRequest() { MetricWidget = metricImageWidgetString }); return imageResponse.MetricWidgetImage; } /// <summary> /// Save a metric image to a file. /// </summary> /// <param name="memoryStream">The MemoryStream for the metric image.</param> /// <param name="metricName">The name of the metric.</param> /// <returns>The path to the file.</returns> public string SaveMetricImage(MemoryStream memoryStream, string metricName) { var metricFileName = $"{metricName}_{DateTime.Now.Ticks}.png"; using var sr = new StreamReader(memoryStream); // Writes the memory stream to a file. File.WriteAllBytes(metricFileName, memoryStream.ToArray()); var filePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, metricFileName); return filePath; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考GetMetricWidgetImage中的。
-
以下代码示例演示了如何使用 GetOTelEnrichment。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Get the current OTel enrichment status for the account. /// </summary> /// <returns>The status, either Running or Stopped.</returns> public async Task<OTelEnrichmentStatus> GetOTelEnrichmentStatus() { var response = await _amazonCloudWatch.GetOTelEnrichmentAsync( new GetOTelEnrichmentRequest()); _logger.LogInformation($"OTel enrichment status is {response.Status}."); return response.Status; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考GetOTelEnrichment中的。
-
以下代码示例演示了如何使用 ListAlarmMuteRules。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// List the alarm mute rules in the account, optionally filtered to the rules that /// target one alarm. /// </summary> /// <param name="alarmName">When specified, only rules that target this alarm are /// returned.</param> /// <returns>The list of mute rule summaries.</returns> public async Task<List<AlarmMuteRuleSummary>> ListAlarmMuteRules(string? alarmName = null) { var results = new List<AlarmMuteRuleSummary>(); string? nextToken = null; do { var response = await _amazonCloudWatch.ListAlarmMuteRulesAsync( new ListAlarmMuteRulesRequest { AlarmName = alarmName, NextToken = nextToken }); if (response.AlarmMuteRuleSummaries != null) { results.AddRange(response.AlarmMuteRuleSummaries); } nextToken = response.NextToken; } while (!string.IsNullOrEmpty(nextToken)); _logger.LogInformation($"Got {results.Count} alarm mute rules."); return results; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考ListAlarmMuteRules中的。
-
以下代码示例演示了如何使用 ListDashboards。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Get a list of dashboards. /// </summary> /// <returns>A list of DashboardEntry objects.</returns> public async Task<List<DashboardEntry>> ListDashboards() { var results = new List<DashboardEntry>(); var paginateDashboards = _amazonCloudWatch.Paginators.ListDashboards( new ListDashboardsRequest()); // Get the entire list using the paginator. await foreach (var data in paginateDashboards.DashboardEntries) { results.Add(data); } return results; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考ListDashboards中的。
-
以下代码示例演示了如何使用 ListMetrics。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// List metrics available, optionally within a namespace. /// </summary> /// <param name="metricNamespace">Optional CloudWatch namespace to use when listing metrics.</param> /// <param name="filter">Optional dimension filter.</param> /// <param name="metricName">Optional metric name filter.</param> /// <returns>The list of metrics.</returns> public async Task<List<Metric>> ListMetrics(string? metricNamespace = null, DimensionFilter? filter = null, string? metricName = null) { var results = new List<Metric>(); var paginateMetrics = _amazonCloudWatch.Paginators.ListMetrics( new ListMetricsRequest { Namespace = metricNamespace, Dimensions = filter != null ? new List<DimensionFilter> { filter } : null, MetricName = metricName }); // Get the entire list using the paginator. await foreach (var metric in paginateMetrics.Metrics) { results.Add(metric); } return results; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考ListMetrics中的。
-
以下代码示例演示了如何使用 PutAlarmMuteRule。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Create or update an alarm mute rule. While a mute rule is active the targeted /// alarms keep evaluating and keep transitioning between states, but their configured /// actions do not fire. This is the supported way to suppress notifications during a /// known maintenance window, instead of disabling alarm actions and relying on /// someone to turn them back on. /// </summary> /// <param name="name">The name of the mute rule.</param> /// <param name="expression">When the rule activates. For a recurring window, use a /// five-field cron expression, cron(Minutes Hours Day-of-month Month Day-of-week), /// such as cron(0 2 * * SUN) for every Sunday at 2:00 AM. Note that this is five /// fields, not the six that Amazon EventBridge uses. For a one-time window, use /// at(yyyy-MM-ddThh:mm), such as at(2026-09-05T02:00).</param> /// <param name="duration">How long the mute window lasts once it activates, in /// ISO 8601 duration format, from PT1M (one minute) to P15D (15 days). For example, /// PT2H is two hours and P2DT12H is two days and 12 hours.</param> /// <param name="timezone">The time zone the expression is evaluated in, such as /// America/Los_Angeles.</param> /// <param name="alarmNames">The names of up to 100 alarms to mute. If null or empty, /// the rule applies to all alarms in the account.</param> /// <returns>True if successful.</returns> public async Task<bool> PutAlarmMuteRule(string name, string expression, string duration, string timezone, List<string>? alarmNames = null) { var request = new PutAlarmMuteRuleRequest { Name = name, Description = "A mute rule created by the AWS SDK for .NET example.", Rule = new Rule { Schedule = new Schedule { Expression = expression, Duration = duration, Timezone = timezone } } }; if (alarmNames != null && alarmNames.Any()) { request.MuteTargets = new MuteTargets { AlarmNames = alarmNames }; } var response = await _amazonCloudWatch.PutAlarmMuteRuleAsync(request); _logger.LogInformation($"Put alarm mute rule {name}."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考PutAlarmMuteRule中的。
-
以下代码示例演示了如何使用 PutAnomalyDetector。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Add an anomaly detector for a single metric. /// </summary> /// <param name="anomalyDetector">A single metric anomaly detector.</param> /// <returns>True if successful.</returns> public async Task<bool> PutAnomalyDetector(SingleMetricAnomalyDetector anomalyDetector) { var putAlarmDetectorResult = await _amazonCloudWatch.PutAnomalyDetectorAsync( new PutAnomalyDetectorRequest() { SingleMetricAnomalyDetector = anomalyDetector }); return putAlarmDetectorResult.HttpStatusCode == HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考PutAnomalyDetector中的。
-
以下代码示例演示了如何使用 PutDashboard。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Wrapper to create or add to a dashboard with metrics. /// </summary> /// <param name="dashboardName">The name for the dashboard.</param> /// <param name="dashboardBody">The metric data in JSON for the dashboard.</param> /// <returns>A list of validation messages for the dashboard.</returns> public async Task<List<DashboardValidationMessage>> PutDashboard(string dashboardName, string dashboardBody) { // Updating a dashboard replaces all contents. // Best practice is to include a text widget indicating this dashboard was created programmatically. var dashboardResponse = await _amazonCloudWatch.PutDashboardAsync( new PutDashboardRequest() { DashboardName = dashboardName, DashboardBody = dashboardBody }); return dashboardResponse.DashboardValidationMessages ?? new List<DashboardValidationMessage>(); }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考PutDashboard中的。
-
以下代码示例演示了如何使用 PutMetricAlarm。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 创建警报,根据指标评估 PromQL 查询。 OpenTelemetry
/// <summary> /// Create an alarm that evaluates a PromQL query. /// /// A PromQL alarm differs from a classic metric alarm in a few ways. The query can /// match many series at once, and each matching series is tracked separately as a /// contributor. Instead of counting breaching periods, you specify durations: a /// contributor moves to ALARM after it breaches continuously for the pending period, /// and back to OK after it stops breaching for the recovery period. A PromQL alarm /// starts in the OK state rather than INSUFFICIENT_DATA. /// /// EvaluationCriteria is a union and is mutually exclusive with the classic /// MetricName and Metrics properties. When you use it you must also set /// EvaluationInterval, and you must not set Period, Statistic, Threshold, /// ComparisonOperator, EvaluationPeriods, DatapointsToAlarm, or TreatMissingData. /// </summary> /// <param name="alarmName">The name of the alarm, unique within the Region.</param> /// <param name="query">The PromQL query to evaluate, such as /// avg(cpu_utilization_percent) > 80. The comparison belongs in the query itself; /// there is no separate threshold property.</param> /// <param name="evaluationInterval">How often, in seconds, to run the query. Valid /// values are 10, 20, 30, and any multiple of 60, up to 3600.</param> /// <param name="pendingPeriod">How long, in seconds, a contributor must breach /// continuously before it moves to ALARM.</param> /// <param name="recoveryPeriod">How long, in seconds, a contributor must stop /// breaching before it moves back to OK.</param> /// <returns>True if successful.</returns> public async Task<bool> PutPromQLMetricAlarm(string alarmName, string query, int evaluationInterval = 60, int pendingPeriod = 300, int recoveryPeriod = 120) { var response = await _amazonCloudWatch.PutMetricAlarmAsync( new PutMetricAlarmRequest { AlarmName = alarmName, AlarmDescription = "A PromQL alarm created by the AWS SDK for .NET example.", EvaluationCriteria = new EvaluationCriteria { PromQLCriteria = new AlarmPromQLCriteria { Query = query, PendingPeriod = pendingPeriod, RecoveryPeriod = recoveryPeriod } }, EvaluationInterval = evaluationInterval }); _logger.LogInformation($"Created PromQL alarm {alarmName} for query {query}."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }创建评估单个 CloudWatch 指标的警报。
/// <summary> /// Add a metric alarm to send an email when the metric passes a threshold. /// </summary> /// <param name="alarmDescription">A description of the alarm.</param> /// <param name="alarmName">The name for the alarm.</param> /// <param name="comparison">The type of comparison to use.</param> /// <param name="metricName">The name of the metric for the alarm.</param> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="threshold">The threshold value for the alarm.</param> /// <param name="alarmActions">Optional actions to execute when in an alarm state.</param> /// <returns>True if successful.</returns> public async Task<bool> PutMetricEmailAlarm(string alarmDescription, string alarmName, ComparisonOperator comparison, string metricName, string metricNamespace, double threshold, List<string> alarmActions = null!) { try { var putEmailAlarmResponse = await _amazonCloudWatch.PutMetricAlarmAsync( new PutMetricAlarmRequest() { AlarmActions = alarmActions, AlarmDescription = alarmDescription, AlarmName = alarmName, ComparisonOperator = comparison, Threshold = threshold, Namespace = metricNamespace, MetricName = metricName, EvaluationPeriods = 1, Period = 10, Statistic = new Statistic("Maximum"), DatapointsToAlarm = 1, TreatMissingData = "ignore" }); return putEmailAlarmResponse.HttpStatusCode == HttpStatusCode.OK; } catch (LimitExceededException lex) { _logger.LogError(lex, $"Unable to add alarm {alarmName}. Alarm quota has already been reached."); } return false; } /// <summary> /// Add specific email actions to a list of action strings for a CloudWatch alarm. /// </summary> /// <param name="accountId">The AccountId for the alarm.</param> /// <param name="region">The region for the alarm.</param> /// <param name="emailTopicName">An Amazon Simple Notification Service (SNS) topic for the alarm email.</param> /// <param name="alarmActions">Optional list of existing alarm actions to append to.</param> /// <returns>A list of string actions for an alarm.</returns> public List<string> AddEmailAlarmAction(string accountId, string region, string emailTopicName, List<string>? alarmActions = null) { alarmActions ??= new List<string>(); var snsAlarmAction = $"arn:aws:sns:{region}:{accountId}:{emailTopicName}"; alarmActions.Add(snsAlarmAction); return alarmActions; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考PutMetricAlarm中的。
-
以下代码示例演示了如何使用 PutMetricData。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Wrapper to add metric data to a CloudWatch metric. /// </summary> /// <param name="metricNamespace">The namespace of the metric.</param> /// <param name="metricData">A data object for the metric data.</param> /// <returns>True if successful.</returns> public async Task<bool> PutMetricData(string metricNamespace, List<MetricDatum> metricData) { var putDataResponse = await _amazonCloudWatch.PutMetricDataAsync( new PutMetricDataRequest() { MetricData = metricData, Namespace = metricNamespace, }); return putDataResponse.HttpStatusCode == HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考PutMetricData中的。
-
以下代码示例演示了如何使用 StartOTelEnrichment。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Turn on OTel enrichment for the account. Once enrichment is running, CloudWatch /// vended metrics that carry a resource identifier dimension, such as the Amazon EC2 /// CPUUtilization metric with its InstanceId dimension, are decorated with resource /// ARN and resource tag labels and become queryable with PromQL. /// /// Resource tags on telemetry must already be enabled for the account before you /// call this operation. /// </summary> /// <returns>True if successful.</returns> public async Task<bool> StartOTelEnrichment() { var response = await _amazonCloudWatch.StartOTelEnrichmentAsync( new StartOTelEnrichmentRequest()); _logger.LogInformation("Started OTel enrichment for this account."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考StartOTelEnrichment中的。
-
以下代码示例演示了如何使用 StopOTelEnrichment。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 /// <summary> /// Turn off OTel enrichment for the account. Existing PromQL alarms are not deleted, /// but vended metrics stop being enriched with resource ARN and tag labels, so /// queries that select on those labels stop matching. /// </summary> /// <returns>True if successful.</returns> public async Task<bool> StopOTelEnrichment() { var response = await _amazonCloudWatch.StopOTelEnrichmentAsync( new StopOTelEnrichmentRequest()); _logger.LogInformation("Stopped OTel enrichment for this account."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }-
有关 API 的详细信息,请参阅 适用于 .NET 的 Amazon SDK API 参考StopOTelEnrichment中的。
-
场景
以下代码示例展示了如何:
使用 OpenTelemetry 收集器将 OTLP CloudWatch 指标发送到指标端点。
开始 OpenTelemetry 充实,将这些指标与您的资源 CloudWatch 关联起来。
创建一个警报,用于评估查询返回的每个序列的 PromQL 查询。
检查将警报置于 “警报” 状态的各个系列(称为贡献者)。
在维护时段内将警报设为静音,然后进行清理。
- 适用于 .NET 的 Amazon SDK (v4)
-
注意
还有更多 GitHub。在 Amazon 代码示例存储库
中查找完整示例,了解如何进行设置和运行。 CloudWatch OpenTelemetry 操作的包装方法。
/// <summary> /// Wrapper class for the OpenTelemetry features of Amazon CloudWatch: turning on OTel /// enrichment so that CloudWatch vended metrics are queryable with PromQL, alarming on a /// PromQL query, inspecting the individual series (contributors) that put a PromQL alarm /// into ALARM, and muting alarm actions on a schedule. /// /// Note that OTLP metric ingestion is not an AWS SDK operation. To send OpenTelemetry /// metrics to CloudWatch, point an OpenTelemetry collector or the AWS Distro for /// OpenTelemetry (ADOT) SDK at the CloudWatch OTLP metrics endpoint, /// https://monitoring.{region}.amazonaws.com/v1/metrics. The operations here cover /// everything you do after those metrics land in CloudWatch. /// </summary> public class CloudWatchOTelWrapper { private readonly IAmazonCloudWatch _amazonCloudWatch; private readonly ILogger<CloudWatchOTelWrapper> _logger; /// <summary> /// Constructor for the CloudWatch OpenTelemetry wrapper. /// </summary> /// <param name="amazonCloudWatch">The injected CloudWatch client.</param> /// <param name="logger">The injected logger for the wrapper.</param> public CloudWatchOTelWrapper(IAmazonCloudWatch amazonCloudWatch, ILogger<CloudWatchOTelWrapper> logger) { _logger = logger; _amazonCloudWatch = amazonCloudWatch; } /// <summary> /// Turn on OTel enrichment for the account. Once enrichment is running, CloudWatch /// vended metrics that carry a resource identifier dimension, such as the Amazon EC2 /// CPUUtilization metric with its InstanceId dimension, are decorated with resource /// ARN and resource tag labels and become queryable with PromQL. /// /// Resource tags on telemetry must already be enabled for the account before you /// call this operation. /// </summary> /// <returns>True if successful.</returns> public async Task<bool> StartOTelEnrichment() { var response = await _amazonCloudWatch.StartOTelEnrichmentAsync( new StartOTelEnrichmentRequest()); _logger.LogInformation("Started OTel enrichment for this account."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Get the current OTel enrichment status for the account. /// </summary> /// <returns>The status, either Running or Stopped.</returns> public async Task<OTelEnrichmentStatus> GetOTelEnrichmentStatus() { var response = await _amazonCloudWatch.GetOTelEnrichmentAsync( new GetOTelEnrichmentRequest()); _logger.LogInformation($"OTel enrichment status is {response.Status}."); return response.Status; } /// <summary> /// Create an alarm that evaluates a PromQL query. /// /// A PromQL alarm differs from a classic metric alarm in a few ways. The query can /// match many series at once, and each matching series is tracked separately as a /// contributor. Instead of counting breaching periods, you specify durations: a /// contributor moves to ALARM after it breaches continuously for the pending period, /// and back to OK after it stops breaching for the recovery period. A PromQL alarm /// starts in the OK state rather than INSUFFICIENT_DATA. /// /// EvaluationCriteria is a union and is mutually exclusive with the classic /// MetricName and Metrics properties. When you use it you must also set /// EvaluationInterval, and you must not set Period, Statistic, Threshold, /// ComparisonOperator, EvaluationPeriods, DatapointsToAlarm, or TreatMissingData. /// </summary> /// <param name="alarmName">The name of the alarm, unique within the Region.</param> /// <param name="query">The PromQL query to evaluate, such as /// avg(cpu_utilization_percent) > 80. The comparison belongs in the query itself; /// there is no separate threshold property.</param> /// <param name="evaluationInterval">How often, in seconds, to run the query. Valid /// values are 10, 20, 30, and any multiple of 60, up to 3600.</param> /// <param name="pendingPeriod">How long, in seconds, a contributor must breach /// continuously before it moves to ALARM.</param> /// <param name="recoveryPeriod">How long, in seconds, a contributor must stop /// breaching before it moves back to OK.</param> /// <returns>True if successful.</returns> public async Task<bool> PutPromQLMetricAlarm(string alarmName, string query, int evaluationInterval = 60, int pendingPeriod = 300, int recoveryPeriod = 120) { var response = await _amazonCloudWatch.PutMetricAlarmAsync( new PutMetricAlarmRequest { AlarmName = alarmName, AlarmDescription = "A PromQL alarm created by the AWS SDK for .NET example.", EvaluationCriteria = new EvaluationCriteria { PromQLCriteria = new AlarmPromQLCriteria { Query = query, PendingPeriod = pendingPeriod, RecoveryPeriod = recoveryPeriod } }, EvaluationInterval = evaluationInterval }); _logger.LogInformation($"Created PromQL alarm {alarmName} for query {query}."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Get the contributors for a PromQL alarm. Each contributor is one series that the /// alarm's query matched, identified by its label set. This is how you find out which /// hosts, services, or pods are breaching, rather than only that something is. /// </summary> /// <param name="alarmName">The name of the PromQL alarm.</param> /// <returns>The list of contributors.</returns> public async Task<List<AlarmContributor>> DescribeAlarmContributors(string alarmName) { var results = new List<AlarmContributor>(); string? nextToken = null; do { var response = await _amazonCloudWatch.DescribeAlarmContributorsAsync( new DescribeAlarmContributorsRequest { AlarmName = alarmName, NextToken = nextToken }); if (response.AlarmContributors != null) { results.AddRange(response.AlarmContributors); } nextToken = response.NextToken; } while (!string.IsNullOrEmpty(nextToken)); _logger.LogInformation($"Got {results.Count} contributors for alarm {alarmName}."); return results; } /// <summary> /// Create or update an alarm mute rule. While a mute rule is active the targeted /// alarms keep evaluating and keep transitioning between states, but their configured /// actions do not fire. This is the supported way to suppress notifications during a /// known maintenance window, instead of disabling alarm actions and relying on /// someone to turn them back on. /// </summary> /// <param name="name">The name of the mute rule.</param> /// <param name="expression">When the rule activates. For a recurring window, use a /// five-field cron expression, cron(Minutes Hours Day-of-month Month Day-of-week), /// such as cron(0 2 * * SUN) for every Sunday at 2:00 AM. Note that this is five /// fields, not the six that Amazon EventBridge uses. For a one-time window, use /// at(yyyy-MM-ddThh:mm), such as at(2026-09-05T02:00).</param> /// <param name="duration">How long the mute window lasts once it activates, in /// ISO 8601 duration format, from PT1M (one minute) to P15D (15 days). For example, /// PT2H is two hours and P2DT12H is two days and 12 hours.</param> /// <param name="timezone">The time zone the expression is evaluated in, such as /// America/Los_Angeles.</param> /// <param name="alarmNames">The names of up to 100 alarms to mute. If null or empty, /// the rule applies to all alarms in the account.</param> /// <returns>True if successful.</returns> public async Task<bool> PutAlarmMuteRule(string name, string expression, string duration, string timezone, List<string>? alarmNames = null) { var request = new PutAlarmMuteRuleRequest { Name = name, Description = "A mute rule created by the AWS SDK for .NET example.", Rule = new Rule { Schedule = new Schedule { Expression = expression, Duration = duration, Timezone = timezone } } }; if (alarmNames != null && alarmNames.Any()) { request.MuteTargets = new MuteTargets { AlarmNames = alarmNames }; } var response = await _amazonCloudWatch.PutAlarmMuteRuleAsync(request); _logger.LogInformation($"Put alarm mute rule {name}."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Get the full configuration of an alarm mute rule, including its schedule, the /// alarms it targets, and whether it is currently SCHEDULED, ACTIVE, or EXPIRED. /// </summary> /// <param name="name">The name of the mute rule.</param> /// <returns>The mute rule.</returns> public async Task<GetAlarmMuteRuleResponse> GetAlarmMuteRule(string name) { var response = await _amazonCloudWatch.GetAlarmMuteRuleAsync( new GetAlarmMuteRuleRequest { AlarmMuteRuleName = name }); _logger.LogInformation($"Mute rule {response.Name} is {response.Status}."); return response; } /// <summary> /// List the alarm mute rules in the account, optionally filtered to the rules that /// target one alarm. /// </summary> /// <param name="alarmName">When specified, only rules that target this alarm are /// returned.</param> /// <returns>The list of mute rule summaries.</returns> public async Task<List<AlarmMuteRuleSummary>> ListAlarmMuteRules(string? alarmName = null) { var results = new List<AlarmMuteRuleSummary>(); string? nextToken = null; do { var response = await _amazonCloudWatch.ListAlarmMuteRulesAsync( new ListAlarmMuteRulesRequest { AlarmName = alarmName, NextToken = nextToken }); if (response.AlarmMuteRuleSummaries != null) { results.AddRange(response.AlarmMuteRuleSummaries); } nextToken = response.NextToken; } while (!string.IsNullOrEmpty(nextToken)); _logger.LogInformation($"Got {results.Count} alarm mute rules."); return results; } /// <summary> /// Delete an alarm mute rule. The alarms it targeted resume firing their actions. /// </summary> /// <param name="name">The name of the mute rule.</param> /// <returns>True if successful.</returns> public async Task<bool> DeleteAlarmMuteRule(string name) { var response = await _amazonCloudWatch.DeleteAlarmMuteRuleAsync( new DeleteAlarmMuteRuleRequest { AlarmMuteRuleName = name }); _logger.LogInformation($"Deleted alarm mute rule {name}."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Turn off OTel enrichment for the account. Existing PromQL alarms are not deleted, /// but vended metrics stop being enriched with resource ARN and tag labels, so /// queries that select on those labels stop matching. /// </summary> /// <returns>True if successful.</returns> public async Task<bool> StopOTelEnrichment() { var response = await _amazonCloudWatch.StopOTelEnrichmentAsync( new StopOTelEnrichmentRequest()); _logger.LogInformation("Stopped OTel enrichment for this account."); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; }-
有关 API 详细信息,请参阅《适用于 .NET 的 Amazon SDK API Reference》中的以下主题。
-