使用 API 管理提醒政策

本页面介绍了如何使用 Cloud Monitoring API 以编程方式创建和管理提醒政策。还说明了如何使用 Cloud SDK 命令行界面来管理提醒政策。

许多此类任务都可以通过使用 Cloud Monitoring 控制台来执行。如需了解如何使用 Cloud Monitoring 控制台创建和管理提醒政策,请参阅使用提醒政策

准备工作

在针对该 API 编写代码之前,您应该满足以下条件:

  • 具备一个工作区,它监控要对其创建提醒政策的项目。
  • 熟悉提醒政策的一般概念和所用术语;详情可参阅提醒功能简介
  • 确保该 API 已启用;详情可参阅启用 API
  • 安装要使用的语言的客户端库;详情可参阅客户端库。目前,此 API 仅支持针对 C#、Go、Java、Node.js 和 Python 的提醒。

  • 安装 Cloud SDK您可以通过 Cloud SDK 访问 gcloud 命令行界面,并从该界面执行这些任务。如果您使用的是 Cloud Shell,则无需安装 Cloud SDK。

    此处还提供了使用 gcloud 界面的示例。请注意,gcloud 示例都假设当前项目已被设置为目标 (gcloud config set project [PROJECT_ID]),因此调用中省略了显式 --project 标志。示例中当前项目的 ID 为 a-gcp-project

关于提醒政策

提醒政策由 AlertPolicy 对象表示,该对象描述一组指示系统可能存在非正常状况的条件。提醒政策会引用通知渠道,您可通过后者指定在提醒政策被触发时获取通知的方式。

每个提醒政策都属于一个单独的工作区,每个工作区最多可以包含 500 个政策。工作区由其 ID 标识,它在参考资料中被称称作“项目 ID”。在这些示例中,工作区的 ID 为 a-gcp-project

AlertPolicy 资源支持 5 种操作:

  • 创建新政策
  • 删除现有政策
  • 检索特定政策
  • 检索所有政策
  • 修改现有政策

提醒政策可用 JSON 或 YAML 格式,它允许您以文件的形式记录政策,并使用文件来备份和恢复政策。通过 Cloud SDK,您可以使用上述两种格式的文件中的任意一种来创建政策。通过 REST API,您可以从 JSON 文件创建政策。 请参阅示例政策,查看 JSON 格式的提醒政策的精选示例。

以下示例使用 gcloud 界面和 API 来演示说明这些基本使用场景。此处的 API 示例摘录自一个示例程序,该程序通过 API 实现用于提醒政策的备份和恢复系统。示例:备份和恢复中显示了更完整的示例。

创建政策

要在项目中创建提醒政策,请使用 alertPolicies.create 方法。

您可以利用 JSON 或 YAML 文件创建政策。 gcloud 命令行界面接受这些文件作为参数,而且您可以通过编程方式读取 JSON 文件,将其转换为 AlertPolicy 对象,然后使用 alertPolicies.create 方法根据这些对象创建政策。

以下示例演示说明了创建提醒政策的过程。

gcloud 命令

要在项目中创建提醒政策,请使用 gcloud alpha monitoring policies create 命令。以下示例利用 rising-cpu-usage.json 文件在 a-gcp-project 中创建了提醒政策:

gcloud alpha monitoring policies create --policy-from-file="rising-cpu-usage.json"
    

如果成功,则该命令将返回新政策的名称,例如:

Created alert policy [projects/a-gcp-project/alertPolicies/12669073143329903307].
    

rising-cpu-usage.json 文件包含了显示名称为“High CPU rate of change”的政策的 JSON 代码。变化率政策中说明了这项政策。

如需了解详情,请查看 gcloud alpha monitoring policies create 参考。

C#

static void RestorePolicies(string projectId, string filePath)
    {
        var policyClient = AlertPolicyServiceClient.Create();
        var channelClient = NotificationChannelServiceClient.Create();
        List<Exception> exceptions = new List<Exception>();
        var backup = JsonConvert.DeserializeObject<BackupRecord>(
            File.ReadAllText(filePath), new ProtoMessageConverter());
        var projectName = new ProjectName(projectId);
        bool isSameProject = projectId == backup.ProjectId;
        // When a channel is recreated, rather than updated, it will get
        // a new name.  We have to update the AlertPolicy with the new
        // name.  Track the names in this map.
        var channelNameMap = new Dictionary<string, string>();
        foreach (NotificationChannel channel in backup.Channels)
        {
        }
        foreach (AlertPolicy policy in backup.Policies)
        {
            string policyName = policy.Name;
            // These two fields cannot be set directly, so clear them.
            policy.CreationRecord = null;
            policy.MutationRecord = null;
            // Update channel names if the channel was recreated with
            // another name.
            for (int i = 0; i < policy.NotificationChannels.Count; ++i)
            {
                if (channelNameMap.ContainsKey(policy.NotificationChannels[i]))
                {
                    policy.NotificationChannels[i] =
                        channelNameMap[policy.NotificationChannels[i]];
                }
            }
            try
            {
                Console.WriteLine("Updating policy.\n{0}",
                    policy.DisplayName);
                bool updated = false;
                if (isSameProject)
                    try
                    {
                        policyClient.UpdateAlertPolicy(null, policy);
                        updated = true;
                    }
                    catch (Grpc.Core.RpcException e)
                    when (e.Status.StatusCode == StatusCode.NotFound)
                    { }
                if (!updated)
                {
                    // The policy no longer exists.  Recreate it.
                    policy.Name = null;
                    foreach (var condition in policy.Conditions)
                    {
                        condition.Name = null;
                    }
                    policyClient.CreateAlertPolicy(projectName, policy);
                }
                Console.WriteLine("Restored {0}.", policyName);
            }
            catch (Exception e)
            {
                // If one failed, continue trying to update the others.
                exceptions.Add(e);
            }
        }
        if (exceptions.Count > 0)
        {
            throw new AggregateException(exceptions);
        }
    }

Go


    // restorePolicies updates the project with the alert policies and
    // notification channels in r.
    func restorePolicies(w io.Writer, projectID string, r io.Reader) error {
    	b := backup{}
    	if err := json.NewDecoder(r).Decode(&b); err != nil {
    		return err
    	}
    	sameProject := projectID == b.ProjectID

    	ctx := context.Background()

    	alertClient, err := monitoring.NewAlertPolicyClient(ctx)
    	if err != nil {
    		return err
    	}
    	channelClient, err := monitoring.NewNotificationChannelClient(ctx)
    	if err != nil {
    		return err
    	}

    	// When a channel is recreated, rather than updated, it will get
    	// a new name.  We have to update the AlertPolicy with the new
    	// name.  channelNames keeps track of the new names.
    	channelNames := make(map[string]string)
    	for _, c := range b.Channels {
    		fmt.Fprintf(w, "Updating channel %q\n", c.GetDisplayName())
    		c.VerificationStatus = monitoringpb.NotificationChannel_VERIFICATION_STATUS_UNSPECIFIED
    		updated := false
    		if sameProject {
    			req := &monitoringpb.UpdateNotificationChannelRequest{
    				NotificationChannel: c.NotificationChannel,
    			}
    			_, err := channelClient.UpdateNotificationChannel(ctx, req)
    			if err == nil {
    				updated = true
    			}
    		}
    		if !updated {
    			req := &monitoringpb.CreateNotificationChannelRequest{
    				Name:                "projects/" + projectID,
    				NotificationChannel: c.NotificationChannel,
    			}
    			oldName := c.GetName()
    			c.Name = ""
    			newC, err := channelClient.CreateNotificationChannel(ctx, req)
    			if err != nil {
    				return err
    			}
    			channelNames[oldName] = newC.GetName()
    		}
    	}

    	for _, policy := range b.AlertPolicies {
    		fmt.Fprintf(w, "Updating alert %q\n", policy.GetDisplayName())
    		policy.CreationRecord = nil
    		policy.MutationRecord = nil
    		for i, aChannel := range policy.GetNotificationChannels() {
    			if c, ok := channelNames[aChannel]; ok {
    				policy.NotificationChannels[i] = c
    			}
    		}
    		updated := false
    		if sameProject {
    			req := &monitoringpb.UpdateAlertPolicyRequest{
    				AlertPolicy: policy.AlertPolicy,
    			}
    			_, err := alertClient.UpdateAlertPolicy(ctx, req)
    			if err == nil {
    				updated = true
    			}
    		}
    		if !updated {
    			req := &monitoringpb.CreateAlertPolicyRequest{
    				Name:        "projects/" + projectID,
    				AlertPolicy: policy.AlertPolicy,
    			}
    			if _, err = alertClient.CreateAlertPolicy(ctx, req); err != nil {
    				log.Fatal(err)
    			}
    		}
    	}
    	fmt.Fprintf(w, "Successfully restored alerts.")
    	return nil
    }
    

Java

private static void restoreRevisedPolicies(
        String projectId, boolean isSameProject, List<AlertPolicy> policies) throws IOException {
      try (AlertPolicyServiceClient client = AlertPolicyServiceClient.create()) {
        for (AlertPolicy policy : policies) {
          if (!isSameProject) {
            policy = client.createAlertPolicy(ProjectName.of(projectId), policy);
          } else {
            try {
              client.updateAlertPolicy(null, policy);
            } catch (Exception e) {
              policy =
                  client.createAlertPolicy(
                      ProjectName.of(projectId), policy.toBuilder().clearName().build());
            }
          }
          System.out.println(String.format("Restored %s", policy.getName()));
        }
      }
    }

Node.js

const fs = require('fs');

    // Imports the Google Cloud client library
    const monitoring = require('@google-cloud/monitoring');

    // Creates a client
    const client = new monitoring.AlertPolicyServiceClient();

    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    // const projectId = 'YOUR_PROJECT_ID';

    console.log('Loading policies from ./policies_backup.json');
    const fileContent = fs.readFileSync('./policies_backup.json', 'utf-8');
    const policies = JSON.parse(fileContent);

    for (const index in policies) {
      // Restore each policy one at a time
      let policy = policies[index];
      if (await doesAlertPolicyExist(policy.name)) {
        policy = await client.updateAlertPolicy({
          alertPolicy: policy,
        });
      } else {
        // Clear away output-only fields
        delete policy.name;
        delete policy.creationRecord;
        delete policy.mutationRecord;
        policy.conditions.forEach(condition => delete condition.name);

        policy = await client.createAlertPolicy({
          name: client.projectPath(projectId),
          alertPolicy: policy,
        });
      }

      console.log(`Restored ${policy[0].name}.`);
    }
    async function doesAlertPolicyExist(name) {
      try {
        const [policy] = await client.getAlertPolicy({
          name,
        });
        return policy ? true : false;
      } catch (err) {
        if (err && err.code === 5) {
          // Error code 5 comes from the google.rpc.code.NOT_FOUND protobuf
          return false;
        }
        throw err;
      }
    }

PHP

use Google\Cloud\Monitoring\V3\AlertPolicyServiceClient;
    use Google\Cloud\Monitoring\V3\AlertPolicy;
    use Google\Cloud\Monitoring\V3\ComparisonType;
    use Google\Cloud\Monitoring\V3\AlertPolicy\Condition;
    use Google\Cloud\Monitoring\V3\AlertPolicy\Condition\MetricThreshold;
    use Google\Cloud\Monitoring\V3\AlertPolicy\ConditionCombinerType;
    use Google\Protobuf\Duration;

    /**
     * @param string $projectId Your project ID
     */
    function alert_create_policy($projectId)
    {
        $alertClient = new AlertPolicyServiceClient([
            'projectId' => $projectId,
        ]);
        $projectName = $alertClient->projectName($projectId);

        $policy = new AlertPolicy();
        $policy->setDisplayName('Test Alert Policy');
        $policy->setCombiner(ConditionCombinerType::PBOR);
        /** @see https://cloud.google.com/monitoring/api/resources for a list of resource.type */
        /** @see https://cloud.google.com/monitoring/api/metrics_gcp for a list of metric.type */
        $policy->setConditions([new Condition([
            'display_name' => 'condition-1',
            'condition_threshold' => new MetricThreshold([
                'filter' => 'resource.type = "gce_instance" AND metric.type = "compute.googleapis.com/instance/cpu/utilization"',
                'duration' => new Duration(['seconds' => '60']),
                'comparison' => ComparisonType::COMPARISON_LT,
            ])
        ])]);

        $policy = $alertClient->createAlertPolicy($projectName, $policy);
        printf('Created alert policy %s' . PHP_EOL, $policy->getName());
    }

Python

def restore(project_name, backup_filename):
        print('Loading alert policies and notification channels from {}.'.format(
            backup_filename)
        )
        record = json.load(open(backup_filename, 'rt'))
        is_same_project = project_name == record['project_name']
        # Convert dicts to AlertPolicies.
        policies_json = [json.dumps(policy) for policy in record['policies']]
        policies = [google.protobuf.json_format.Parse(
            policy_json, monitoring_v3.types.alert_pb2.AlertPolicy())
            for policy_json in policies_json]
        # Convert dicts to NotificationChannels
        channels_json = [json.dumps(channel) for channel in record['channels']]
        channels = [google.protobuf.json_format.Parse(
            channel_json, monitoring_v3.types.notification_pb2.
            NotificationChannel()) for channel_json in channels_json]

        # Restore the channels.
        channel_client = monitoring_v3.NotificationChannelServiceClient()
        channel_name_map = {}

        for channel in channels:
            updated = False
            print('Updating channel', channel.display_name)
            # This field is immutable and it is illegal to specify a
            # non-default value (UNVERIFIED or VERIFIED) in the
            # Create() or Update() operations.
            channel.verification_status = monitoring_v3.enums.NotificationChannel.\
                VerificationStatus.VERIFICATION_STATUS_UNSPECIFIED

            if is_same_project:
                try:
                    channel_client.update_notification_channel(channel)
                    updated = True
                except google.api_core.exceptions.NotFound:
                    pass  # The channel was deleted.  Create it below.

            if not updated:
                # The channel no longer exists.  Recreate it.
                old_name = channel.name
                channel.ClearField("name")
                new_channel = channel_client.create_notification_channel(
                    project_name, channel)
                channel_name_map[old_name] = new_channel.name

        # Restore the alerts
        alert_client = monitoring_v3.AlertPolicyServiceClient()

        for policy in policies:
            print('Updating policy', policy.display_name)
            # These two fields cannot be set directly, so clear them.
            policy.ClearField('creation_record')
            policy.ClearField('mutation_record')

            # Update old channel names with new channel names.
            for i, channel in enumerate(policy.notification_channels):
                new_channel = channel_name_map.get(channel)
                if new_channel:
                    policy.notification_channels[i] = new_channel

            updated = False

            if is_same_project:
                try:
                    alert_client.update_alert_policy(policy)
                    updated = True
                except google.api_core.exceptions.NotFound:
                    pass  # The policy was deleted.  Create it below.
                except google.api_core.exceptions.InvalidArgument:
                    # Annoying that API throws InvalidArgument when the policy
                    # does not exist.  Seems like it should throw NotFound.
                    pass  # The policy was deleted.  Create it below.

            if not updated:
                # The policy no longer exists.  Recreate it.
                old_name = policy.name
                policy.ClearField("name")
                for condition in policy.conditions:
                    condition.ClearField("name")
                policy = alert_client.create_alert_policy(project_name, policy)
            print('Updated', policy.name)

创建的 AlertPolicy 对象将具有其他字段。该政策本身有 namecreationRecordmutationRecord 字段。此外,政策中的每个条件也都有一个 name。这些字段不能在外部修改,因此不必在创建政策时设置这些字段。创建政策的 JSON 示例里都不包含这些字段,但如果有人在示例创建政策后检索这些政策,则这些字段将出现。

检索政策

要检索项目中的政策列表,请使用 alertPolicies.list 方法。使用此方法可检索政策,并可以对检索到的政策应用一些操作,例如备份这些政策。此方法还支持使用 filterorderBy 选项对结果进行限制和排序;具体请参阅排序和过滤

如果您要查找特定政策且知道其名称,则可使用 alertPolicies.get 方法仅检索该政策。政策的名称是 name 字段的值,而不是 AlertPolicy 对象中的 displayName。政策名称的格式为 projects/[PROJECT_ID]/alertPolicies/[POLICY_ID],例如:

projects/a-gcp-project/alertPolicies/12669073143329903307
    

gcloud 命令

要列出项目中的所有提醒政策,请使用 gcloud alpha monitoring policies list 命令:

gcloud alpha monitoring policies list
    

如果成功,list 命令将以 YAML 格式列出指定项目中的所有政策。例如,a-gcp-project 项目中显示名为 High CPU rate of change 的政策按下述形式显示在政策列表中:

---
    combiner: OR
    conditions:
    - conditionThreshold:
        aggregations:
        - alignmentPeriod: 900s
          perSeriesAligner: ALIGN_PERCENT_CHANGE
        comparison: COMPARISON_GT
        duration: 180s
        filter: metric.type="compute.googleapis.com/instance/cpu/utilization" AND resource.type="gce_instance"
        thresholdValue: 0.5
        trigger:
          count: 1
      displayName: CPU usage is increasing at a high rate
      name: projects/a-gcp-project/alertPolicies/12669073143329903307/conditions/12669073143329903008
    creationRecord:
      mutateTime: '2018-03-26T18:52:39.363601689Z'
      mutatedBy: [USER@DOMAIN]
    displayName: High CPU rate of change
    enabled: true
    mutationRecord:
      mutateTime: '2018-03-26T18:52:39.363601689Z'
      mutatedBy: [USER@DOMAIN]
    name: projects/a-gcp-project/alertPolicies/12669073143329903307
    ---
    

要列出单个提醒政策,请改用 gcloud alpha monitoring policies describe,并指定政策的名称。例如,此命令仅返回上面所列出的政策:

gcloud alpha monitoring policies describe projects/a-gcp-project/alertPolicies/12669073143329903307
    

如需了解详情,请参阅 gcloud alpha monitoring policies listdescribe 参考。describe 命令对应于 API 中的 alertPolicies.get 方法。

C#

static void ListAlertPolicies(string projectId)
    {
        var client = AlertPolicyServiceClient.Create();
        var response = client.ListAlertPolicies(new ProjectName(projectId));
        foreach (AlertPolicy policy in response)
        {
            Console.WriteLine(policy.Name);
            if (policy.DisplayName != null)
            {
                Console.WriteLine(policy.DisplayName);
            }
            if (policy.Documentation?.Content != null)
            {
                Console.WriteLine(policy.Documentation.Content);
            }
            Console.WriteLine();
        }
    }

Go


    // listAlertPolicies lists the alert policies in the project.
    func listAlertPolicies(w io.Writer, projectID string) error {
    	ctx := context.Background()
    	client, err := monitoring.NewAlertPolicyClient(ctx)
    	if err != nil {
    		return err
    	}

    	req := &monitoringpb.ListAlertPoliciesRequest{
    		Name: "projects/" + projectID,
    		// Filter:  "", // See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering.
    		// OrderBy: "", // See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering.
    	}
    	it := client.ListAlertPolicies(ctx, req)
    	for {
    		resp, err := it.Next()
    		if err == iterator.Done {
    			fmt.Fprintln(w, "Done")
    			break
    		}
    		if err != nil {
    			return err
    		}
    		fmt.Fprintf(w, "  Name: %q\n", resp.GetName())
    		fmt.Fprintf(w, "  Display Name: %q\n", resp.GetDisplayName())
    		fmt.Fprintf(w, "  Documentation Content: %q\n\n", resp.GetDocumentation().GetContent())
    	}
    	return nil
    }
    

Java

private static void listAlertPolicies(String projectId) throws IOException {
      try (AlertPolicyServiceClient client = AlertPolicyServiceClient.create()) {
        ListAlertPoliciesPagedResponse response = client.listAlertPolicies(ProjectName.of(projectId));

        System.out.println("Alert Policies:");
        for (AlertPolicy policy : response.iterateAll()) {
          System.out.println(
              String.format("\nPolicy %s\nalert-id: %s", policy.getDisplayName(), policy.getName()));
          int channels = policy.getNotificationChannelsCount();
          if (channels > 0) {
            System.out.println("notification-channels:");
            for (int i = 0; i < channels; i++) {
              System.out.println("\t" + policy.getNotificationChannels(i));
            }
          }
          if (policy.hasDocumentation() && policy.getDocumentation().getContent() != null) {
            System.out.println(policy.getDocumentation().getContent());
          }
        }
      }
    }

Node.js

// Imports the Google Cloud client library
    const monitoring = require('@google-cloud/monitoring');

    // Creates a client
    const client = new monitoring.AlertPolicyServiceClient();

    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    // const projectId = 'YOUR_PROJECT_ID';

    const listAlertPoliciesRequest = {
      name: client.projectPath(projectId),
    };
    const [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);
    console.log('Policies:');
    policies.forEach(policy => {
      console.log(`  Display name: ${policy.displayName}`);
      if (policy.documentation && policy.documentation.content) {
        console.log(`     Documentation: ${policy.documentation.content}`);
      }
    });
    

PHP

use Google\Cloud\Monitoring\V3\AlertPolicyServiceClient;

    /**
     * Adds a new column to the Albums table in the example database.
     * Example:
     * ```
     * alert_list_policies($projectId);
     * ```
     *
     * @param string $projectId Your project ID
     */
    function alert_list_policies($projectId)
    {
        $alertClient = new AlertPolicyServiceClient([
            'projectId' => $projectId,
        ]);

        $policies = $alertClient->listAlertPolicies(
            $alertClient->projectName($projectId)
        );
        foreach ($policies->iterateAllElements() as $policy) {
            printf('Name: %s (%s)' . PHP_EOL, $policy->getDisplayName(), $policy->getName());
        }
    }

Python

def list_alert_policies(project_name):
        client = monitoring_v3.AlertPolicyServiceClient()
        policies = client.list_alert_policies(project_name)
        print(tabulate.tabulate(
            [(policy.name, policy.display_name) for policy in policies],
            ('name', 'display_name')))

删除政策

要从项目中删除政策,请使用 alertPolicies.delete 方法,并提供要删除的提醒政策的名称。

gcloud 命令

要删除提醒政策,请使用 gcloud alpha monitoring policies delete 并指定要删除的政策的名称。例如,以下命令将删除 High CPU rate of change 政策:

gcloud alpha monitoring policies delete projects/a-gcp-project/alertPolicies/12669073143329903307
    

如需了解详情,请查看 gcloud alpha monitoring policies delete 参考。

修改政策

要修改提醒政策,请使用 REST API 中的 alertPolicies.patch 方法。其他 API 实现和 gcloud 界面称之为 update,而不是 patch

更新操作可以完全替换现有的政策,也可以修改其中一部分字段。要进行更新,您需要使用新的 AlertPolicy 对象并根据情况使用字段掩码

如果指定了一个字段掩码,则字段掩码中列出的所有字段将更新为提供的政策中的值。如果提供的政策中不包括字段掩码中提到的某个字段,则该字段将被清空并设置为默认值。掩码中未列出的任何字段将保留其先前的值。

如果未指定字段掩码,则现有政策将被替换为提供的政策,但沿用原有名称 (projects/[PROJECT_ID]/alertPolicies/[POLICY_ID])。新政策中的任何条件,若有 name 值,且该值中含有 CONDITION_ID,则该条件的名称保留不变。若新政策中的条件不符合上述情形,则将创建新的条件名称和政策名称。

使用 gcloud 命令行更新政策时,指定需要更新的字段是通过使用命令行标志来实现的,而不是使用字段掩码。如需了解详情,请参阅 gcloud alpha monitoring policies update

启用或停用政策

要启用或停用政策,请更改 AlertPolicy 对象中 enabled 字段的布尔值。请注意,在您启用某项政策后,之前在该政策处于停用状态时收集的数据此时仍可能触发提醒。

gcloud 命令

要停用提醒政策,请使用 gcloud alpha monitoring policies update 命令并提供 --no-enabled 标志。以下命令将停用 a-gcp-project 项目中的“High CPU rate of change”提醒政策:

gcloud alpha monitoring policies update projects/a-gcp-project/alertPolicies/12669073143329903307 --no-enabled
    

要启用该政策,请使用同一命令并提供 --enabled 标志。如需了解详情,请查看 gcloud alpha monitoring policies update参考。 update 命令与 REST API 中的 alertPolicies.patch 方法相对应。

C#

static object EnablePolicies(string projectId, string filter, bool enable)
    {
        var client = AlertPolicyServiceClient.Create();
        var request = new ListAlertPoliciesRequest()
        {
            ProjectName = new ProjectName(projectId),
            Filter = filter
        };
        var response = client.ListAlertPolicies(request);
        int result = 0;
        foreach (AlertPolicy policy in response)
        {
            try
            {
                if (policy.Enabled == enable)
                {
                    Console.WriteLine("Policy {0} is already {1}.",
                        policy.Name, enable ? "enabled" : "disabled");
                    continue;
                }
                policy.Enabled = enable;
                var fieldMask = new FieldMask { Paths = { "enabled" } };
                client.UpdateAlertPolicy(fieldMask, policy);
                Console.WriteLine("{0} {1}.", enable ? "Enabled" : "Disabled",
                    policy.Name);
            }
            catch (Grpc.Core.RpcException e)
            when (e.Status.StatusCode == StatusCode.InvalidArgument)
            {
                Console.WriteLine(e.Message);
                result -= 1;
            }
        }
        // Return a negative count of how many enable operations failed.
        return result;
    }

Go


    // enablePolicies enables or disables all alert policies in the project.
    func enablePolicies(w io.Writer, projectID string, enable bool) error {
    	ctx := context.Background()

    	client, err := monitoring.NewAlertPolicyClient(ctx)
    	if err != nil {
    		return err
    	}

    	req := &monitoringpb.ListAlertPoliciesRequest{
    		Name: "projects/" + projectID,
    		// Filter:  "", // See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering.
    		// OrderBy: "", // See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering.
    	}
    	it := client.ListAlertPolicies(ctx, req)
    	for {
    		a, err := it.Next()
    		if err == iterator.Done {
    			break
    		}
    		if err != nil {
    			return err
    		}
    		if a.GetEnabled().GetValue() == enable {
    			fmt.Fprintf(w, "Policy %q already has enabled=%v", a.GetDisplayName(), enable)
    			continue
    		}
    		a.Enabled = &wrappers.BoolValue{Value: enable}
    		req := &monitoringpb.UpdateAlertPolicyRequest{
    			AlertPolicy: a,
    			UpdateMask: &fieldmask.FieldMask{
    				Paths: []string{"enabled"},
    			},
    		}
    		if _, err := client.UpdateAlertPolicy(ctx, req); err != nil {
    			return err
    		}
    	}
    	fmt.Fprintln(w, "Successfully updated alerts.")
    	return nil
    }
    

Java

private static void enablePolicies(String projectId, String filter, boolean enable)
        throws IOException {
      try (AlertPolicyServiceClient client = AlertPolicyServiceClient.create()) {
        ListAlertPoliciesPagedResponse response =
            client.listAlertPolicies(
                ListAlertPoliciesRequest.newBuilder()
                    .setName(ProjectName.of(projectId).toString())
                    .setFilter(filter)
                    .build());

        for (AlertPolicy policy : response.iterateAll()) {
          if (policy.getEnabled().getValue() == enable) {
            System.out.println(
                String.format(
                    "Policy %s is already %b.", policy.getName(), enable ? "enabled" : "disabled"));
            continue;
          }
          AlertPolicy updatedPolicy =
              AlertPolicy.newBuilder()
                  .setName(policy.getName())
                  .setEnabled(BoolValue.newBuilder().setValue(enable))
                  .build();
          AlertPolicy result =
              client.updateAlertPolicy(
                  FieldMask.newBuilder().addPaths("enabled").build(), updatedPolicy);
          System.out.println(
              String.format(
                  "%s %s",
                  result.getDisplayName(), result.getEnabled().getValue() ? "enabled" : "disabled"));
        }
      }
    }

Node.js

// Imports the Google Cloud client library
    const monitoring = require('@google-cloud/monitoring');

    // Creates a client
    const client = new monitoring.AlertPolicyServiceClient();

    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    // const projectId = 'YOUR_PROJECT_ID';
    // const enabled = true;
    // const filter = 'A filter for selecting policies, e.g. description:"cloud"';

    const listAlertPoliciesRequest = {
      name: client.projectPath(projectId),
      // See https://cloud.google.com/monitoring/alerting/docs/sorting-and-filtering
      filter: filter,
    };

    const [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);
    const tasks = await Promise.all(
      policies
        .map(policy => {
          return {
            updateMask: {
              paths: ['enabled'],
            },
            alertPolicy: {
              name: policy.name,
              enabled: {
                value: enabled,
              },
            },
          };
        })
        .map(updateAlertPolicyRequest =>
          client.updateAlertPolicy(updateAlertPolicyRequest)
        )
    );
    tasks.forEach(response => {
      const alertPolicy = response[0];
      console.log(`${enabled ? 'Enabled' : 'Disabled'} ${alertPolicy.name}.`);
    });

PHP

use Google\Cloud\Monitoring\V3\AlertPolicyServiceClient;
    use Google\Protobuf\FieldMask;

    /**
     * Enable or disable alert policies in a project.
     *
     * @param string $projectId Your project ID
     * @param bool $enable Enable or disable the policies.
     * @param string $filter Only enable/disable alert policies that match a filter.
     *        See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering
     */
    function alert_enable_policies($projectId, $enable = true, $filter = null)
    {
        $alertClient = new AlertPolicyServiceClient([
            'projectId' => $projectId,
        ]);
        $projectName = $alertClient->projectName($projectId);

        $policies = $alertClient->listAlertPolicies($projectName, [
            'filter' => $filter
        ]);
        foreach ($policies->iterateAllElements() as $policy) {
            $isEnabled = $policy->getEnabled()->getValue();
            if ($enable == $isEnabled) {
                printf('Policy %s is already %s' . PHP_EOL,
                    $policy->getName(),
                    $isEnabled ? 'enabled' : 'disabled'
                );
            } else {
                $policy->getEnabled()->setValue((bool) $enable);
                $mask = new FieldMask();
                $mask->setPaths(['enabled']);
                $alertClient->updateAlertPolicy($policy, [
                    'updateMask' => $mask
                ]);
                printf('%s %s' . PHP_EOL,
                    $enable ? 'Enabled' : 'Disabled',
                    $policy->getName()
                );
            }
        }
    }

Python

def enable_alert_policies(project_name, enable, filter_=None):
        """Enable or disable alert policies in a project.

        Arguments:
            project_name (str)
            enable (bool): Enable or disable the policies.
            filter_ (str, optional): Only enable/disable alert policies that match
                this filter_.  See
                https://cloud.google.com/monitoring/api/v3/sorting-and-filtering
        """

        client = monitoring_v3.AlertPolicyServiceClient()
        policies = client.list_alert_policies(project_name, filter_=filter_)

        for policy in policies:
            if bool(enable) == policy.enabled.value:
                print('Policy', policy.name, 'is already',
                      'enabled' if policy.enabled.value else 'disabled')
            else:
                policy.enabled.value = bool(enable)
                mask = monitoring_v3.types.field_mask_pb2.FieldMask()
                mask.paths.append('enabled')
                client.update_alert_policy(policy, mask)
                print('Enabled' if enable else 'Disabled', policy.name)

更新政策中的通知渠道

您还可以更新提醒政策引用的通知渠道。 提醒政策按名称引用通知渠道。 提醒政策只能使用已存在的渠道。

您可以通过使用 NotificationChannelNotificationChannelDescriptors 资源以编程方式创建和管理通知渠道。本部分中的这些示例假设这些渠道已经存在,并且程序示例中也展示了这些 API 的使用。

如需查看关于通知渠道对象的更多讨论,请参阅使用 API 管理渠道

gcloud 命令

要修改提醒政策中的通知渠道,请使用 gcloud alpha monitoring policies update 命令。与通知渠道相关的标志有几种,您可以使用这些标志删除通知渠道、替换通知渠道、以及添加新的通知渠道。

例如,在项目 a-gcp-project 中创建显示名为 High CPU rate of change 的政策时,没有为该政策创建通知渠道。

要向此政策添加通知渠道,请使用 gcloud alpha monitoring policies update 命令,并指定要添加 --add-notification-channels 标志的渠道:

gcloud alpha monitoring policies update projects/a-gcp-project/alertPolicies/12669073143329903307 \
    --add-notification-channels="projects/a-gcp-project/notificationChannels/1355376463305411567"
    

如需了解详情,请查看 gcloud alpha monitoring policies update 参考。update 命令与 REST API 中的 alertPolicies.patch 方法相对应。

此处添加的通知渠道必须已经存在;详情请参阅创建频道

C#

static void ReplaceChannels(string projectId, string alertPolicyId,
        IEnumerable<string> channelIds)
    {
        var alertClient = AlertPolicyServiceClient.Create();
        var policy = new AlertPolicy()
        {
            Name = new AlertPolicyName(projectId, alertPolicyId).ToString()
        };
        foreach (string channelId in channelIds)
        {
            policy.NotificationChannels.Add(
                new NotificationChannelName(projectId, channelId)
                .ToString());
        }
        var response = alertClient.UpdateAlertPolicy(
            new FieldMask { Paths = { "notification_channels" } }, policy);
        Console.WriteLine("Updated {0}.", response.Name);
    }

Go


    // replaceChannels replaces the notification channels in the alert policy
    // with channelIDs.
    func replaceChannels(w io.Writer, projectID, alertPolicyID string, channelIDs []string) error {
    	ctx := context.Background()

    	client, err := monitoring.NewAlertPolicyClient(ctx)
    	if err != nil {
    		return err
    	}

    	policy := &monitoringpb.AlertPolicy{
    		Name: "projects/" + projectID + "/alertPolicies/" + alertPolicyID,
    	}
    	for _, c := range channelIDs {
    		c = "projects/" + projectID + "/notificationChannels/" + c
    		policy.NotificationChannels = append(policy.NotificationChannels, c)
    	}
    	req := &monitoringpb.UpdateAlertPolicyRequest{
    		AlertPolicy: policy,
    		UpdateMask: &fieldmask.FieldMask{
    			Paths: []string{"notification_channels"},
    		},
    	}
    	if _, err := client.UpdateAlertPolicy(ctx, req); err != nil {
    		return fmt.Errorf("UpdateAlertPolicy: %v", err)
    	}
    	fmt.Fprintf(w, "Successfully replaced channels.")
    	return nil
    }
    

Java

private static void replaceChannels(String projectId, String alertPolicyId, String[] channelIds)
        throws IOException {
      AlertPolicy.Builder policyBuilder =
          AlertPolicy.newBuilder().setName(AlertPolicyName.of(projectId, alertPolicyId).toString());
      for (String channelId : channelIds) {
        policyBuilder.addNotificationChannels(
            NotificationChannelName.of(projectId, channelId).toString());
      }
      try (AlertPolicyServiceClient client = AlertPolicyServiceClient.create()) {
        AlertPolicy result =
            client.updateAlertPolicy(
                FieldMask.newBuilder().addPaths("notification_channels").build(),
                policyBuilder.build());
        System.out.println(String.format("Updated %s", result.getName()));
      }
    }

Node.js


    // Imports the Google Cloud client library
    const monitoring = require('@google-cloud/monitoring');

    // Creates clients
    const alertClient = new monitoring.AlertPolicyServiceClient();
    const notificationClient = new monitoring.NotificationChannelServiceClient();

    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    // const projectId = 'YOUR_PROJECT_ID';
    // const alertPolicyId = '123456789012314';
    // const channelIds = [
    //   'channel-1',
    //   'channel-2',
    //   'channel-3',
    // ];

    const notificationChannels = channelIds.map(id =>
      notificationClient.projectNotificationChannelPath(projectId, id)
    );

    for (const channel of notificationChannels) {
      const updateChannelRequest = {
        updateMask: {
          paths: ['enabled'],
        },
        notificationChannel: {
          name: channel,
          enabled: {
            value: true,
          },
        },
      };
      try {
        await notificationClient.updateNotificationChannel(updateChannelRequest);
      } catch (err) {
        const createChannelRequest = {
          notificationChannel: {
            name: channel,
            notificationChannel: {
              type: 'email',
            },
          },
        };
        const newChannel = await notificationClient.createNotificationChannel(
          createChannelRequest
        );
        notificationChannels.push(newChannel);
      }
    }

    const updateAlertPolicyRequest = {
      updateMask: {
        paths: ['notification_channels'],
      },
      alertPolicy: {
        name: alertClient.projectAlertPolicyPath(projectId, alertPolicyId),
        notificationChannels: notificationChannels,
      },
    };
    const [alertPolicy] = await alertClient.updateAlertPolicy(
      updateAlertPolicyRequest
    );
    console.log(`Updated ${alertPolicy.name}.`);

PHP

use Google\Cloud\Monitoring\V3\AlertPolicyServiceClient;
    use Google\Cloud\Monitoring\V3\NotificationChannelServiceClient;
    use Google\Cloud\Monitoring\V3\AlertPolicy;
    use Google\Protobuf\FieldMask;

    /**
     * @param string $projectId Your project ID
     * @param string $alertPolicyId Your alert policy id ID
     * @param array $channelIds array of channel IDs
     */
    function alert_replace_channels($projectId, $alertPolicyId, array $channelIds)
    {
        $alertClient = new AlertPolicyServiceClient([
            'projectId' => $projectId,
        ]);

        $channelClient = new NotificationChannelServiceClient([
            'projectId' => $projectId,
        ]);
        $policy = new AlertPolicy();
        $policy->setName($alertClient->alertPolicyName($projectId, $alertPolicyId));

        $newChannels = [];
        foreach ($channelIds as $channelId) {
            $newChannels[] = $channelClient->notificationChannelName($projectId, $channelId);
        }
        $policy->setNotificationChannels($newChannels);
        $mask = new FieldMask();
        $mask->setPaths(['notification_channels']);
        $updatedPolicy = $alertClient->updateAlertPolicy($policy, [
            'updateMask' => $mask,
        ]);
        printf('Updated %s' . PHP_EOL, $updatedPolicy->getName());
    }

Python

def replace_notification_channels(project_name, alert_policy_id, channel_ids):
        _, project_id = project_name.split('/')
        alert_client = monitoring_v3.AlertPolicyServiceClient()
        channel_client = monitoring_v3.NotificationChannelServiceClient()
        policy = monitoring_v3.types.alert_pb2.AlertPolicy()
        policy.name = alert_client.alert_policy_path(project_id, alert_policy_id)

        for channel_id in channel_ids:
            policy.notification_channels.append(
                channel_client.notification_channel_path(project_id, channel_id))

        mask = monitoring_v3.types.field_mask_pb2.FieldMask()
        mask.paths.append('notification_channels')
        updated_policy = alert_client.update_alert_policy(policy, mask)
        print('Updated', updated_policy.name)

修改政策中的文档

政策中可以包括与政策关联的事件和通知中附带的文档。使用此字段添加信息,以协助响应人员理解和处理提醒政策所指示的问题。某些类型的通知允许附带文档发送,例如电子邮件通知;而另一些类型的渠道可能会省略文档。

gcloud 命令

要为政策添加文档或替换现有文档,请使用 gcloud alpha monitoring policies update 命令并提供 --documentation-format="text/markdown" 标志(唯一支持的格式),以及 --documentation 标志(从命令行输入值)或 --documentation-from-file 标志(从文件中读取值)。

例如,在项目 a-gcp-project 中创建显示名为 High CPU rate of change 的政策时,没有为该政策添加文档。

以下命令将指定政策中的 documentation 字段设置为 cpu-usage-doc.md 文件中的内容:

gcloud alpha monitoring policies update projects/a-gcp-project/alertPolicies/12669073143329903307 \
    --documentation-format="text/markdown" \
    --documentation-from-file="cpu-usage-doc.md"
    

如需了解详情,请查看 gcloud alpha monitoring policies update 参考。update 命令与 REST API 中的 alertPolicies.patch 方法相对应。

示例:备份和恢复

此处显示的所有 API 示例都是从一个较大的应用中提取的,该应用可以将项目中的提醒政策备份到文件,并可以恢复政策(可能是恢复到另一个项目)。如果用于备份和恢复的项目不是同一个,该应用可以有效地将政策从一个项目导出并导入到另一个项目。

本部分提供的备份和恢复代码附有上下文,而非只摘录一小部分孤立的代码段。

备份政策

备份操作非常简单直接:收集每个项目中的提醒政策和通知渠道,以 JSON 格式保存到外部存储空间。

C#

        static void BackupPolicies(string projectId, string filePath)
            {
                var policyClient = AlertPolicyServiceClient.Create();
                var channelClient = NotificationChannelServiceClient.Create();
                var projectName = new ProjectName(projectId);
                File.WriteAllText(filePath, JsonConvert.SerializeObject(
                    new BackupRecord()
                    {
                        ProjectId = projectId,
                        Policies = policyClient.ListAlertPolicies(projectName),
                        Channels = channelClient.ListNotificationChannels(projectName)
                    }, new ProtoMessageConverter()));
            }
            class BackupRecord
            {
                public string ProjectId { get; set; }
                public IEnumerable<AlertPolicy> Policies { get; set; }
                public IEnumerable<NotificationChannel> Channels { get; set; }
            }

            /// <summary>
            /// Lets Newtonsoft.Json and Protobuf's json converters play nicely
            /// together.  The default Netwtonsoft.Json Deserialize method will
            /// not correctly deserialize proto messages.
            /// </summary>
            class ProtoMessageConverter : JsonConverter
            {
                public override bool CanConvert(System.Type objectType)
                {
                    return typeof(Google.Protobuf.IMessage)
                        .IsAssignableFrom(objectType);
                }

                public override object ReadJson(JsonReader reader,
                    System.Type objectType, object existingValue,
                    JsonSerializer serializer)
                {
                    // Read an entire object from the reader.
                    var converter = new ExpandoObjectConverter();
                    object o = converter.ReadJson(reader, objectType, existingValue,
                        serializer);
                    // Convert it back to json text.
                    string text = JsonConvert.SerializeObject(o);
                    // And let protobuf's parser parse the text.
                    IMessage message = (IMessage)Activator
                        .CreateInstance(objectType);
                    return Google.Protobuf.JsonParser.Default.Parse(text,
                        message.Descriptor);
                }

                public override void WriteJson(JsonWriter writer, object value,
                    JsonSerializer serializer)
                {
                    writer.WriteRawValue(Google.Protobuf.JsonFormatter.Default
                        .Format((IMessage)value));
                }
            }

Go


    // backupPolicies writes a JSON representation of the project's alert
    // policies and notification channels.
    func backupPolicies(w io.Writer, projectID string) error {
    	b := backup{ProjectID: projectID}
    	ctx := context.Background()

    	alertClient, err := monitoring.NewAlertPolicyClient(ctx)
    	if err != nil {
    		return err
    	}
    	alertReq := &monitoringpb.ListAlertPoliciesRequest{
    		Name: "projects/" + projectID,
    		// Filter:  "", // See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering.
    		// OrderBy: "", // See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering.
    	}
    	alertIt := alertClient.ListAlertPolicies(ctx, alertReq)
    	for {
    		resp, err := alertIt.Next()
    		if err == iterator.Done {
    			break
    		}
    		if err != nil {
    			return err
    		}
    		b.AlertPolicies = append(b.AlertPolicies, &alertPolicy{resp})
    	}

    	channelClient, err := monitoring.NewNotificationChannelClient(ctx)
    	if err != nil {
    		return err
    	}
    	channelReq := &monitoringpb.ListNotificationChannelsRequest{
    		Name: "projects/" + projectID,
    		// Filter:  "", // See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering.
    		// OrderBy: "", // See https://cloud.google.com/monitoring/api/v3/sorting-and-filtering.
    	}
    	channelIt := channelClient.ListNotificationChannels(ctx, channelReq)
    	for {
    		resp, err := channelIt.Next()
    		if err == iterator.Done {
    			break
    		}
    		if err != nil {
    			return err
    		}
    		b.Channels = append(b.Channels, &channel{resp})
    	}
    	bs, err := json.MarshalIndent(b, "", "  ")
    	if err != nil {
    		return err
    	}
    	if _, err := w.Write(bs); err != nil {
    		return err
    	}
    	return nil
    }

    // alertPolicy is a wrapper around the AlertPolicy proto to
    // ensure JSON marshaling/unmarshaling works correctly.
    type alertPolicy struct {
    	*monitoringpb.AlertPolicy
    }

    // channel is a wrapper around the NotificationChannel proto to
    // ensure JSON marshaling/unmarshaling works correctly.
    type channel struct {
    	*monitoringpb.NotificationChannel
    }

    // backup is used to backup and restore a project's policies.
    type backup struct {
    	ProjectID     string
    	AlertPolicies []*alertPolicy
    	Channels      []*channel
    }

    func (a *alertPolicy) MarshalJSON() ([]byte, error) {
    	m := &jsonpb.Marshaler{EmitDefaults: true}
    	b := new(bytes.Buffer)
    	m.Marshal(b, a.AlertPolicy)
    	return b.Bytes(), nil
    }

    func (a *alertPolicy) UnmarshalJSON(b []byte) error {
    	u := &jsonpb.Unmarshaler{}
    	a.AlertPolicy = new(monitoringpb.AlertPolicy)
    	return u.Unmarshal(bytes.NewReader(b), a.AlertPolicy)
    }

    func (c *channel) MarshalJSON() ([]byte, error) {
    	m := &jsonpb.Marshaler{}
    	b := new(bytes.Buffer)
    	m.Marshal(b, c.NotificationChannel)
    	return b.Bytes(), nil
    }

    func (c *channel) UnmarshalJSON(b []byte) error {
    	u := &jsonpb.Unmarshaler{}
    	c.NotificationChannel = new(monitoringpb.NotificationChannel)
    	return u.Unmarshal(bytes.NewReader(b), c.NotificationChannel)
    }
    

Java

private static void backupPolicies(String projectId, String filePath) throws IOException {
      List<AlertPolicy> alertPolicies = getAlertPolicies(projectId);
      List<NotificationChannel> notificationChannels = getNotificationChannels(projectId);
      writePoliciesBackupFile(projectId, filePath, alertPolicies, notificationChannels);
      System.out.println(String.format("Saved policies to %s", filePath));
    }

    private static List<AlertPolicy> getAlertPolicies(String projectId) throws IOException {
      List<AlertPolicy> alertPolicies = Lists.newArrayList();
      try (AlertPolicyServiceClient client = AlertPolicyServiceClient.create()) {
        ListAlertPoliciesPagedResponse response = client.listAlertPolicies(ProjectName.of(projectId));

        for (AlertPolicy policy : response.iterateAll()) {
          alertPolicies.add(policy);
        }
      }
      return alertPolicies;
    }

    private static List<NotificationChannel> getNotificationChannels(String projectId)
        throws IOException {
      List<NotificationChannel> notificationChannels = Lists.newArrayList();
      try (NotificationChannelServiceClient client = NotificationChannelServiceClient.create()) {
        ListNotificationChannelsPagedResponse listNotificationChannelsResponse =
            client.listNotificationChannels(ProjectName.of(projectId));
        for (NotificationChannel channel : listNotificationChannelsResponse.iterateAll()) {
          notificationChannels.add(channel);
        }
      }
      return notificationChannels;
    }

    private static void writePoliciesBackupFile(
        String projectId,
        String filePath,
        List<AlertPolicy> alertPolicies,
        List<NotificationChannel> notificationChannels)
        throws IOException {
      JsonObject backupContents = new JsonObject();
      backupContents.add("project_id", new JsonPrimitive(projectId));
      JsonArray policiesJson = new JsonArray();
      for (AlertPolicy policy : alertPolicies) {
        policiesJson.add(gson.toJsonTree(policy));
      }
      backupContents.add("policies", policiesJson);

      JsonArray notificationsJson = new JsonArray();
      for (NotificationChannel channel : notificationChannels) {
        notificationsJson.add(gson.toJsonTree(channel));
      }
      backupContents.add("notification_channels", notificationsJson);

      FileWriter writer = new FileWriter(filePath);
      writer.write(backupContents.toString());
      writer.close();
    }

Node.js

const fs = require('fs');

    // Imports the Google Cloud client library
    const monitoring = require('@google-cloud/monitoring');

    // Creates a client
    const client = new monitoring.AlertPolicyServiceClient();

    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    // const projectId = 'YOUR_PROJECT_ID';

    const listAlertPoliciesRequest = {
      name: client.projectPath(projectId),
    };

    let [policies] = await client.listAlertPolicies(listAlertPoliciesRequest);

    // filter out any policies created by tests for this sample
    policies = policies.filter(policy => {
      return !policy.displayName.startsWith('gcloud-tests-');
    });

    fs.writeFileSync(
      './policies_backup.json',
      JSON.stringify(policies, null, 2),
      'utf-8'
    );

    console.log('Saved policies to ./policies_backup.json');

PHP

use Google\Cloud\Monitoring\V3\AlertPolicyServiceClient;
    use Google\Cloud\Monitoring\V3\NotificationChannelServiceClient;

    /**
     * Back up alert policies.
     *
     * @param string $projectId Your project ID
     */
    function alert_backup_policies($projectId)
    {
        $alertClient = new AlertPolicyServiceClient([
            'projectId' => $projectId,
        ]);
        $channelClient = new NotificationChannelServiceClient([
            'projectId' => $projectId,
        ]);
        $projectName = $alertClient->projectName($projectId);

        $record = [
            'project_name' => $projectName,
            'policies' => [],
            'channels' => [],
        ];
        $policies = $alertClient->listAlertPolicies($projectName);
        foreach ($policies->iterateAllElements() as $policy) {
            $record['policies'][] = json_decode($policy->serializeToJsonString());
        }
        $channels = $channelClient->listNotificationChannels($projectName);
        foreach ($channels->iterateAllElements() as $channel) {
            $record['channels'][] = json_decode($channel->serializeToJsonString());
        }
        file_put_contents('backup.json', json_encode($record, JSON_PRETTY_PRINT));
        print('Backed up alert policies and notification channels to backup.json.');
    }

Python

def backup(project_name, backup_filename):
        alert_client = monitoring_v3.AlertPolicyServiceClient()
        channel_client = monitoring_v3.NotificationChannelServiceClient()
        record = {'project_name': project_name,
                  'policies': list(alert_client.list_alert_policies(project_name)),
                  'channels': list(channel_client.list_notification_channels(
                      project_name))}
        json.dump(record, open(backup_filename, 'wt'), cls=ProtoEncoder, indent=2)
        print('Backed up alert policies and notification channels to {}.'.format(
            backup_filename)
        )

    class ProtoEncoder(json.JSONEncoder):
        """Uses google.protobuf.json_format to encode protobufs as json."""
        def default(self, obj):
            if type(obj) in (monitoring_v3.types.alert_pb2.AlertPolicy,
                             monitoring_v3.types.notification_pb2.
                             NotificationChannel):
                text = google.protobuf.json_format.MessageToJson(obj)
                return json.loads(text)
            return super(ProtoEncoder, self).default(obj)

恢复已备份的政策

恢复过程比原始备份复杂。您可以恢复到最初备份的项目;也可以恢复到其他项目,即提供提醒政策的导入。

如果恢复到同一项目,并且该项目中仍存在备份中的政策或渠道,则这些政策或渠道将全部更新。如果现有项目中已不存在备份中的政策或渠道,则备份将在现有项目中重新创建这些政策或渠道。 在重新创建策略和通知之前,还原过程将清除备份政策中的只读字段,如创建和突变记录。

您可以使用保存在一个项目中的政策,在另一个项目中创建新政策或类似政策。但是,您必须首先在已保存政策的副本中进行以下更改:

  • 从任何通知渠道中移除以下字段:
    • name
    • verificationStatus
  • 在引用提醒政策中的通知渠道之前先创建通知渠道(您需要新的渠道标识符)。
  • 从您正在重新创建的任何提醒政策中移除以下字段:
    • name
    • condition.name
    • creationRecord
    • mutationRecord

如果在新项目中重新创建政策,则备份政策中任何条件的名称以及创建和突变记录也会一并清除。

此外,在另一个项目中重新创建通知渠道时,该渠道将被赋予不同的名称,因此恢复过程必须将已备份提醒政策中的渠道名称映射到新名称,并用新名称替换旧名称。

除了通知渠道的名称之外,verificationStatus 字段的值无法在创建或更新渠道时设置,因此会使用一个特殊值,即 unspecified。渠道恢复到新项目后,必须明确对其进行验证。

C#

        static void RestorePolicies(string projectId, string filePath)
            {
                var policyClient = AlertPolicyServiceClient.Create();
                var channelClient = NotificationChannelServiceClient.Create();
                List<Exception> exceptions = new List<Exception>();
                var backup = JsonConvert.DeserializeObject<BackupRecord>(
                    File.ReadAllText(filePath), new ProtoMessageConverter());
                var projectName = new ProjectName(projectId);
                bool isSameProject = projectId == backup.ProjectId;
                // When a channel is recreated, rather than updated, it will get
                // a new name.  We have to update the AlertPolicy with the new
                // name.  Track the names in this map.
                var channelNameMap = new Dictionary<string, string>();
                foreach (NotificationChannel channel in backup.Channels)
                {
                    try
                    {
                        bool updated = false;
                        Console.WriteLine("Updating channel.\n{0}",
                            channel.DisplayName);
                        // This field is immutable and it is illegal to specify a
                        // non-default value (UNVERIFIED or VERIFIED) in the
                        // Create() or Update() operations.
                        channel.VerificationStatus = NotificationChannel.Types
                            .VerificationStatus.Unspecified;
                        if (isSameProject)
                            try
                            {
                                channelClient.UpdateNotificationChannel(
                                    null, channel);
                                updated = true;
                            }
                            catch (Grpc.Core.RpcException e)
                            when (e.Status.StatusCode == StatusCode.NotFound)
                            { }
                        if (!updated)
                        {
                            // The channel no longer exists.  Recreate it.
                            string oldName = channel.Name;
                            channel.Name = null;
                            var response = channelClient.CreateNotificationChannel(
                                projectName, channel);
                            channelNameMap.Add(oldName, response.Name);
                        }
                    }
                    catch (Exception e)
                    {
                        // If one failed, continue trying to update the others.
                        exceptions.Add(e);
                    }
                }
                foreach (AlertPolicy policy in backup.Policies)
                {
                    string policyName = policy.Name;
                    // These two fields cannot be set directly, so clear them.
                    policy.CreationRecord = null;
                    policy.MutationRecord = null;
                    // Update channel names if the channel was recreated with
                    // another name.
                    for (int i = 0; i < policy.NotificationChannels.Count; ++i)
                    {
                        if (channelNameMap.ContainsKey(policy.NotificationChannels[i]))
                        {
                            policy.NotificationChannels[i] =
                                channelNameMap[policy.NotificationChannels[i]];
                        }
                    }
                    try
                    {
                        Console.WriteLine("Updating policy.\n{0}",
                            policy.DisplayName);
                        bool updated = false;
                        if (isSameProject)
                            try
                            {
                                policyClient.UpdateAlertPolicy(null, policy);
                                updated = true;
                            }
                            catch (Grpc.Core.RpcException e)
                            when (e.Status.StatusCode == StatusCode.NotFound)
                            { }
                        if (!updated)
                        {
                            // The policy no longer exists.  Recreate it.
                            policy.Name = null;
                            foreach (var condition in policy.Conditions)
                            {
                                condition.Name = null;
                            }
                            policyClient.CreateAlertPolicy(projectName, policy);
                        }
                        Console.WriteLine("Restored {0}.", policyName);
                    }
                    catch (Exception e)
                    {
                        // If one failed, continue trying to update the others.
                        exceptions.Add(e);
                    }
                }
                if (exceptions.Count > 0)
                {
                    throw new AggregateException(exceptions);
                }
            }

            class BackupRecord
            {
                public string ProjectId { get; set; }
                public IEnumerable<AlertPolicy> Policies { get; set; }
                public IEnumerable<NotificationChannel> Channels { get; set; }
            }

            /// <summary>
            /// Lets Newtonsoft.Json and Protobuf's json converters play nicely
            /// together.  The default Netwtonsoft.Json Deserialize method will
            /// not correctly deserialize proto messages.
            /// </summary>
            class ProtoMessageConverter : JsonConverter
            {
                public override bool CanConvert(System.Type objectType)
                {
                    return typeof(Google.Protobuf.IMessage)
                        .IsAssignableFrom(objectType);
                }

                public override object ReadJson(JsonReader reader,
                    System.Type objectType, object existingValue,
                    JsonSerializer serializer)
                {
                    // Read an entire object from the reader.
                    var converter = new ExpandoObjectConverter();
                    object o = converter.ReadJson(reader, objectType, existingValue,
                        serializer);
                    // Convert it back to json text.
                    string text = JsonConvert.SerializeObject(o);
                    // And let protobuf's parser parse the text.
                    IMessage message = (IMessage)Activator
                        .CreateInstance(objectType);
                    return Google.Protobuf.JsonParser.Default.Parse(text,
                        message.Descriptor);
                }

                public override void WriteJson(JsonWriter writer, object value,
                    JsonSerializer serializer)
                {
                    writer.WriteRawValue(Google.Protobuf.JsonFormatter.Default
                        .Format((IMessage)value));
                }
            }

Go


    // restorePolicies updates the project with the alert policies and
    // notification channels in r.
    func restorePolicies(w io.Writer, projectID string, r io.Reader) error {
    	b := backup{}
    	if err := json.NewDecoder(r).Decode(&b); err != nil {
    		return err
    	}
    	sameProject := projectID == b.ProjectID

    	ctx := context.Background()

    	alertClient, err := monitoring.NewAlertPolicyClient(ctx)
    	if err != nil {
    		return err
    	}
    	channelClient, err := monitoring.NewNotificationChannelClient(ctx)
    	if err != nil {
    		return err
    	}

    	// When a channel is recreated, rather than updated, it will get
    	// a new name.  We have to update the AlertPolicy with the new
    	// name.  channelNames keeps track of the new names.
    	channelNames := make(map[string]string)
    	for _, c := range b.Channels {
    		fmt.Fprintf(w, "Updating channel %q\n", c.GetDisplayName())
    		c.VerificationStatus = monitoringpb.NotificationChannel_VERIFICATION_STATUS_UNSPECIFIED
    		updated := false
    		if sameProject {
    			req := &monitoringpb.UpdateNotificationChannelRequest{
    				NotificationChannel: c.NotificationChannel,
    			}
    			_, err := channelClient.UpdateNotificationChannel(ctx, req)
    			if err == nil {
    				updated = true
    			}
    		}
    		if !updated {
    			req := &monitoringpb.CreateNotificationChannelRequest{
    				Name:                "projects/" + projectID,
    				NotificationChannel: c.NotificationChannel,
    			}
    			oldName := c.GetName()
    			c.Name = ""
    			newC, err := channelClient.CreateNotificationChannel(ctx, req)
    			if err != nil {
    				return err
    			}
    			channelNames[oldName] = newC.GetName()
    		}
    	}

    	for _, policy := range b.AlertPolicies {
    		fmt.Fprintf(w, "Updating alert %q\n", policy.GetDisplayName())
    		policy.CreationRecord = nil
    		policy.MutationRecord = nil
    		for i, aChannel := range policy.GetNotificationChannels() {
    			if c, ok := channelNames[aChannel]; ok {
    				policy.NotificationChannels[i] = c
    			}
    		}
    		updated := false
    		if sameProject {
    			req := &monitoringpb.UpdateAlertPolicyRequest{
    				AlertPolicy: policy.AlertPolicy,
    			}
    			_, err := alertClient.UpdateAlertPolicy(ctx, req)
    			if err == nil {
    				updated = true
    			}
    		}
    		if !updated {
    			req := &monitoringpb.CreateAlertPolicyRequest{
    				Name:        "projects/" + projectID,
    				AlertPolicy: policy.AlertPolicy,
    			}
    			if _, err = alertClient.CreateAlertPolicy(ctx, req); err != nil {
    				log.Fatal(err)
    			}
    		}
    	}
    	fmt.Fprintf(w, "Successfully restored alerts.")
    	return nil
    }
    

Java

private static void restorePolicies(String projectId, String filePath) throws IOException {
      FileReader reader = new FileReader(filePath);
      BufferedReader bufferedReader = new BufferedReader(reader);

      JsonObject backupContent = getPolicyJsonContents(filePath, bufferedReader);
      String backupProjectId = backupContent.get("project_id").getAsString();
      boolean isSameProject = projectId.equals(backupProjectId);

      AlertPolicy[] policies = gson.fromJson(backupContent.get("policies"), AlertPolicy[].class);
      List<NotificationChannel> notificationChannels = readNotificationChannelsJson(backupContent);
      Map<String, String> restoredChannelIds =
          restoreNotificationChannels(projectId, notificationChannels, isSameProject);
      List<AlertPolicy> policiesToRestore =
          reviseRestoredPolicies(policies, isSameProject, restoredChannelIds);

      restoreRevisedPolicies(projectId, isSameProject, policiesToRestore);
    }

    private static List<AlertPolicy> reviseRestoredPolicies(
        AlertPolicy[] policies, boolean isSameProject, Map<String, String> restoredChannelIds) {
      List<AlertPolicy> newPolicies = Lists.newArrayListWithCapacity(policies.length);
      for (AlertPolicy policy : policies) {
        AlertPolicy.Builder policyBuilder =
            policy
                .toBuilder()
                .clearNotificationChannels()
                .clearMutationRecord()
                .clearCreationRecord();
        // Update restored notification channel names.
        for (String channelName : policy.getNotificationChannelsList()) {
          String newChannelName = restoredChannelIds.get(channelName);
          if (!Strings.isNullOrEmpty(newChannelName)) {
            policyBuilder.addNotificationChannels(newChannelName);
          }
        }
        if (!isSameProject) {
          policyBuilder.clearName();
          policyBuilder.clearConditions();
          for (AlertPolicy.Condition condition : policy.getConditionsList()) {
            policyBuilder.addConditions(condition.toBuilder().clearName());
          }
        }
        newPolicies.add(policyBuilder.build());
      }
      return newPolicies;
    }

    private static void restoreRevisedPolicies(
        String projectId, boolean isSameProject, List<AlertPolicy> policies) throws IOException {
      try (AlertPolicyServiceClient client = AlertPolicyServiceClient.create()) {
        for (AlertPolicy policy : policies) {
          if (!isSameProject) {
            policy = client.createAlertPolicy(ProjectName.of(projectId), policy);
          } else {
            try {
              client.updateAlertPolicy(null, policy);
            } catch (Exception e) {
              policy =
                  client.createAlertPolicy(
                      ProjectName.of(projectId), policy.toBuilder().clearName().build());
            }
          }
          System.out.println(String.format("Restored %s", policy.getName()));
        }
      }
    }

    private static List<NotificationChannel> readNotificationChannelsJson(JsonObject backupContent) {
      if (backupContent.has("notification_channels")) {
        NotificationChannel[] channels =
            gson.fromJson(backupContent.get("notification_channels"), NotificationChannel[].class);
        return Lists.newArrayList(channels);
      }
      return Lists.newArrayList();
    }

    private static Map<String, String> restoreNotificationChannels(
        String projectId, List<NotificationChannel> channels, boolean isSameProject)
        throws IOException {
      Map<String, String> newChannelNames = Maps.newHashMap();
      try (NotificationChannelServiceClient client = NotificationChannelServiceClient.create()) {
        for (NotificationChannel channel : channels) {
          // Update channel name if project ID is different.
          boolean channelUpdated = false;
          if (isSameProject) {
            try {
              NotificationChannel updatedChannel =
                  client.updateNotificationChannel(NOTIFICATION_CHANNEL_UPDATE_MASK, channel);
              newChannelNames.put(channel.getName(), updatedChannel.getName());
              channelUpdated = true;
            } catch (Exception e) {
              channelUpdated = false;
            }
          }
          if (!channelUpdated) {
            NotificationChannel newChannel =
                client.createNotificationChannel(
                    ProjectName.of(projectId),
                    channel.toBuilder().clearName().clearVerificationStatus().build());
            newChannelNames.put(channel.getName(), newChannel.getName());
          }
        }
      }
      return newChannelNames;
    }

    private static JsonObject getPolicyJsonContents(String filePath, BufferedReader content) {
      try {
        return gson.fromJson(content, JsonObject.class);
      } catch (JsonSyntaxException jse) {
        throw new RuntimeException(String.format("Could not parse policies file %s", filePath), jse);
      }
    }

Node.js

const fs = require('fs');

    // Imports the Google Cloud client library
    const monitoring = require('@google-cloud/monitoring');

    // Creates a client
    const client = new monitoring.AlertPolicyServiceClient();

    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    // const projectId = 'YOUR_PROJECT_ID';

    console.log('Loading policies from ./policies_backup.json');
    const fileContent = fs.readFileSync('./policies_backup.json', 'utf-8');
    const policies = JSON.parse(fileContent);

    for (const index in policies) {
      // Restore each policy one at a time
      let policy = policies[index];
      if (await doesAlertPolicyExist(policy.name)) {
        policy = await client.updateAlertPolicy({
          alertPolicy: policy,
        });
      } else {
        // Clear away output-only fields
        delete policy.name;
        delete policy.creationRecord;
        delete policy.mutationRecord;
        policy.conditions.forEach(condition => delete condition.name);

        policy = await client.createAlertPolicy({
          name: client.projectPath(projectId),
          alertPolicy: policy,
        });
      }

      console.log(`Restored ${policy[0].name}.`);
    }
    async function doesAlertPolicyExist(name) {
      try {
        const [policy] = await client.getAlertPolicy({
          name,
        });
        return policy ? true : false;
      } catch (err) {
        if (err && err.code === 5) {
          // Error code 5 comes from the google.rpc.code.NOT_FOUND protobuf
          return false;
        }
        throw err;
      }
    }

PHP

use Google\Cloud\Monitoring\V3\AlertPolicyServiceClient;
    use Google\Cloud\Monitoring\V3\NotificationChannelServiceClient;
    use Google\Cloud\Monitoring\V3\AlertPolicy;
    use Google\Cloud\Monitoring\V3\NotificationChannel;
    use Google\Cloud\Monitoring\V3\NotificationChannel\VerificationStatus;
    use Google\ApiCore\ApiException;

    /**
     * @param string $projectId Your project ID
     */
    function alert_restore_policies($projectId)
    {
        $alertClient = new AlertPolicyServiceClient([
            'projectId' => $projectId,
        ]);

        $channelClient = new NotificationChannelServiceClient([
            'projectId' => $projectId,
        ]);

        print('Loading alert policies and notification channels from backup.json.' . PHP_EOL);
        $projectName = $alertClient->projectName($projectId);
        $record = json_decode(file_get_contents('backup.json'), true);
        $isSameProject = $projectName == $record['project_name'];

        # Convert dicts to AlertPolicies.
        $policies = [];
        foreach ($record['policies'] as $policyArray) {
            $policy = new AlertPolicy();
            $policy->mergeFromJsonString(json_encode($policyArray));
            $policies[] = $policy;
        }

        # Convert dicts to NotificationChannels
        $channels = [];
        foreach (array_filter($record['channels']) as $channelArray) {
            $channel = new NotificationChannel();
            $channel->mergeFromJsonString(json_encode($channelArray));
            $channels[] = $channel;
        }

        # Restore the channels.
        $channelNameMap = [];
        foreach ($channels as $channel) {
            $updated = false;
            printf('Updating channel %s' . PHP_EOL, $channel->getDisplayName());

            # This field is immutable and it is illegal to specify a
            # non-default value (UNVERIFIED or VERIFIED) in the
            # Create() or Update() operations.
            $channel->setVerificationStatus(
                VerificationStatus::VERIFICATION_STATUS_UNSPECIFIED
            );

            if ($isSameProject) {
                try {
                    $channelClient->updateNotificationChannel($channel);
                    $updated = true;
                } catch (ApiException $e) {
                    # The channel was deleted.  Create it below.
                    if ($e->getStatus() !== 'NOT_FOUND') {
                        throw $e;
                    }
                }
            }

            if (!$updated) {
                # The channel no longer exists.  Recreate it.
                $oldName = $channel->getName();
                $channel->setName('');
                $newChannel = $channelClient->createNotificationChannel(
                    $projectName,
                    $channel
                );
                $channelNameMap[$oldName] = $newChannel->getName();
            }
        }

        # Restore the alerts
        foreach ($policies as $policy) {
            printf('Updating policy %s' . PHP_EOL, $policy->getDisplayName());
            # These two fields cannot be set directly, so clear them.
            $policy->setCreationRecord(null);
            $policy->setMutationRecord(null);

            $notificationChannels = $policy->getNotificationChannels();

            # Update old channel names with new channel names.
            foreach ($notificationChannels as $i => $channel) {
                if (isset($channelNameMap[$channel])) {
                    $notificationChannels[$i] = $channelNameMap[$channel];
                }
            }

            $updated = false;
            if ($isSameProject) {
                try {
                    $alertClient->updateAlertPolicy($policy);
                    $updated = true;
                } catch (ApiException $e) {
                    # The policy was deleted.  Create it below.
                    if ($e->getStatus() !== 'NOT_FOUND') {
                        throw $e;
                    }
                }
            }

            if (!$updated) {
                # The policy no longer exists.  Recreate it.
                $oldName = $policy->getName();
                $policy->setName('');
                foreach ($policy->getConditions() as $condition) {
                    $condition->setName('');
                }
                $policy = $alertClient->createAlertPolicy($projectName, $policy);
            }
            printf('Updated %s' . PHP_EOL, $policy->getName());
        }
        print('Restored alert policies and notification channels from backup.json.');
    }

Python

def restore(project_name, backup_filename):
        print('Loading alert policies and notification channels from {}.'.format(
            backup_filename)
        )
        record = json.load(open(backup_filename, 'rt'))
        is_same_project = project_name == record['project_name']
        # Convert dicts to AlertPolicies.
        policies_json = [json.dumps(policy) for policy in record['policies']]
        policies = [google.protobuf.json_format.Parse(
            policy_json, monitoring_v3.types.alert_pb2.AlertPolicy())
            for policy_json in policies_json]
        # Convert dicts to NotificationChannels
        channels_json = [json.dumps(channel) for channel in record['channels']]
        channels = [google.protobuf.json_format.Parse(
            channel_json, monitoring_v3.types.notification_pb2.
            NotificationChannel()) for channel_json in channels_json]

        # Restore the channels.
        channel_client = monitoring_v3.NotificationChannelServiceClient()
        channel_name_map = {}

        for channel in channels:
            updated = False
            print('Updating channel', channel.display_name)
            # This field is immutable and it is illegal to specify a
            # non-default value (UNVERIFIED or VERIFIED) in the
            # Create() or Update() operations.
            channel.verification_status = monitoring_v3.enums.NotificationChannel.\
                VerificationStatus.VERIFICATION_STATUS_UNSPECIFIED

            if is_same_project:
                try:
                    channel_client.update_notification_channel(channel)
                    updated = True
                except google.api_core.exceptions.NotFound:
                    pass  # The channel was deleted.  Create it below.

            if not updated:
                # The channel no longer exists.  Recreate it.
                old_name = channel.name
                channel.ClearField("name")
                new_channel = channel_client.create_notification_channel(
                    project_name, channel)
                channel_name_map[old_name] = new_channel.name

        # Restore the alerts
        alert_client = monitoring_v3.AlertPolicyServiceClient()

        for policy in policies:
            print('Updating policy', policy.display_name)
            # These two fields cannot be set directly, so clear them.
            policy.ClearField('creation_record')
            policy.ClearField('mutation_record')

            # Update old channel names with new channel names.
            for i, channel in enumerate(policy.notification_channels):
                new_channel = channel_name_map.get(channel)
                if new_channel:
                    policy.notification_channels[i] = new_channel

            updated = False

            if is_same_project:
                try:
                    alert_client.update_alert_policy(policy)
                    updated = True
                except google.api_core.exceptions.NotFound:
                    pass  # The policy was deleted.  Create it below.
                except google.api_core.exceptions.InvalidArgument:
                    # Annoying that API throws InvalidArgument when the policy
                    # does not exist.  Seems like it should throw NotFound.
                    pass  # The policy was deleted.  Create it below.

            if not updated:
                # The policy no longer exists.  Recreate it.
                old_name = policy.name
                policy.ClearField("name")
                for condition in policy.conditions:
                    condition.ClearField("name")
                policy = alert_client.create_alert_policy(project_name, policy)
            print('Updated', policy.name)

提醒和 Cloud SDK

在 Cloud SDK 中,用于管理提醒政策和通知渠道的命令组是 monitoring(现为 Alpha 版)。monitoring 组在 alpha 组件中提供。也就是说,这些命令均以如下内容开头:

gcloud alpha monitoring
    

要检查您是否安装了 alpha 组件,请运行以下命令:

gcloud components list
    

如果您没有安装 alpha 组件,请运行以下命令进行安装:

gcloud components install alpha
    

如果您已安装了 alpha 组件,请通过运行以下命令来检查是否包含 monitoring 组:

gcloud alpha monitoring --help
    

如果未包含 monitoring 组,Cloud SDK 将提示您进行添加:

You do not currently have this command group installed.
    [...]
    Do you want to continue (Y/n)?  y