View a markdown version of this page

SDK for Python (Boto3)을 사용한 CloudWatch 예제 - AWSSDK 코드 예제

Doc AWSSDK 예제 GitHub 리포지토리에서 더 많은 SDK 예제를 사용할 수 있습니다. AWS

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

SDK for Python (Boto3)을 사용한 CloudWatch 예제

다음 코드 예제에서는 CloudWatch와 AWS SDK for Python (Boto3)함께를 사용하여 작업을 수행하고 일반적인 시나리오를 구현하는 방법을 보여줍니다.

기본 사항은 서비스 내에서 필수 작업을 수행하는 방법을 보여주는 코드 예제입니다.

작업은 대규모 프로그램에서 발췌한 코드이며 컨텍스트에 맞춰 실행해야 합니다. 작업은 개별 서비스 함수를 직접 호출하는 방법을 보여주며, 관련 시나리오의 컨텍스트에 맞는 작업을 볼 수 있습니다.

시나리오는 동일한 서비스 내에서 또는 다른 AWS 서비스와 결합된 상태에서 여러 함수를 직접적으로 호출하여 특정 태스크를 수행하는 방법을 보여주는 코드 예제입니다.

각 예시에는 전체 소스 코드에 대한 링크가 포함되어 있으며, 여기에서 컨텍스트에 맞춰 코드를 설정하고 실행하는 방법에 대한 지침을 찾을 수 있습니다.

기본 사항

다음 코드 예제에서는 다음과 같은 작업을 수행하는 방법을 보여줍니다.

  • CloudWatch 네임스페이스 및 지표를 나열합니다.

  • CloudWatch가 수신 OTLP 지표를 생성한 리소스와 상호 연관시키도록 OpenTelemetry 보강을 시작합니다.

  • OTLP 지표가 CloudWatch 지표 엔드포인트에 도달하는 방법을 알아봅니다. OTLP를 통한 지표 수집은 AWSSDK 작업이 아닙니다.

  • PromQL 쿼리를 평가하는 경보를 생성합니다.

  • 쿼리가 일치하는 개별 시리즈인 경보의 기여자를 검사합니다.

  • 지표에 대한 통계를 가져와 대시보드에서 차트로 작성합니다.

  • 유지 관리 기간에 대한 경보를 음소거한 다음 정리합니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

CloudWatch OpenTelemetry 환경을 보여주는 대화형 시나리오를 실행합니다.

from collections import Counter from datetime import datetime, timedelta, timezone import json import logging import random import sys import boto3 from botocore.exceptions import ClientError from cloudwatch_basics import CloudWatchWrapper from cloudwatch_otel import CloudWatchOTelWrapper logger = logging.getLogger(__name__) DEFAULT_QUERY = "avg by (host) (system_cpu_utilization) > 80" # Valid evaluation intervals are 10, 20, 30, or any multiple of 60 up to 3600 seconds. EVALUATION_INTERVAL = 60 PENDING_PERIOD = 300 RECOVERY_PERIOD = 120 DASHES = "-" * 80 class CloudWatchScenario: """Runs an interactive scenario that shows how to use Amazon CloudWatch.""" def __init__(self, cloudwatch_wrapper, otel_wrapper): """ :param cloudwatch_wrapper: An object that wraps CloudWatch metric, statistic, and dashboard actions. :param otel_wrapper: An object that wraps CloudWatch OTel enrichment, PromQL alarm, and alarm mute rule actions. """ self.cloudwatch_wrapper = cloudwatch_wrapper self.otel_wrapper = otel_wrapper # Suffix the resource names so repeated runs do not collide. suffix = random.randint(1000, 9999) self.alarm_name = f"doc-example-promql-alarm-{suffix}" self.dashboard_name = f"doc-example-dashboard-{suffix}" self.mute_rule_name = f"doc-example-mute-rule-{suffix}" # Tracks whether this run turned enrichment on, so that cleanup only turns off # enrichment that this run started. self.started_enrichment = False self.dashboard_created = False def run_scenario(self): """Runs the eight steps of the scenario in order.""" print(DASHES) print("Welcome to the Amazon CloudWatch Basics scenario.") print( "\nCloudWatch now ingests OpenTelemetry metrics natively. This scenario walks\n" "through that experience: it turns on OTel enrichment so CloudWatch can\n" "correlate incoming OTLP metrics with the resources that produced them, alarms\n" "on those metrics with a PromQL query, and shows you which individual series\n" "drove the alarm.\n" "\nA PromQL alarm works differently from a classic metric alarm. Rather than\n" "watching one metric and counting breaching periods, it evaluates a query that\n" "can match many series at once, and tracks each one separately as a contributor." ) print(DASHES) namespaces = self.list_metrics_and_namespaces() self.start_otel_enrichment() self.explain_otlp_ingestion() self.create_promql_alarm() self.inspect_alarm_contributors() self.get_statistics_and_chart_metric(namespaces) self.mute_alarm_for_maintenance() def list_metrics_and_namespaces(self): """ Lists the metrics and namespaces already present in the account, to orient the reader before any configuration happens. :return: A Counter of namespace to metric count, most common first. """ print("1. List metrics and namespaces") print( "\nBefore configuring anything, let's see what CloudWatch is already\n" "collecting in this account by calling ListMetrics.\n" ) namespaces = Counter() metric_count = 0 for metric in self.cloudwatch_wrapper.list_all_metrics(): namespaces[metric.namespace] += 1 metric_count += 1 # This account may have a very large number of metrics, so stop once we # have enough to give the reader a sense of what is there. if metric_count >= 500: break print(f"\tFound {metric_count} metrics across {len(namespaces)} namespaces:") for namespace, count in namespaces.most_common(10): print(f"\t {namespace} ({count} metrics)") if not namespaces: print( "\tNo metrics found in this account. The statistics and dashboard steps\n" "\tlater on need an existing metric, so they will be skipped." ) print(DASHES) return namespaces def start_otel_enrichment(self): """ Starts OTel enrichment, but only if it is not already running. Enrichment is what makes CloudWatch attach AWS resource context to incoming OTLP metrics. """ print("2. Start OpenTelemetry enrichment") print( "\nEnrichment is what lets CloudWatch attach AWS resource context to the OTLP\n" "metrics you send it. Without it, your metrics arrive as opaque series with no\n" "connection to the resources that emitted them.\n" "\nWe check the current state first, and only start enrichment if it isn't\n" "already on.\n" ) status = self.otel_wrapper.get_otel_enrichment_status() print(f"\tEnrichment status: {status}") if status != "Running": self.otel_wrapper.start_otel_enrichment() self.started_enrichment = True status = self.otel_wrapper.get_otel_enrichment_status() print(f"\tEnrichment status: {status}") print( "\n\tNote: this run started enrichment, so the cleanup step will stop it\n" "\tagain." ) else: print( "\n\tEnrichment was already running, so we will leave it alone. The cleanup\n" "\tstep will not stop it, because other workloads in this account may\n" "\tdepend on it." ) print(DASHES) @staticmethod def explain_otlp_ingestion(): """ Explains that OTLP metric ingestion is not an AWS SDK operation. This step makes no service call; naming the gap explicitly is the point. """ print("3. Send OTLP metrics to CloudWatch") print( "\nThis step is not an AWS SDK operation, and that's worth being explicit\n" "about. Metrics reach CloudWatch over the OTLP protocol, through the CloudWatch\n" "agent, an OpenTelemetry Collector, or an ADOT SDK. There is no PutOTelMetrics\n" "API to call.\n" "\nPoint your collector at the CloudWatch metrics endpoint, which follows the\n" "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\n" "exporter rather than otlp. The metrics endpoint signs as 'monitoring'.\n" "\nSee otlp_collector_config.yaml in this folder for a working collector\n" "configuration." ) print(DASHES) def create_promql_alarm(self): """Creates an alarm whose evaluation is a PromQL query.""" print("4. Create a PromQL alarm") print( "\nNow we alarm on those metrics. The comparison goes inside the query itself:\n" "a PromQL alarm has no separate threshold, comparison operator, statistic, or\n" "period.\n" ) query = ( input( f"Enter a PromQL query, or press ENTER for [{DEFAULT_QUERY}]: " ).strip() or DEFAULT_QUERY ) self.otel_wrapper.create_promql_alarm( self.alarm_name, query, EVALUATION_INTERVAL, pending_period=PENDING_PERIOD, recovery_period=RECOVERY_PERIOD, description="A PromQL alarm created by the Boto3 Basics scenario.", ) print(f"\tCreated alarm {self.alarm_name}:") print(f"\t query: {query}") print(f"\t evaluationInterval: {EVALUATION_INTERVAL} seconds") print(f"\t pendingPeriod: {PENDING_PERIOD} seconds") print(f"\t recoveryPeriod: {RECOVERY_PERIOD} seconds") print( "\n\tA PromQL alarm starts in the OK state rather than INSUFFICIENT_DATA, which\n" "\tis another way it differs from a classic alarm." ) print(DASHES) def inspect_alarm_contributors(self): """ Shows which individual series the alarm's query matched. This is the step with no classic-alarm equivalent. """ print("5. Inspect the alarm's contributors") print( "\nEach contributor is one series the query matched, identified by its label\n" "set. This is how you find out which host is unhealthy rather than only that\n" "something is. Classic alarms have no equivalent.\n" ) contributors = self.otel_wrapper.describe_alarm_contributors(self.alarm_name) if not contributors: print( "\tNo contributors yet. The query matched no series, which usually means no\n" "\tOTel metrics with these labels have arrived. Once your collector is\n" "\tsending data, each matching series appears here with its labels and the\n" "\treason it breached." ) else: print(f"\tFound {len(contributors)} contributors:") for contributor in contributors: labels = ", ".join( f"{key}={value}" for key, value in sorted( contributor.get("ContributorAttributes", {}).items() ) ) print(f"\t {contributor['ContributorId']}: {labels}") print(f"\t reason: {contributor.get('StateReason')}") print(DASHES) def get_statistics_and_chart_metric(self, namespaces): """ Gets statistics for an existing metric and charts it on a dashboard, so the reader can see what the alarm is evaluating. :param namespaces: The Counter of namespaces discovered in step 1. """ print("6. Get statistics and chart the metric on a dashboard") print( "\nStatistics and dashboards are how you see what the alarm is evaluating.\n" ) if not namespaces: print("\tSkipping statistics and dashboard because no metrics exist yet.") print(DASHES) return namespace = namespaces.most_common(1)[0][0] metric = next( ( candidate for candidate in self.cloudwatch_wrapper.list_all_metrics() if candidate.namespace == namespace ), None, ) if metric is None: print(f"\tNo metrics found in namespace {namespace}, skipping.") print(DASHES) return try: stats = self.cloudwatch_wrapper.get_metric_statistics( metric.namespace, metric.name, datetime.now(timezone.utc) - timedelta(days=1), datetime.now(timezone.utc), 3600, ["Average", "Maximum"], ) datapoints = stats["Datapoints"] print( f"\tStatistics for {metric.namespace} {metric.name} over the last day:" ) print(f"\t Datapoints: {len(datapoints)}") for datapoint in datapoints[:3]: print( f"\t {datapoint['Timestamp']} average {datapoint.get('Average')}, " f"maximum {datapoint.get('Maximum')}" ) except ClientError as error: print(f"\tCould not get statistics: {error}") try: region = self.otel_wrapper.cloudwatch_client.meta.region_name body = self.build_dashboard_body(metric, region) messages = self.cloudwatch_wrapper.put_dashboard(self.dashboard_name, body) self.dashboard_created = True for message in messages: print(f"\tDashboard validation message: {message.get('Message')}") print(f"\tCreated dashboard {self.dashboard_name}.") stored = self.cloudwatch_wrapper.get_dashboard(self.dashboard_name) print( f"\tRead the dashboard back, {len(stored)} characters of widget JSON." ) except ClientError as error: print(f"\tCould not create the dashboard: {error}") print(DASHES) @staticmethod def build_dashboard_body(metric, region): """ Builds a single-widget dashboard body that charts the given metric. :param metric: A Boto3 CloudWatch Metric resource. :param region: The region the metric is in. A metric widget must name its region, because a dashboard can chart metrics from several. :return: The dashboard body, as a JSON string. """ metric_spec = [metric.namespace, metric.name] for dimension in metric.dimensions or []: metric_spec.extend([dimension["Name"], dimension["Value"]]) return json.dumps( { "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": [metric_spec], "view": "timeSeries", "stat": "Average", "period": 300, "region": region, "title": metric.name, }, }, ] } ) def mute_alarm_for_maintenance(self): """ Creates a mute rule so the alarm's actions are suppressed during a maintenance window, then reads it back and finds it in the account's rules. """ print("7. Mute the alarm for a maintenance window") print( "\nWhile a mute rule is active the targeted alarms keep evaluating and keep\n" "changing state, but their actions do not fire. This is the supported way to\n" "suppress notifications during planned maintenance, instead of disabling alarm\n" "actions and hoping 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. expression = "cron(0 2 * * SUN)" duration = "PT2H" tz = "America/Los_Angeles" self.otel_wrapper.put_alarm_mute_rule( self.mute_rule_name, expression, duration, alarm_names=[self.alarm_name], timezone=tz, description="A mute rule created by the Boto3 Basics scenario.", ) print(f"\tCreated mute rule {self.mute_rule_name}:") print(f"\t schedule: {expression} for {duration}") print(f"\t timezone: {tz}") print(f"\t targets: {self.alarm_name}") print( "\n\tNote the two formats here. The expression is a five-field cron expression,\n" "\tfive rather 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." ) mute_rule = self.otel_wrapper.get_alarm_mute_rule(self.mute_rule_name) print( f"\tRead the rule back: status {mute_rule.get('Status')}, " f"mute type {mute_rule.get('MuteType')}." ) summaries = self.otel_wrapper.list_alarm_mute_rules(alarm_name=self.alarm_name) print(f"\tFound {len(summaries)} mute rules targeting this alarm.") # Mute rule summaries carry no name field, only an ARN, so match on the ARN # suffix. for summary in summaries: arn = summary.get("AlarmMuteRuleArn", "") if arn.endswith(f"/{self.mute_rule_name}") or arn.endswith( f":{self.mute_rule_name}" ): print(f"\t matched by ARN: {arn} ({summary.get('Status')})") break print(DASHES) def clean_up(self): """ Deletes the resources the scenario created. Each deletion is attempted independently so that one failure does not leave the remaining resources behind. """ print("8. Clean up") answer = input("Delete the resources this scenario created? (y/n) ") if answer.strip().lower() != "y": print( "\tSkipping cleanup. Note that the alarm, dashboard, and mute rule are\n" "\tstill in your account, and enrichment may still be running." ) print(DASHES) return try: self.otel_wrapper.delete_alarm_mute_rule(self.mute_rule_name) print(f"\tDeleted mute rule {self.mute_rule_name}.") except ClientError as error: print(f"\tCould not delete the mute rule: {error}") try: self.otel_wrapper.delete_alarms([self.alarm_name]) print(f"\tDeleted alarm {self.alarm_name}.") except ClientError as error: print(f"\tCould not delete the alarm: {error}") if self.dashboard_created: try: self.cloudwatch_wrapper.delete_dashboards([self.dashboard_name]) print(f"\tDeleted dashboard {self.dashboard_name}.") except ClientError as error: print(f"\tCould not delete the dashboard: {error}") if self.started_enrichment: try: self.otel_wrapper.stop_otel_enrichment() print("\tStopped OTel enrichment, because this run started it.") except ClientError as error: print(f"\tCould not stop OTel enrichment: {error}") else: print( "\tLeft OTel enrichment running, because it was already on before this run." ) print(DASHES) def main(): logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") scenario = CloudWatchScenario( CloudWatchWrapper(boto3.resource("cloudwatch")), CloudWatchOTelWrapper(boto3.client("cloudwatch")), ) try: scenario.run_scenario() except Exception: # pylint: disable=broad-except logging.exception("Something went wrong with the scenario.") finally: scenario.clean_up() print("This concludes the Amazon CloudWatch Basics scenario.") if __name__ == "__main__": sys.exit(main())

시나리오가 호출하는 CloudWatch OpenTelemetry 작업을 래핑하는 클래스입니다.

import logging import time import boto3 from botocore.exceptions import ClientError logger = logging.getLogger(__name__) class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def get_otel_enrichment_status(self): """ Gets the current OTel enrichment status for the account. :return: The status, either 'Running' or 'Stopped'. """ try: response = self.cloudwatch_client.get_o_tel_enrichment() except ClientError: logger.exception("Couldn't get the OTel enrichment status.") raise else: status = response["Status"] logger.info("OTel enrichment status is %s.", status) return status def start_otel_enrichment(self): """ Turns on OTel enrichment for the account. Once enrichment is running, CloudWatch vended metrics that carry a resource identifier dimension, such as the 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. """ try: # Boto3 splits the OTel prefix when it converts the StartOTelEnrichment # operation name to snake case, so the method is start_o_tel_enrichment. self.cloudwatch_client.start_o_tel_enrichment() logger.info("Started OTel enrichment for this account.") except ClientError: logger.exception("Couldn't start OTel enrichment.") raise def create_promql_alarm( self, alarm_name, query, evaluation_interval, pending_period=300, recovery_period=120, description=None, alarm_actions=None, ): """ Creates 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. The PromQL evaluation parameters live in the EvaluationCriteria union, which is mutually exclusive with the classic MetricName and Metrics parameters. When you use EvaluationCriteria you must also set EvaluationInterval, and you must not set Period, Statistic, Threshold, ComparisonOperator, EvaluationPeriods, DatapointsToAlarm, or TreatMissingData. :param alarm_name: The name of the alarm. Must be unique within the Region. :param 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 parameter. :param evaluation_interval: How often, in seconds, to run the query. Valid values are 10, 20, 30, and any multiple of 60, up to 3600. :param pending_period: How long, in seconds, a contributor must breach continuously before it moves to ALARM. :param recovery_period: How long, in seconds, a contributor must stop breaching before it moves back to OK. :param description: The description of the alarm. :param alarm_actions: A list of ARNs to notify when the alarm fires, such as an Amazon SNS topic. """ promql_criteria = { "Query": query, "PendingPeriod": pending_period, "RecoveryPeriod": recovery_period, } kwargs = { "AlarmName": alarm_name, "EvaluationCriteria": {"PromQLCriteria": promql_criteria}, "EvaluationInterval": evaluation_interval, } if description is not None: kwargs["AlarmDescription"] = description if alarm_actions is not None: kwargs["AlarmActions"] = alarm_actions try: self.cloudwatch_client.put_metric_alarm(**kwargs) logger.info("Created PromQL alarm %s for query %s.", alarm_name, query) except ClientError: logger.exception("Couldn't create PromQL alarm %s.", alarm_name) raise def describe_alarm_contributors(self, alarm_name): """ Gets 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. :param alarm_name: The name of the PromQL alarm. :return: The list of contributors. Each contributor has a ContributorId, a ContributorAttributes map of the labels that identify the series, a StateReason, and the time it last changed state. """ contributors = [] try: next_token = None while True: kwargs = {"AlarmName": alarm_name} if next_token is not None: kwargs["NextToken"] = next_token response = self.cloudwatch_client.describe_alarm_contributors(**kwargs) contributors.extend(response["AlarmContributors"]) next_token = response.get("NextToken") if not next_token: break except ClientError: logger.exception("Couldn't get contributors for alarm %s.", alarm_name) raise else: logger.info( "Got %s contributors for alarm %s.", len(contributors), alarm_name ) return contributors def put_alarm_mute_rule( self, name, expression, duration, alarm_names=None, timezone=None, description=None, ): """ Creates or updates 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 hoping someone remembers to turn them back on. :param name: The name of the mute rule. :param 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 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 alarm_names: The names of up to 100 alarms to mute. If omitted, the rule applies to all alarms in the account. :param timezone: The time zone the expression is evaluated in, such as 'America/Los_Angeles'. :param description: The description of the mute rule. """ schedule = {"Expression": expression, "Duration": duration} if timezone is not None: schedule["Timezone"] = timezone kwargs = {"Name": name, "Rule": {"Schedule": schedule}} if alarm_names is not None: kwargs["MuteTargets"] = {"AlarmNames": alarm_names} if description is not None: kwargs["Description"] = description try: self.cloudwatch_client.put_alarm_mute_rule(**kwargs) logger.info("Put alarm mute rule %s.", name) except ClientError: logger.exception("Couldn't put alarm mute rule %s.", name) raise def get_alarm_mute_rule(self, name): """ Gets the full configuration of an alarm mute rule, including its schedule, the alarms it targets, and whether it is currently SCHEDULED, ACTIVE, or EXPIRED. :param name: The name of the mute rule. :return: The mute rule. """ try: response = self.cloudwatch_client.get_alarm_mute_rule( AlarmMuteRuleName=name ) except ClientError: logger.exception("Couldn't get alarm mute rule %s.", name) raise else: logger.info("Got alarm mute rule %s.", name) return response def list_alarm_mute_rules(self, alarm_name=None, statuses=None): """ Lists alarm mute rules in the account. :param alarm_name: When specified, only rules that target this alarm are returned. :param statuses: When specified, only rules in these statuses are returned. Valid values are 'SCHEDULED', 'ACTIVE', and 'EXPIRED'. :return: The list of mute rule summaries. """ summaries = [] try: next_token = None while True: kwargs = {} if alarm_name is not None: kwargs["AlarmName"] = alarm_name if statuses is not None: kwargs["Statuses"] = statuses if next_token is not None: kwargs["NextToken"] = next_token response = self.cloudwatch_client.list_alarm_mute_rules(**kwargs) summaries.extend(response.get("AlarmMuteRuleSummaries", [])) next_token = response.get("NextToken") if not next_token: break except ClientError: logger.exception("Couldn't list alarm mute rules.") raise else: logger.info("Got %s alarm mute rules.", len(summaries)) return summaries def delete_alarm_mute_rule(self, name): """ Deletes an alarm mute rule. :param name: The name of the mute rule. """ try: self.cloudwatch_client.delete_alarm_mute_rule(AlarmMuteRuleName=name) logger.info("Deleted alarm mute rule %s.", name) except ClientError: logger.exception("Couldn't delete alarm mute rule %s.", name) raise def stop_otel_enrichment(self): """ Turns 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. """ try: self.cloudwatch_client.stop_o_tel_enrichment() logger.info("Stopped OTel enrichment for this account.") except ClientError: logger.exception("Couldn't stop OTel enrichment.") raise

시나리오가 호출하는 지표, 통계 및 대시보드 작업입니다.

def list_all_metrics(self): """ Gets every metric in the account, without filtering by namespace or name. Use this to discover what CloudWatch is already collecting before you configure anything. :return: An iterator that yields the retrieved metrics. """ try: metric_iter = self.cloudwatch_resource.metrics.all() logger.info("Got all metrics for the account.") except ClientError: logger.exception("Couldn't get metrics for the account.") raise else: return metric_iter def get_metric_statistics(self, namespace, name, start, end, period, stat_types): """ Gets statistics for a metric within a specified time span. Metrics are grouped into the specified period. :param namespace: The namespace of the metric. :param name: The name of the metric. :param start: The UTC start time of the time span to retrieve. :param end: The UTC end time of the time span to retrieve. :param period: The period, in seconds, in which to group metrics. The period must match the granularity of the metric, which depends on the metric's age. For example, metrics that are older than three hours have a one-minute granularity, so the period must be at least 60 and must be a multiple of 60. :param stat_types: The type of statistics to retrieve, such as average value or maximum value. :return: The retrieved statistics for the metric. """ try: metric = self.cloudwatch_resource.Metric(namespace, name) stats = metric.get_statistics( StartTime=start, EndTime=end, Period=period, Statistics=stat_types ) logger.info( "Got %s statistics for %s.", len(stats["Datapoints"]), stats["Label"] ) except ClientError: logger.exception("Couldn't get statistics for %s.%s.", namespace, name) raise else: return stats def put_dashboard(self, name, body): """ Creates or replaces a dashboard. The body is a JSON document describing the dashboard's widgets. :param name: The name of the dashboard. :param body: The dashboard body, as a JSON string. :return: Any validation messages the service returned. An empty list means the dashboard body was accepted as written. """ try: response = self.cloudwatch_resource.meta.client.put_dashboard( DashboardName=name, DashboardBody=body ) logger.info("Put dashboard %s.", name) except ClientError: logger.exception("Couldn't put dashboard %s.", name) raise else: return response.get("DashboardValidationMessages", []) def get_dashboard(self, name): """ Gets a dashboard's body, so you can confirm what the service actually stored. :param name: The name of the dashboard. :return: The dashboard body, as a JSON string. """ try: response = self.cloudwatch_resource.meta.client.get_dashboard( DashboardName=name ) logger.info("Got dashboard %s.", name) except ClientError: logger.exception("Couldn't get dashboard %s.", name) raise else: return response["DashboardBody"] def delete_dashboards(self, names): """ Deletes the specified dashboards. :param names: The names of the dashboards to delete. """ try: self.cloudwatch_resource.meta.client.delete_dashboards(DashboardNames=names) logger.info("Deleted dashboards %s.", ", ".join(names)) except ClientError: logger.exception("Couldn't delete dashboards %s.", ", ".join(names)) raise

작업

다음 코드 예시는 DeleteAlarmMuteRule의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def delete_alarm_mute_rule(self, name): """ Deletes an alarm mute rule. :param name: The name of the mute rule. """ try: self.cloudwatch_client.delete_alarm_mute_rule(AlarmMuteRuleName=name) logger.info("Deleted alarm mute rule %s.", name) except ClientError: logger.exception("Couldn't delete alarm mute rule %s.", name) raise
  • API 세부 정보는 SDK for Python (Boto3) API 참조의 DeleteAlarmMuteRule을 참조하세요. AWS

다음 코드 예시는 DeleteAlarms의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def delete_metric_alarms(self, metric_namespace, metric_name): """ Deletes all of the alarms that are currently watching the specified metric. :param metric_namespace: The namespace of the metric. :param metric_name: The name of the metric. """ try: metric = self.cloudwatch_resource.Metric(metric_namespace, metric_name) metric.alarms.delete() logger.info( "Deleted alarms for metric %s.%s.", metric_namespace, metric_name ) except ClientError: logger.exception( "Couldn't delete alarms for metric %s.%s.", metric_namespace, metric_name, ) raise
  • API 세부 정보는 AWS SDK for Python (Boto3) API 참조의 DeleteAlarms을 참조하세요.

다음 코드 예시는 DescribeAlarmContributors의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def describe_alarm_contributors(self, alarm_name): """ Gets 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. :param alarm_name: The name of the PromQL alarm. :return: The list of contributors. Each contributor has a ContributorId, a ContributorAttributes map of the labels that identify the series, a StateReason, and the time it last changed state. """ contributors = [] try: next_token = None while True: kwargs = {"AlarmName": alarm_name} if next_token is not None: kwargs["NextToken"] = next_token response = self.cloudwatch_client.describe_alarm_contributors(**kwargs) contributors.extend(response["AlarmContributors"]) next_token = response.get("NextToken") if not next_token: break except ClientError: logger.exception("Couldn't get contributors for alarm %s.", alarm_name) raise else: logger.info( "Got %s contributors for alarm %s.", len(contributors), alarm_name ) return contributors

다음 코드 예시는 DescribeAlarmsForMetric의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def get_metric_alarms(self, metric_namespace, metric_name): """ Gets the alarms that are currently watching the specified metric. :param metric_namespace: The namespace of the metric. :param metric_name: The name of the metric. :returns: An iterator that yields the alarms. """ metric = self.cloudwatch_resource.Metric(metric_namespace, metric_name) alarm_iter = metric.alarms.all() logger.info("Got alarms for metric %s.%s.", metric_namespace, metric_name) return alarm_iter

다음 코드 예시는 DisableAlarmActions의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def enable_alarm_actions(self, alarm_name, enable): """ Enables or disables actions on the specified alarm. Alarm actions can be used to send notifications or automate responses when an alarm enters a particular state. :param alarm_name: The name of the alarm. :param enable: When True, actions are enabled for the alarm. Otherwise, they disabled. """ try: alarm = self.cloudwatch_resource.Alarm(alarm_name) if enable: alarm.enable_actions() else: alarm.disable_actions() logger.info( "%s actions for alarm %s.", "Enabled" if enable else "Disabled", alarm_name, ) except ClientError: logger.exception( "Couldn't %s actions alarm %s.", "enable" if enable else "disable", alarm_name, ) raise
  • API 세부 정보는 AWS SDK for Python (Boto3) API 참조의 DisableAlarmActions을 참조하세요.

다음 코드 예시는 EnableAlarmActions의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def enable_alarm_actions(self, alarm_name, enable): """ Enables or disables actions on the specified alarm. Alarm actions can be used to send notifications or automate responses when an alarm enters a particular state. :param alarm_name: The name of the alarm. :param enable: When True, actions are enabled for the alarm. Otherwise, they disabled. """ try: alarm = self.cloudwatch_resource.Alarm(alarm_name) if enable: alarm.enable_actions() else: alarm.disable_actions() logger.info( "%s actions for alarm %s.", "Enabled" if enable else "Disabled", alarm_name, ) except ClientError: logger.exception( "Couldn't %s actions alarm %s.", "enable" if enable else "disable", alarm_name, ) raise
  • API 세부 정보는 AWS SDK for Python (Boto3) API 참조의 EnableAlarmActions을 참조하세요.

다음 코드 예시는 GetAlarmMuteRule의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def get_alarm_mute_rule(self, name): """ Gets the full configuration of an alarm mute rule, including its schedule, the alarms it targets, and whether it is currently SCHEDULED, ACTIVE, or EXPIRED. :param name: The name of the mute rule. :return: The mute rule. """ try: response = self.cloudwatch_client.get_alarm_mute_rule( AlarmMuteRuleName=name ) except ClientError: logger.exception("Couldn't get alarm mute rule %s.", name) raise else: logger.info("Got alarm mute rule %s.", name) return response
  • API 세부 정보는 SDK for Python (Boto3) API 참조의 GetAlarmMuteRule을 참조하세요. AWS

다음 코드 예시는 GetMetricStatistics의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def get_metric_statistics(self, namespace, name, start, end, period, stat_types): """ Gets statistics for a metric within a specified time span. Metrics are grouped into the specified period. :param namespace: The namespace of the metric. :param name: The name of the metric. :param start: The UTC start time of the time span to retrieve. :param end: The UTC end time of the time span to retrieve. :param period: The period, in seconds, in which to group metrics. The period must match the granularity of the metric, which depends on the metric's age. For example, metrics that are older than three hours have a one-minute granularity, so the period must be at least 60 and must be a multiple of 60. :param stat_types: The type of statistics to retrieve, such as average value or maximum value. :return: The retrieved statistics for the metric. """ try: metric = self.cloudwatch_resource.Metric(namespace, name) stats = metric.get_statistics( StartTime=start, EndTime=end, Period=period, Statistics=stat_types ) logger.info( "Got %s statistics for %s.", len(stats["Datapoints"]), stats["Label"] ) except ClientError: logger.exception("Couldn't get statistics for %s.%s.", namespace, name) raise else: return stats
  • API 세부 정보는 AWS SDK for Python (Boto3) API 참조의 GetMetricStatistics를 참조하세요.

다음 코드 예시는 GetOTelEnrichment의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def get_otel_enrichment_status(self): """ Gets the current OTel enrichment status for the account. :return: The status, either 'Running' or 'Stopped'. """ try: response = self.cloudwatch_client.get_o_tel_enrichment() except ClientError: logger.exception("Couldn't get the OTel enrichment status.") raise else: status = response["Status"] logger.info("OTel enrichment status is %s.", status) return status
  • API 세부 정보는 SDK for Python (Boto3) API 참조의 GetOTelEnrichment를 참조하세요. AWS

다음 코드 예시는 ListAlarmMuteRules의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def list_alarm_mute_rules(self, alarm_name=None, statuses=None): """ Lists alarm mute rules in the account. :param alarm_name: When specified, only rules that target this alarm are returned. :param statuses: When specified, only rules in these statuses are returned. Valid values are 'SCHEDULED', 'ACTIVE', and 'EXPIRED'. :return: The list of mute rule summaries. """ summaries = [] try: next_token = None while True: kwargs = {} if alarm_name is not None: kwargs["AlarmName"] = alarm_name if statuses is not None: kwargs["Statuses"] = statuses if next_token is not None: kwargs["NextToken"] = next_token response = self.cloudwatch_client.list_alarm_mute_rules(**kwargs) summaries.extend(response.get("AlarmMuteRuleSummaries", [])) next_token = response.get("NextToken") if not next_token: break except ClientError: logger.exception("Couldn't list alarm mute rules.") raise else: logger.info("Got %s alarm mute rules.", len(summaries)) return summaries
  • API 세부 정보는 SDK for Python (Boto3) API 참조의 ListAlarmMuteRules를 참조하세요. AWS

다음 코드 예시는 ListMetrics의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def list_metrics(self, namespace, name, recent=False): """ Gets the metrics within a namespace that have the specified name. If the metric has no dimensions, a single metric is returned. Otherwise, metrics for all dimensions are returned. :param namespace: The namespace of the metric. :param name: The name of the metric. :param recent: When True, only metrics that have been active in the last three hours are returned. :return: An iterator that yields the retrieved metrics. """ try: kwargs = {"Namespace": namespace, "MetricName": name} if recent: kwargs["RecentlyActive"] = "PT3H" # List past 3 hours only metric_iter = self.cloudwatch_resource.metrics.filter(**kwargs) logger.info("Got metrics for %s.%s.", namespace, name) except ClientError: logger.exception("Couldn't get metrics for %s.%s.", namespace, name) raise else: return metric_iter
  • API 세부 정보는 AWS SDK for Python (Boto3) API 참조의 ListMetrics을 참조하세요.

다음 코드 예시는 PutAlarmMuteRule의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def put_alarm_mute_rule( self, name, expression, duration, alarm_names=None, timezone=None, description=None, ): """ Creates or updates 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 hoping someone remembers to turn them back on. :param name: The name of the mute rule. :param 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 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 alarm_names: The names of up to 100 alarms to mute. If omitted, the rule applies to all alarms in the account. :param timezone: The time zone the expression is evaluated in, such as 'America/Los_Angeles'. :param description: The description of the mute rule. """ schedule = {"Expression": expression, "Duration": duration} if timezone is not None: schedule["Timezone"] = timezone kwargs = {"Name": name, "Rule": {"Schedule": schedule}} if alarm_names is not None: kwargs["MuteTargets"] = {"AlarmNames": alarm_names} if description is not None: kwargs["Description"] = description try: self.cloudwatch_client.put_alarm_mute_rule(**kwargs) logger.info("Put alarm mute rule %s.", name) except ClientError: logger.exception("Couldn't put alarm mute rule %s.", name) raise
  • API 세부 정보는 SDK for Python (Boto3) API 참조의 PutAlarmMuteRule을 참조하세요. AWS

다음 코드 예시는 PutMetricAlarm의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

OpenTelemetry 지표에 대해 PromQL 쿼리를 평가하는 경보를 생성합니다.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def create_promql_alarm( self, alarm_name, query, evaluation_interval, pending_period=300, recovery_period=120, description=None, alarm_actions=None, ): """ Creates 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. The PromQL evaluation parameters live in the EvaluationCriteria union, which is mutually exclusive with the classic MetricName and Metrics parameters. When you use EvaluationCriteria you must also set EvaluationInterval, and you must not set Period, Statistic, Threshold, ComparisonOperator, EvaluationPeriods, DatapointsToAlarm, or TreatMissingData. :param alarm_name: The name of the alarm. Must be unique within the Region. :param 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 parameter. :param evaluation_interval: How often, in seconds, to run the query. Valid values are 10, 20, 30, and any multiple of 60, up to 3600. :param pending_period: How long, in seconds, a contributor must breach continuously before it moves to ALARM. :param recovery_period: How long, in seconds, a contributor must stop breaching before it moves back to OK. :param description: The description of the alarm. :param alarm_actions: A list of ARNs to notify when the alarm fires, such as an Amazon SNS topic. """ promql_criteria = { "Query": query, "PendingPeriod": pending_period, "RecoveryPeriod": recovery_period, } kwargs = { "AlarmName": alarm_name, "EvaluationCriteria": {"PromQLCriteria": promql_criteria}, "EvaluationInterval": evaluation_interval, } if description is not None: kwargs["AlarmDescription"] = description if alarm_actions is not None: kwargs["AlarmActions"] = alarm_actions try: self.cloudwatch_client.put_metric_alarm(**kwargs) logger.info("Created PromQL alarm %s for query %s.", alarm_name, query) except ClientError: logger.exception("Couldn't create PromQL alarm %s.", alarm_name) raise

단일 CloudWatch 지표를 평가하는 경보를 생성합니다.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def create_metric_alarm( self, metric_namespace, metric_name, alarm_name, stat_type, period, eval_periods, threshold, comparison_op, ): """ Creates an alarm that watches a metric. :param metric_namespace: The namespace of the metric. :param metric_name: The name of the metric. :param alarm_name: The name of the alarm. :param stat_type: The type of statistic the alarm watches. :param period: The period in which metric data are grouped to calculate statistics. :param eval_periods: The number of periods that the metric must be over the alarm threshold before the alarm is set into an alarmed state. :param threshold: The threshold value to compare against the metric statistic. :param comparison_op: The comparison operation used to compare the threshold against the metric. :return: The newly created alarm. """ try: metric = self.cloudwatch_resource.Metric(metric_namespace, metric_name) alarm = metric.put_alarm( AlarmName=alarm_name, Statistic=stat_type, Period=period, EvaluationPeriods=eval_periods, Threshold=threshold, ComparisonOperator=comparison_op, ) logger.info( "Added alarm %s to track metric %s.%s.", alarm_name, metric_namespace, metric_name, ) except ClientError: logger.exception( "Couldn't add alarm %s to metric %s.%s", alarm_name, metric_namespace, metric_name, ) raise else: return alarm
  • API 세부 정보는 AWS SDK for Python (Boto3) API 참조의 PutMetricAlarm을 참조하세요.

다음 코드 예시는 PutMetricData의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def put_metric_data(self, namespace, name, value, unit): """ Sends a single data value to CloudWatch for a metric. This metric is given a timestamp of the current UTC time. :param namespace: The namespace of the metric. :param name: The name of the metric. :param value: The value of the metric. :param unit: The unit of the metric. """ try: metric = self.cloudwatch_resource.Metric(namespace, name) metric.put_data( Namespace=namespace, MetricData=[{"MetricName": name, "Value": value, "Unit": unit}], ) logger.info("Put data for metric %s.%s", namespace, name) except ClientError: logger.exception("Couldn't put data for metric %s.%s", namespace, name) raise

CloudWatch 지표에 데이터 집합을 추가합니다.

class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def put_metric_data_set(self, namespace, name, timestamp, unit, data_set): """ Sends a set of data to CloudWatch for a metric. All of the data in the set have the same timestamp and unit. :param namespace: The namespace of the metric. :param name: The name of the metric. :param timestamp: The UTC timestamp for the metric. :param unit: The unit of the metric. :param data_set: The set of data to send. This set is a dictionary that contains a list of values and a list of corresponding counts. The value and count lists must be the same length. """ try: metric = self.cloudwatch_resource.Metric(namespace, name) metric.put_data( Namespace=namespace, MetricData=[ { "MetricName": name, "Timestamp": timestamp, "Values": data_set["values"], "Counts": data_set["counts"], "Unit": unit, } ], ) logger.info("Put data set for metric %s.%s.", namespace, name) except ClientError: logger.exception("Couldn't put data set for metric %s.%s.", namespace, name) raise
  • API 세부 정보는 AWS SDK for Python (Boto3) API 참조의 PutMetricData를 참조하세요.

다음 코드 예시는 StartOTelEnrichment의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def start_otel_enrichment(self): """ Turns on OTel enrichment for the account. Once enrichment is running, CloudWatch vended metrics that carry a resource identifier dimension, such as the 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. """ try: # Boto3 splits the OTel prefix when it converts the StartOTelEnrichment # operation name to snake case, so the method is start_o_tel_enrichment. self.cloudwatch_client.start_o_tel_enrichment() logger.info("Started OTel enrichment for this account.") except ClientError: logger.exception("Couldn't start OTel enrichment.") raise
  • API 세부 정보는 SDK for Python (Boto3) API 참조의 StartOTelEnrichment를 참조하세요. AWS

다음 코드 예시는 StopOTelEnrichment의 사용 방법을 보여줍니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def stop_otel_enrichment(self): """ Turns 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. """ try: self.cloudwatch_client.stop_o_tel_enrichment() logger.info("Stopped OTel enrichment for this account.") except ClientError: logger.exception("Couldn't stop OTel enrichment.") raise
  • API 세부 정보는 SDK for Python (Boto3) API 참조의 StopOTelEnrichment를 참조하세요. AWS

시나리오

다음 코드 예제에서는 다음과 같은 작업을 수행하는 방법을 보여줍니다.

  • 단일 CloudWatch 지표를 감시하는 경보를 생성합니다.

  • 를 사용하여 지표에 데이터를 넣고 경보를 PutMetricData 트리거합니다.

  • 경보에서 데이터를 가져옵니다.

  • 경보를 삭제합니다.

SDK for Python (Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

CloudWatch 작업을 래핑하는 클래스를 만듭니다.

from datetime import datetime, timedelta, timezone import logging from pprint import pprint import random import time import boto3 from botocore.exceptions import ClientError logger = logging.getLogger(__name__) class CloudWatchWrapper: """Encapsulates Amazon CloudWatch functions.""" def __init__(self, cloudwatch_resource): """ :param cloudwatch_resource: A Boto3 CloudWatch resource. """ self.cloudwatch_resource = cloudwatch_resource def put_metric_data_set(self, namespace, name, timestamp, unit, data_set): """ Sends a set of data to CloudWatch for a metric. All of the data in the set have the same timestamp and unit. :param namespace: The namespace of the metric. :param name: The name of the metric. :param timestamp: The UTC timestamp for the metric. :param unit: The unit of the metric. :param data_set: The set of data to send. This set is a dictionary that contains a list of values and a list of corresponding counts. The value and count lists must be the same length. """ try: metric = self.cloudwatch_resource.Metric(namespace, name) metric.put_data( Namespace=namespace, MetricData=[ { "MetricName": name, "Timestamp": timestamp, "Values": data_set["values"], "Counts": data_set["counts"], "Unit": unit, } ], ) logger.info("Put data set for metric %s.%s.", namespace, name) except ClientError: logger.exception("Couldn't put data set for metric %s.%s.", namespace, name) raise def create_metric_alarm( self, metric_namespace, metric_name, alarm_name, stat_type, period, eval_periods, threshold, comparison_op, ): """ Creates an alarm that watches a metric. :param metric_namespace: The namespace of the metric. :param metric_name: The name of the metric. :param alarm_name: The name of the alarm. :param stat_type: The type of statistic the alarm watches. :param period: The period in which metric data are grouped to calculate statistics. :param eval_periods: The number of periods that the metric must be over the alarm threshold before the alarm is set into an alarmed state. :param threshold: The threshold value to compare against the metric statistic. :param comparison_op: The comparison operation used to compare the threshold against the metric. :return: The newly created alarm. """ try: metric = self.cloudwatch_resource.Metric(metric_namespace, metric_name) alarm = metric.put_alarm( AlarmName=alarm_name, Statistic=stat_type, Period=period, EvaluationPeriods=eval_periods, Threshold=threshold, ComparisonOperator=comparison_op, ) logger.info( "Added alarm %s to track metric %s.%s.", alarm_name, metric_namespace, metric_name, ) except ClientError: logger.exception( "Couldn't add alarm %s to metric %s.%s", alarm_name, metric_namespace, metric_name, ) raise else: return alarm def put_metric_data(self, namespace, name, value, unit): """ Sends a single data value to CloudWatch for a metric. This metric is given a timestamp of the current UTC time. :param namespace: The namespace of the metric. :param name: The name of the metric. :param value: The value of the metric. :param unit: The unit of the metric. """ try: metric = self.cloudwatch_resource.Metric(namespace, name) metric.put_data( Namespace=namespace, MetricData=[{"MetricName": name, "Value": value, "Unit": unit}], ) logger.info("Put data for metric %s.%s", namespace, name) except ClientError: logger.exception("Couldn't put data for metric %s.%s", namespace, name) raise def get_metric_statistics(self, namespace, name, start, end, period, stat_types): """ Gets statistics for a metric within a specified time span. Metrics are grouped into the specified period. :param namespace: The namespace of the metric. :param name: The name of the metric. :param start: The UTC start time of the time span to retrieve. :param end: The UTC end time of the time span to retrieve. :param period: The period, in seconds, in which to group metrics. The period must match the granularity of the metric, which depends on the metric's age. For example, metrics that are older than three hours have a one-minute granularity, so the period must be at least 60 and must be a multiple of 60. :param stat_types: The type of statistics to retrieve, such as average value or maximum value. :return: The retrieved statistics for the metric. """ try: metric = self.cloudwatch_resource.Metric(namespace, name) stats = metric.get_statistics( StartTime=start, EndTime=end, Period=period, Statistics=stat_types ) logger.info( "Got %s statistics for %s.", len(stats["Datapoints"]), stats["Label"] ) except ClientError: logger.exception("Couldn't get statistics for %s.%s.", namespace, name) raise else: return stats def get_metric_alarms(self, metric_namespace, metric_name): """ Gets the alarms that are currently watching the specified metric. :param metric_namespace: The namespace of the metric. :param metric_name: The name of the metric. :returns: An iterator that yields the alarms. """ metric = self.cloudwatch_resource.Metric(metric_namespace, metric_name) alarm_iter = metric.alarms.all() logger.info("Got alarms for metric %s.%s.", metric_namespace, metric_name) return alarm_iter def delete_metric_alarms(self, metric_namespace, metric_name): """ Deletes all of the alarms that are currently watching the specified metric. :param metric_namespace: The namespace of the metric. :param metric_name: The name of the metric. """ try: metric = self.cloudwatch_resource.Metric(metric_namespace, metric_name) metric.alarms.delete() logger.info( "Deleted alarms for metric %s.%s.", metric_namespace, metric_name ) except ClientError: logger.exception( "Couldn't delete alarms for metric %s.%s.", metric_namespace, metric_name, ) raise

래퍼 클래스를 사용하여 데이터를 지표에 넣고, 지표를 감시하는 경보를 트리거하고, 경보에서 데이터를 가져옵니다.

def usage_demo(): print("-" * 88) print("Welcome to the Amazon CloudWatch metrics and alarms demo!") print("-" * 88) logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") cw_wrapper = CloudWatchWrapper(boto3.resource("cloudwatch")) minutes = 20 metric_namespace = "doc-example-metric" metric_name = "page_views" start = datetime.now(timezone.utc) - timedelta(minutes=minutes) print( f"Putting data into metric {metric_namespace}.{metric_name} spanning the " f"last {minutes} minutes." ) for offset in range(0, minutes): stamp = start + timedelta(minutes=offset) cw_wrapper.put_metric_data_set( metric_namespace, metric_name, stamp, "Count", { "values": [ random.randint(bound, bound * 2) for bound in range(offset + 1, offset + 11) ], "counts": [random.randint(1, offset + 1) for _ in range(10)], }, ) alarm_name = "high_page_views" period = 60 eval_periods = 2 print(f"Creating alarm {alarm_name} for metric {metric_name}.") alarm = cw_wrapper.create_metric_alarm( metric_namespace, metric_name, alarm_name, "Maximum", period, eval_periods, 100, "GreaterThanThreshold", ) print(f"Alarm ARN is {alarm.alarm_arn}.") print(f"Current alarm state is: {alarm.state_value}.") print( f"Sending data to trigger the alarm. This requires data over the threshold " f"for {eval_periods} periods of {period} seconds each." ) while alarm.state_value == "INSUFFICIENT_DATA": print("Sending data for the metric.") cw_wrapper.put_metric_data( metric_namespace, metric_name, random.randint(100, 200), "Count" ) alarm.load() print(f"Current alarm state is: {alarm.state_value}.") if alarm.state_value == "INSUFFICIENT_DATA": print(f"Waiting for {period} seconds...") time.sleep(period) else: print("Wait for a minute for eventual consistency of metric data.") time.sleep(period) if alarm.state_value == "OK": alarm.load() print(f"Current alarm state is: {alarm.state_value}.") print( f"Getting data for metric {metric_namespace}.{metric_name} during timespan " f"of {start} to {datetime.now(timezone.utc)} (times are UTC)." ) stats = cw_wrapper.get_metric_statistics( metric_namespace, metric_name, start, datetime.now(timezone.utc), 60, ["Average", "Minimum", "Maximum"], ) print( f"Got {len(stats['Datapoints'])} data points for metric " f"{metric_namespace}.{metric_name}." ) pprint(sorted(stats["Datapoints"], key=lambda x: x["Timestamp"])) print(f"Getting alarms for metric {metric_name}.") alarms = cw_wrapper.get_metric_alarms(metric_namespace, metric_name) for alarm in alarms: print(f"Alarm {alarm.name} is currently in state {alarm.state_value}.") print(f"Deleting alarms for metric {metric_name}.") cw_wrapper.delete_metric_alarms(metric_namespace, metric_name) print("Thanks for watching!") print("-" * 88)

다음 코드 예제에서는 다음과 같은 작업을 수행하는 방법을 보여줍니다.

  • OpenTelemetry Collector를 사용하여 OTLP 지표를 CloudWatch 지표 엔드포인트로 전송합니다.

  • CloudWatch가 이러한 지표를 리소스와 연관시키도록 OpenTelemetry 보강을 시작합니다.

  • 쿼리가 반환하는 모든 시리즈에서 PromQL 쿼리를 평가하는 경보를 생성합니다.

  • 경보를 ALARM 상태로 설정하는 기여자라는 개별 시리즈를 검사합니다.

  • 유지 관리 기간에 대한 경보를 음소거한 다음 정리합니다.

SDK for Python(Boto3)
참고

GitHub에 더 많은 내용이 있습니다. AWS 코드 예제 리포지토리에서 전체 예를 찾고 설정 및 실행하는 방법을 배워보세요.

CloudWatch OpenTelemetry 작업을 래핑하는 클래스를 생성합니다.

import logging import time import boto3 from botocore.exceptions import ClientError logger = logging.getLogger(__name__) class CloudWatchOTelWrapper: """Encapsulates the OpenTelemetry-oriented Amazon CloudWatch operations.""" def __init__(self, cloudwatch_client): """ :param cloudwatch_client: A Boto3 CloudWatch client. The OpenTelemetry operations are only available on the client interface, not on the higher-level ``boto3.resource("cloudwatch")`` interface. """ self.cloudwatch_client = cloudwatch_client @classmethod def from_client(cls): """ Creates a wrapper backed by a default CloudWatch client. :return: A CloudWatchOTelWrapper. """ return cls(boto3.client("cloudwatch")) def start_otel_enrichment(self): """ Turns on OTel enrichment for the account. Once enrichment is running, CloudWatch vended metrics that carry a resource identifier dimension, such as the 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. """ try: # Boto3 splits the OTel prefix when it converts the StartOTelEnrichment # operation name to snake case, so the method is start_o_tel_enrichment. self.cloudwatch_client.start_o_tel_enrichment() logger.info("Started OTel enrichment for this account.") except ClientError: logger.exception("Couldn't start OTel enrichment.") raise def get_otel_enrichment_status(self): """ Gets the current OTel enrichment status for the account. :return: The status, either 'Running' or 'Stopped'. """ try: response = self.cloudwatch_client.get_o_tel_enrichment() except ClientError: logger.exception("Couldn't get the OTel enrichment status.") raise else: status = response["Status"] logger.info("OTel enrichment status is %s.", status) return status def create_promql_alarm( self, alarm_name, query, evaluation_interval, pending_period=300, recovery_period=120, description=None, alarm_actions=None, ): """ Creates 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. The PromQL evaluation parameters live in the EvaluationCriteria union, which is mutually exclusive with the classic MetricName and Metrics parameters. When you use EvaluationCriteria you must also set EvaluationInterval, and you must not set Period, Statistic, Threshold, ComparisonOperator, EvaluationPeriods, DatapointsToAlarm, or TreatMissingData. :param alarm_name: The name of the alarm. Must be unique within the Region. :param 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 parameter. :param evaluation_interval: How often, in seconds, to run the query. Valid values are 10, 20, 30, and any multiple of 60, up to 3600. :param pending_period: How long, in seconds, a contributor must breach continuously before it moves to ALARM. :param recovery_period: How long, in seconds, a contributor must stop breaching before it moves back to OK. :param description: The description of the alarm. :param alarm_actions: A list of ARNs to notify when the alarm fires, such as an Amazon SNS topic. """ promql_criteria = { "Query": query, "PendingPeriod": pending_period, "RecoveryPeriod": recovery_period, } kwargs = { "AlarmName": alarm_name, "EvaluationCriteria": {"PromQLCriteria": promql_criteria}, "EvaluationInterval": evaluation_interval, } if description is not None: kwargs["AlarmDescription"] = description if alarm_actions is not None: kwargs["AlarmActions"] = alarm_actions try: self.cloudwatch_client.put_metric_alarm(**kwargs) logger.info("Created PromQL alarm %s for query %s.", alarm_name, query) except ClientError: logger.exception("Couldn't create PromQL alarm %s.", alarm_name) raise def describe_alarm_contributors(self, alarm_name): """ Gets 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. :param alarm_name: The name of the PromQL alarm. :return: The list of contributors. Each contributor has a ContributorId, a ContributorAttributes map of the labels that identify the series, a StateReason, and the time it last changed state. """ contributors = [] try: next_token = None while True: kwargs = {"AlarmName": alarm_name} if next_token is not None: kwargs["NextToken"] = next_token response = self.cloudwatch_client.describe_alarm_contributors(**kwargs) contributors.extend(response["AlarmContributors"]) next_token = response.get("NextToken") if not next_token: break except ClientError: logger.exception("Couldn't get contributors for alarm %s.", alarm_name) raise else: logger.info( "Got %s contributors for alarm %s.", len(contributors), alarm_name ) return contributors def put_alarm_mute_rule( self, name, expression, duration, alarm_names=None, timezone=None, description=None, ): """ Creates or updates 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 hoping someone remembers to turn them back on. :param name: The name of the mute rule. :param 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 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 alarm_names: The names of up to 100 alarms to mute. If omitted, the rule applies to all alarms in the account. :param timezone: The time zone the expression is evaluated in, such as 'America/Los_Angeles'. :param description: The description of the mute rule. """ schedule = {"Expression": expression, "Duration": duration} if timezone is not None: schedule["Timezone"] = timezone kwargs = {"Name": name, "Rule": {"Schedule": schedule}} if alarm_names is not None: kwargs["MuteTargets"] = {"AlarmNames": alarm_names} if description is not None: kwargs["Description"] = description try: self.cloudwatch_client.put_alarm_mute_rule(**kwargs) logger.info("Put alarm mute rule %s.", name) except ClientError: logger.exception("Couldn't put alarm mute rule %s.", name) raise def get_alarm_mute_rule(self, name): """ Gets the full configuration of an alarm mute rule, including its schedule, the alarms it targets, and whether it is currently SCHEDULED, ACTIVE, or EXPIRED. :param name: The name of the mute rule. :return: The mute rule. """ try: response = self.cloudwatch_client.get_alarm_mute_rule( AlarmMuteRuleName=name ) except ClientError: logger.exception("Couldn't get alarm mute rule %s.", name) raise else: logger.info("Got alarm mute rule %s.", name) return response def list_alarm_mute_rules(self, alarm_name=None, statuses=None): """ Lists alarm mute rules in the account. :param alarm_name: When specified, only rules that target this alarm are returned. :param statuses: When specified, only rules in these statuses are returned. Valid values are 'SCHEDULED', 'ACTIVE', and 'EXPIRED'. :return: The list of mute rule summaries. """ summaries = [] try: next_token = None while True: kwargs = {} if alarm_name is not None: kwargs["AlarmName"] = alarm_name if statuses is not None: kwargs["Statuses"] = statuses if next_token is not None: kwargs["NextToken"] = next_token response = self.cloudwatch_client.list_alarm_mute_rules(**kwargs) summaries.extend(response.get("AlarmMuteRuleSummaries", [])) next_token = response.get("NextToken") if not next_token: break except ClientError: logger.exception("Couldn't list alarm mute rules.") raise else: logger.info("Got %s alarm mute rules.", len(summaries)) return summaries def delete_alarm_mute_rule(self, name): """ Deletes an alarm mute rule. :param name: The name of the mute rule. """ try: self.cloudwatch_client.delete_alarm_mute_rule(AlarmMuteRuleName=name) logger.info("Deleted alarm mute rule %s.", name) except ClientError: logger.exception("Couldn't delete alarm mute rule %s.", name) raise def stop_otel_enrichment(self): """ Turns 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. """ try: self.cloudwatch_client.stop_o_tel_enrichment() logger.info("Stopped OTel enrichment for this account.") except ClientError: logger.exception("Couldn't stop OTel enrichment.") raise def delete_alarms(self, alarm_names): """ Deletes the specified alarms. :param alarm_names: The names of the alarms to delete. """ try: self.cloudwatch_client.delete_alarms(AlarmNames=alarm_names) logger.info("Deleted alarms %s.", ", ".join(alarm_names)) except ClientError: logger.exception("Couldn't delete alarms %s.", ", ".join(alarm_names)) raise

래퍼 클래스를 사용하여 PromQL 쿼리로 OpenTelemetry 지표를 경보하고, 경보 기여자를 검사하고, 음소거합니다.

def usage_demo(): """ Walks through the OpenTelemetry metrics workflow in CloudWatch: turn on enrichment, alarm on a PromQL query, inspect the contributors that matched, mute the alarm for a maintenance window, then clean up. This scenario assumes OpenTelemetry metrics are already flowing into the account, either from an OpenTelemetry collector, the CloudWatch agent, or the ADOT SDK. """ print("-" * 88) print("Welcome to the Amazon CloudWatch OpenTelemetry metrics demo!") print("-" * 88) logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") cw = CloudWatchOTelWrapper.from_client() alarm_name = "doc-example-promql-high-cpu" mute_rule_name = "doc-example-maintenance-window" print("Checking whether OTel enrichment is on for this account.") status = cw.get_otel_enrichment_status() started_enrichment_here = False if status == "Stopped": print("Enrichment is stopped. Starting it so vended metrics accept PromQL.") cw.start_otel_enrichment() started_enrichment_here = True else: print("Enrichment is already running. Leaving it alone.") query = 'avg by (host_name) (cpu_utilization_percent{service_name="checkout"}) > 80' print(f"\nCreating a PromQL alarm on: {query}") cw.create_promql_alarm( alarm_name, query, evaluation_interval=30, pending_period=300, recovery_period=120, description="Average CPU over 80% per host for the checkout service.", ) print( "The alarm evaluates every 30 seconds. A host moves to ALARM after breaching " "for 300 seconds straight, and back to OK after 120 seconds clean." ) print("\nWaiting a moment for the first evaluation, then listing contributors.") time.sleep(30) contributors = cw.describe_alarm_contributors(alarm_name) if not contributors: print( "No contributors yet. The query matched no series, which usually means " "no OTel metrics with these labels have arrived. Send some OTel metrics " "through the OTLP endpoint and run this again." ) for contributor in contributors: labels = ", ".join( f"{key}={value}" for key, value in sorted(contributor["ContributorAttributes"].items()) ) print(f" {contributor['ContributorId']}: {labels}") print(f" reason: {contributor['StateReason']}") print(f"\nMuting {alarm_name} for a weekly two-hour maintenance window.") cw.put_alarm_mute_rule( mute_rule_name, expression="cron(0 2 * * SUN)", duration="PT2H", alarm_names=[alarm_name], timezone="America/Los_Angeles", description="Suppress checkout CPU pages during Sunday patching.", ) rule = cw.get_alarm_mute_rule(mute_rule_name) print(f"Mute rule status is {rule.get('Status')}.") print( "While the window is active the alarm keeps evaluating and still changes " "state; only its actions are suppressed." ) print(f"\nMute rules targeting {alarm_name}:") for summary in cw.list_alarm_mute_rules(alarm_name=alarm_name): print(f" {summary.get('AlarmMuteRuleArn')} ({summary.get('Status')})") print("\nCleaning up.") cw.delete_alarm_mute_rule(mute_rule_name) cw.delete_alarms([alarm_name]) if started_enrichment_here: print("Stopping OTel enrichment, since this demo started it.") cw.stop_otel_enrichment() print("\nThanks for watching!") print("-" * 88)

이 예제에서 경보가 발생하는 OTLP 지표를 CloudWatch 지표 엔드포인트로 보내도록 OpenTelemetry Collector를 구성합니다. OTLP를 통한 지표 수집은 AWSSDK 작업이 아니므로이 예제의 절반은 SDK 코드가 아닌 수집기 구성입니다.

# Purpose # # An OpenTelemetry Collector configuration that sends OTLP metrics to the Amazon # CloudWatch metrics endpoint. Once metrics land in CloudWatch they are queryable with # PromQL in Query Studio, and you can alarm on them with the PromQL alarm operations # shown in cloudwatch_otel.py. # # Metric ingestion over OTLP is deliberately NOT an AWS SDK operation. There is no # boto3 call that sends OTLP metrics. You send them with one of the following, in # rough order of how integrated the CloudWatch experience is: # # 1. The CloudWatch agent (recommended). An AWS-managed OpenTelemetry Collector with # CloudWatch components pre-built. Adds entity correlation, runtime metrics, and # Container Insights support. # 2. An upstream OpenTelemetry Collector. What this file configures. # 3. A custom OpenTelemetry Collector build. # 4. The AWS Distro for OpenTelemetry (ADOT) SDK, with no collector at all. # # Prerequisites # # * An OpenTelemetry Collector release that includes the sigv4authextension. The # contrib distribution does. See # https://github.com/open-telemetry/opentelemetry-collector-releases/releases # * AWS credentials the collector can resolve. On Amazon EC2, attach the # CloudWatchAgentServerPolicy managed policy to the instance role. On Amazon EKS, # bind that policy to the collector's service account with IRSA. On premises, run # `aws configure` for an IAM user that has the same policy. # # Run the collector with: # # otelcol-contrib --config otlp_collector_config.yaml # # Then point your instrumented application at http://localhost:4318. # # For more information, see # https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-OTLPEndpoint.html receivers: # The CloudWatch OTLP endpoints are HTTP 1.1 only and do not support gRPC. You can # still accept gRPC from your applications here and let the collector translate, but # this example keeps the receiver HTTP-only to mirror what is sent upstream. otlp: protocols: http: endpoint: "0.0.0.0:4318" processors: # Batch to stay inside the endpoint's per-request limits: 1 MB uncompressed and # 1,000 datapoints, counted as the sum across ResourceMetrics, ScopeMetrics, and # Metrics. A batch of 200 leaves comfortable headroom. batch: send_batch_size: 200 timeout: 10s exporters: otlphttp: tls: insecure: false # Pattern: https://monitoring.{region}.amazonaws.com/v1/metrics endpoint: "https://monitoring.us-east-1.amazonaws.com/v1/metrics" # Only gzip and none are supported. compression: gzip auth: authenticator: sigv4auth extensions: # SigV4 is the recommended authentication method, and the only one supported for # traces. For hosts outside AWS you can instead use the bearertokenauth extension # against the metrics or logs endpoints; see # https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-OTLP-MetricsBearerTokenAuth.html sigv4auth: # The metrics endpoint signs as "monitoring". The logs endpoint signs as "logs" # and the traces endpoint as "xray". service: "monitoring" region: "us-east-1" service: extensions: [sigv4auth] pipelines: metrics: receivers: [otlp] processors: [batch] exporters: [otlphttp] # Endpoint limits worth designing around, all per account and Region: # # Maximum TPS 500 # New series creation rate 1,000,000 per 10-minute window # Maximum request size 1 MB uncompressed # Maximum datapoint count 1,000 per request # Maximum metadata size 40 KB of labels and values per series per datapoint # Maximum label count 150 across Resource, Scope, and Datapoint attributes # Timestamp window at most 10 minutes in the future, 14 days in the past # # Exceeding the TPS or new-series limits returns 429. The size, count, metadata, # label, and timestamp limits return 400, and a request whose metrics are only # partially invalid returns 200 with the valid metrics ingested.