向 Slack 发送通知

本文档介绍了如何将预算通知发送到 Slack。

预算通常配置为发送电子邮件通知。但是,电子邮件并非在任何时候都是您及时了解云费用的最佳方式,尤其是在您的预算非常重要且具有高时效性的情况下。借助程序化通知,您可以将预算消息转发给其他媒介,例如 Slack

准备工作

在开始之前,您必须完成以下任务:

  1. 启用 Cloud Billing API
  2. 创建预算
  3. 设置程序化预算通知

设置 Slack 频道和权限

第一步是创建 Slack 工作区以及用于调用 Slack API 的聊天机器人用户令牌。API 令牌可以通过 https://api.slack.com/apps 进行管理。如需查看详细说明,请参阅 Slack 网站上的聊天机器人用户

配置 Slack 通知。

设置 Cloud Run 函数

  1. 完成创建 Cloud Run 函数中的步骤。确保将触发器类型设置为预算将使用的同一 Pub/Sub 主题。

  2. 添加以下依赖项:

    Node.js

    将以下内容复制到 package.json 中:

    {
      "name": "cloud-functions-billing",
      "private": "true",
      "version": "0.0.1",
      "description": "Examples of integrating Cloud Functions with billing",
      "main": "index.js",
      "engines": {
        "node": ">=16.0.0"
      },
      "scripts": {
        "compute-test": "c8 mocha -p -j 2 test/periodic.test.js --timeout=600000",
        "test": "c8 mocha -p -j 2 test/index.test.js --timeout=5000 --exit"
      },
      "author": "Ace Nassri <anassri@google.com>",
      "license": "Apache-2.0",
      "dependencies": {
        "@google-cloud/billing": "^4.0.0",
        "@google-cloud/compute": "^4.0.0",
        "google-auth-library": "^9.0.0",
        "googleapis": "^143.0.0",
        "slack": "^11.0.1"
      },
      "devDependencies": {
        "@google-cloud/functions-framework": "^3.0.0",
        "c8": "^10.0.0",
        "gaxios": "^6.0.0",
        "mocha": "^10.0.0",
        "promise-retry": "^2.0.0",
        "proxyquire": "^2.1.0",
        "sinon": "^18.0.0",
        "wait-port": "^1.0.4"
      }
    }
    

    Python

    将以下内容复制到 requirements.txt 中:

    slackclient==2.9.4
    google-api-python-client==2.131.0
    

  3. 将以下代码复制到您的 Cloud Run 函数中,以使用 Slack API 将预算通知发布到 Slack 聊天频道:

    Node.js

    const slack = require('slack');
    
    // TODO(developer) replace these with your own values
    const BOT_ACCESS_TOKEN =
      process.env.BOT_ACCESS_TOKEN || 'xxxx-111111111111-abcdefghidklmnopq';
    const CHANNEL = process.env.SLACK_CHANNEL || 'general';
    
    exports.notifySlack = async pubsubEvent => {
      const pubsubAttrs = pubsubEvent.attributes;
      const pubsubData = Buffer.from(pubsubEvent.data, 'base64').toString();
      const budgetNotificationText = `${JSON.stringify(
        pubsubAttrs
      )}, ${pubsubData}`;
    
      await slack.chat.postMessage({
        token: BOT_ACCESS_TOKEN,
        channel: CHANNEL,
        text: budgetNotificationText,
      });
    
      return 'Slack notification sent successfully';
    };

    Python

    import base64
    import json
    import os
    
    import slack
    from slack.errors import SlackApiError
    
    # See https://api.slack.com/docs/token-types#bot for more info
    BOT_ACCESS_TOKEN = "xxxx-111111111111-abcdefghidklmnopq"
    CHANNEL = "C0XXXXXX"
    
    slack_client = slack.WebClient(token=BOT_ACCESS_TOKEN)
    
    
    def notify_slack(data, context):
        pubsub_message = data
    
        # For more information, see
        # https://cloud.google.com/billing/docs/how-to/budgets-programmatic-notifications#notification_format
        try:
            notification_attr = json.dumps(pubsub_message["attributes"])
        except KeyError:
            notification_attr = "No attributes passed in"
    
        try:
            notification_data = base64.b64decode(data["data"]).decode("utf-8")
        except KeyError:
            notification_data = "No data passed in"
    
        # This is just a quick dump of the budget data (or an empty string)
        # You can modify and format the message to meet your needs
        budget_notification_text = f"{notification_attr}, {notification_data}"
    
        try:
            slack_client.api_call(
                "chat.postMessage",
                json={"channel": CHANNEL, "text": budget_notification_text},
            )
        except SlackApiError:
            print("Error posting to Slack")
    
    

  4. 确保正确设置以下 Slack API postMessage 参数:

    • 聊天机器人用户 OAuth 访问令牌
    • 渠道名称

测试函数

如需确保您的函数按预期运行,请按照测试 Cloud Run 函数中的步骤操作。

如果成功,Slack 中会显示一条消息。

后续步骤

查看其他程序化通知示例,了解如何执行以下操作: