Slack App for Channel Routing

groundcover supports sending notifications to Slack using a Slack App with bot tokens instead of static webhooks. This method allows dynamic routing of alerts to any channel by including the channel ID in the payload. In addition to routing, messages can be enriched with formatting, blocks, and mentions — for example including <@user_id> in the payload to directly notify specific team members. This provides a flexible and powerful alternative to fixed incoming webhooks for alerting.

Make sure you created a webhook for a Slack App with Bot Tokens.

Use the following workflow as an example. You can later enrich your workflow with additional functionality.

Here are a few tips for using the example workflow:

  1. In the consts section, the channels attribute defines the mapping between Slack channels and their IDs. Use a clear, readable label to identify each channel (for example, the channel’s actual name in Slack), and map it to the corresponding channel ID.

  2. To locate a channel ID, open the channel in Slack, click the channel name at the top, and scroll to the About section. The channel ID is shown at the bottom of this section.

  1. The channel name should be included in the monitor’s Metadata Labels, or you can fall back to a default. See the channel_id attribute in the workflow example.

  2. Finally, replace the integration name in {{ providers.slack-routing-webhook }} with the actual name of the Webhook integration you created.

workflow:
  id: slack-channel-routing-workflow
  description: workflow for all channels with dynamic routing
  triggers:
  - type: alert
    filters:
    - key: annotations.slack-channel-routing-workflow
      value: enabled
  name: slack-channel-routing-workflow
  consts:
    channels: '{"devops":"C0111111111", "alerts":"C0222222222", "incidents":"C0333333333"}'
    channel_id: keep.dictget( '{{ consts.channels }}', '{{ alert.labels.channel_id }}', 'C09G9AFHLTB')
    env: keep.dictget({{ alert.labels }}, 'env', 'no-env')
    upper_env: "keep.uppercase({{consts.env}})"
    severity: keep.dictget({{ alert.annotations }}, '_gc_severity', 'unknown-severity')
    summary: keep.dictget({{ alert.labels }}, 'summary', 'no-summary')
    slack_message: "<https://app.groundcover.com/monitors/create-silence?keep.replace(keep.join(keep.dict_pop({{ alert.labels }}, \"_gc_monitor_id\", \"_gc_monitor_name\", \"_gc_severity\", \"backend_id\", \"grafana_folder\", \"_gc_issue_header\"), \"&\", \"matcher_\"), \" \", \"+\")|Silence> :no_bell: | \n<https://app.groundcover.com/monitors/issues?backendId={{ alert.labels.backend_id }}&selectedObjectId={{ alert.fingerprint }}|Investigate> :mag: | \n<https://app.groundcover.com/monitors?backendId={{ alert.labels.backend_id }}&selectedObjectId={{ alert.labels._gc_monitor_id }}|See Monitor> :chart_with_upwards_trend:\n\n*Labels:*  \n- keep.join(keep.dict_pop({{alert.labels}}, \"_gc_monitor_id\", \"_gc_monitor_name\", \"_gc_severity\", \"backend_id\", \"grafana_folder\", \"_gc_issue_header\"), \"\\n- \")\n"
    title_link: "https://app.groundcover.com/monitors/issues?backendId={{ alert.labels.backend_id }}&selectedObjectId={{ alert.fingerprint }}"
    red_color: "#FF0000"
    green_color: "#008000"
    footer_url: "groundcover.com"
    footer_icon: "https://app.groundcover.com/favicon.ico"
  actions:
  - if: "{{ alert.status }} == 'firing'"
    name: webhook-alert
    provider:
      type: webhook
      config: "{{ providers.slack-routing-webhook }}"
      with:
        body:
          channel: "{{ consts.channel_id }}"
          attachments:
          - color: "{{ consts.red_color }}"
            footer: "{{ consts.footer_url }}"
            footer_icon: "{{ consts.footer_icon }}"
            text: "{{ consts.slack_message }}"
            title: "\U0001F6A8 Firing: {{ alert.alertname }} [{{ consts.upper_env}}]"
            title_link: "{{ consts.title_link }}"
            type: plain_text
  - if: "{{ alert.status }} != 'firing'"
    name: webhook-alert-resolved
    provider:
      type: webhook
      config: "{{ providers.slack-routing-webhook }}"
      with:
        body:
          channel: "{{ consts.channel_id }}"
          text: "\u2705 [RESOLVED][{{ consts.upper_env}}] {{ consts.severity }} {{ alert.alertname }}"
          attachments:
          - color: "{{ consts.green_color }}"
            text: "*Summary:* {{ consts.summary }}"
            fields:
            - title: "Environment"
              value: "{{ consts.upper_env}}"
              short: true
            footer: "{{ consts.footer_url }}"
            footer_icon: "{{ consts.footer_icon }}"

Last updated