Slack Bildirimi Gönderme: Webhook Entegrasyonu

Sistem yöneticilerinin en sık karşılaştığı sorunlardan biri şu: Bir şeyler bozulduğunda ya da önemli bir olay gerçekleştiğinde, doğru kişiye zamanında haber ulaştırmak. E-posta artık bu iş için çok yavaş. PagerDuty gibi araçlar ise küçük ekipler için fazla karmaşık ve pahalı olabiliyor. Slack webhook entegrasyonu tam bu noktada devreye giriyor: Birkaç satır kod ile sunucularınızdan, CI/CD pipeline’larınızdan veya herhangi bir script’ten doğrudan Slack kanalınıza mesaj gönderebilirsiniz.

Bu yazıda Slack Incoming Webhook yapısını sıfırdan kuracak, bash script’lerinden Python’a kadar farklı senaryolarda nasıl kullanacağınızı görecek ve gerçek dünya monitoring entegrasyonlarını ele alacağız.

Slack Webhook Nedir ve Nasıl Çalışır

Incoming Webhook, Slack’in dışarıdan mesaj almak için sağladığı bir HTTP endpoint’idir. Siz bu URL’ye bir POST isteği gönderirsiniz, Slack da mesajı belirlediğiniz kanala iletir. OAuth token’ı yönetmenize gerek yok, karmaşık bir API akışı yok. Sadece bir URL ve JSON payload yeterli.

Webhook URL’si şöyle görünür:

https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

Bu URL üç bölümden oluşuyor: workspace ID, channel ID ve güvenlik token’ı. Bu URL’yi kimseyle paylaşmayın, versiyon kontrolüne eklemeyin. Sızdırırsanız herkes sizin kanalınıza mesaj gönderebilir.

Webhook Oluşturma: Adım Adım

Önce Slack tarafında webhook’u oluşturmamız gerekiyor.

Adım 1: Slack App Oluşturma

  • [api.slack.com/apps](https://api.slack.com/apps) adresine gidin
  • “Create New App” butonuna tıklayın
  • “From scratch” seçeneğini seçin
  • App adı girin (örneğin: “ServerBot” veya “Infrastructure Alerts”)
  • Workspace’inizi seçin

Adım 2: Incoming Webhooks’u Aktifleştirme

  • Sol menüden “Incoming Webhooks” bölümüne girin
  • Toggle’ı “On” pozisyonuna alın
  • Sayfanın altına kaydırın ve “Add New Webhook to Workspace” butonuna tıklayın
  • Hangi kanala mesaj göndereceğinizi seçin (örneğin: #alerts, #infrastructure)
  • “Allow” butonuna tıklayın

Artık bir webhook URL’niz var. Bu URL’yi kopyalayıp güvenli bir yere kaydedin.

Adım 3: Test Edin

Hemen terminalden test edelim:

WEBHOOK_URL="https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX"

curl -X POST -H 'Content-type: application/json' 
  --data '{"text":"Merhaba! Bu bir test mesajidir."}' 
  "$WEBHOOK_URL"

Eğer Slack kanalınıza mesaj geldiyse, her şey çalışıyor demektir. ok cevabı aldıysanız istek başarılı olmuştur.

Temel Bash Script ile Bildirim Gönderme

Günlük sysadmin işlerinde en çok bash kullanacaksınız. İşte yeniden kullanılabilir bir Slack bildirim fonksiyonu:

#!/bin/bash

# Slack webhook URL'sini environment variable olarak tutun
SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:-}"

send_slack_message() {
    local message="$1"
    local channel="${2:-}"  # Bos birakilirsa webhook'un varsayilan kanali kullanilir
    local username="${3:-ServerBot}"
    local emoji="${4:-:robot_face:}"

    if [[ -z "$SLACK_WEBHOOK_URL" ]]; then
        echo "HATA: SLACK_WEBHOOK_URL environment variable tanimli degil!" >&2
        return 1
    fi

    local payload
    payload=$(cat <<EOF
{
    "username": "${username}",
    "icon_emoji": "${emoji}",
    "text": "${message}"
}
EOF
)

    local response
    response=$(curl -s -o /dev/null -w "%{http_code}" 
        -X POST 
        -H 'Content-type: application/json' 
        --data "$payload" 
        "$SLACK_WEBHOOK_URL")

    if [[ "$response" != "200" ]]; then
        echo "HATA: Slack mesaji gonderilemedi. HTTP kod: $response" >&2
        return 1
    fi

    return 0
}

# Kullanim ornekleri
send_slack_message "Sunucu yedeklemesi tamamlandi."
send_slack_message ":warning: Disk dolulugu %85'i gecti!" "" "AlertBot" ":warning:"
send_slack_message ":white_check_mark: Deploy basariyla tamamlandi."

Bu fonksiyonu /etc/profile.d/slack_notify.sh dosyasına eklerseniz tüm scriptlerinizden çağırabilirsiniz.

Disk Alanı Monitörü: Gerçek Dünya Senaryosu

Pratik bir örnek yapalım. Disk kullanımı belirli bir eşiği aştığında otomatik Slack bildirimi gönderen script:

#!/bin/bash
# /usr/local/bin/disk_monitor.sh
# Cron ile her saat calistirin: 0 * * * * /usr/local/bin/disk_monitor.sh

SLACK_WEBHOOK_URL="https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX"
HOSTNAME=$(hostname -f)
THRESHOLD=80
CRITICAL_THRESHOLD=90

send_alert() {
    local mount_point="$1"
    local usage_percent="$2"
    local severity="$3"
    local emoji color

    if [[ "$severity" == "critical" ]]; then
        emoji=":rotating_light:"
        color="danger"
    else
        emoji=":warning:"
        color="warning"
    fi

    local payload
    payload=$(cat <<EOF
{
    "attachments": [
        {
            "color": "${color}",
            "title": "${emoji} Disk Alani Uyarisi - ${HOSTNAME}",
            "fields": [
                {
                    "title": "Sunucu",
                    "value": "${HOSTNAME}",
                    "short": true
                },
                {
                    "title": "Mount Point",
                    "value": "${mount_point}",
                    "short": true
                },
                {
                    "title": "Kullanim",
                    "value": "%${usage_percent}",
                    "short": true
                },
                {
                    "title": "Onem Seviyesi",
                    "value": "${severity^^}",
                    "short": true
                }
            ],
            "footer": "Disk Monitor",
            "ts": $(date +%s)
        }
    ]
}
EOF
)

    curl -s -X POST 
        -H 'Content-type: application/json' 
        --data "$payload" 
        "$SLACK_WEBHOOK_URL" > /dev/null
}

# Disk kullanim kontrolu
while IFS= read -r line; do
    usage=$(echo "$line" | awk '{print $5}' | tr -d '%')
    mount=$(echo "$line" | awk '{print $6}')

    if [[ "$usage" -ge "$CRITICAL_THRESHOLD" ]]; then
        send_alert "$mount" "$usage" "critical"
    elif [[ "$usage" -ge "$THRESHOLD" ]]; then
        send_alert "$mount" "$usage" "warning"
    fi
done < <(df -h | grep -v "^Filesystem" | grep -v "tmpfs")

Bu script’i crontab’a ekleyin:

# Her saat basi calistir
0 * * * * /usr/local/bin/disk_monitor.sh

# Ya da sudo ile
sudo crontab -e

Block Kit ile Zengin Mesajlar

Slack’in Block Kit formatını kullanarak çok daha okunaklı ve görsel mesajlar gönderebilirsiniz. Block Kit, mesajı bölümlere ayırmanıza, buton eklemenize ve bilgileri düzenli şekilde sunmanıza olanak tanıyor.

#!/bin/bash
# Deploy bildirimi - Block Kit kullanimi

SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL}"
DEPLOY_ENV="${1:-production}"
APP_NAME="${2:-myapp}"
VERSION="${3:-latest}"
DEPLOY_USER=$(whoami)
DEPLOY_TIME=$(date '+%d.%m.%Y %H:%M:%S')

send_deploy_notification() {
    local status="$1"  # success veya failure
    local details="$2"

    local header_emoji status_text color
    if [[ "$status" == "success" ]]; then
        header_emoji=":white_check_mark:"
        status_text="BASARILI"
        color="#36a64f"
    else
        header_emoji=":x:"
        status_text="BASARISIZ"
        color="#ff0000"
    fi

    cat <<EOF | curl -s -X POST -H 'Content-type: application/json' -d @- "$SLACK_WEBHOOK_URL"
{
    "blocks": [
        {
            "type": "header",
            "text": {
                "type": "plain_text",
                "text": "${header_emoji} Deploy ${status_text}: ${APP_NAME}"
            }
        },
        {
            "type": "section",
            "fields": [
                {
                    "type": "mrkdwn",
                    "text": "*Uygulama:*n${APP_NAME}"
                },
                {
                    "type": "mrkdwn",
                    "text": "*Versiyon:*n${VERSION}"
                },
                {
                    "type": "mrkdwn",
                    "text": "*Ortam:*n${DEPLOY_ENV}"
                },
                {
                    "type": "mrkdwn",
                    "text": "*Yapan:*n${DEPLOY_USER}"
                },
                {
                    "type": "mrkdwn",
                    "text": "*Zaman:*n${DEPLOY_TIME}"
                }
            ]
        },
        {
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text": "*Detaylar:*n```${details}```"
            }
        },
        {
            "type": "divider"
        }
    ]
}
EOF
}

# Kullanim
send_deploy_notification "success" "Docker image build edildi ve Kubernetes'e deploy edildi."

Python ile Gelişmiş Webhook Entegrasyonu

Daha karmaşık senaryolar için Python çok daha esneklik sunuyor. Özellikle hata yönetimi ve retry mekanizması için:

#!/usr/bin/env python3
# slack_notifier.py

import json
import os
import time
import urllib.request
import urllib.error
from datetime import datetime
from typing import Optional


class SlackNotifier:
    def __init__(self, webhook_url: Optional[str] = None):
        self.webhook_url = webhook_url or os.environ.get("SLACK_WEBHOOK_URL")
        if not self.webhook_url:
            raise ValueError("Slack webhook URL tanimli degil!")
        self.max_retries = 3
        self.retry_delay = 5

    def send(self, message: str, emoji: str = ":robot_face:",
             username: str = "ServerBot") -> bool:
        payload = {
            "text": message,
            "username": username,
            "icon_emoji": emoji
        }
        return self._post(payload)

    def send_alert(self, title: str, message: str, severity: str = "warning",
                   fields: Optional[dict] = None) -> bool:
        color_map = {
            "info": "#36a64f",
            "warning": "#ffaa00",
            "critical": "#ff0000",
            "success": "#36a64f"
        }

        attachment = {
            "color": color_map.get(severity, "#cccccc"),
            "title": title,
            "text": message,
            "fields": [],
            "footer": f"Alert System | {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}",
            "ts": int(time.time())
        }

        if fields:
            for key, value in fields.items():
                attachment["fields"].append({
                    "title": key,
                    "value": str(value),
                    "short": True
                })

        payload = {"attachments": [attachment]}
        return self._post(payload)

    def _post(self, payload: dict) -> bool:
        data = json.dumps(payload).encode("utf-8")
        req = urllib.request.Request(
            self.webhook_url,
            data=data,
            headers={"Content-Type": "application/json"}
        )

        for attempt in range(1, self.max_retries + 1):
            try:
                with urllib.request.urlopen(req, timeout=10) as response:
                    if response.status == 200:
                        return True
            except urllib.error.HTTPError as e:
                print(f"HTTP Hata ({attempt}/{self.max_retries}): {e.code} - {e.reason}")
            except urllib.error.URLError as e:
                print(f"URL Hata ({attempt}/{self.max_retries}): {e.reason}")
            except Exception as e:
                print(f"Beklenmeyen hata ({attempt}/{self.max_retries}): {e}")

            if attempt < self.max_retries:
                time.sleep(self.retry_delay * attempt)

        return False


# Kullanim ornegi
if __name__ == "__main__":
    notifier = SlackNotifier()

    # Basit mesaj
    notifier.send(":wave: Python notifier baslatildi!")

    # Alert mesaji
    notifier.send_alert(
        title="Yuksek CPU Kullanimi",
        message="web-server-01 sunucusunda CPU kullanimi kritik seviyeye ulasti.",
        severity="critical",
        fields={
            "Sunucu": "web-server-01",
            "CPU Kullanimi": "%94",
            "Surec": "nginx worker",
            "PID": "12847"
        }
    )

Webhook URL’sini Güvenli Saklama

Webhook URL’sini script içine yazmak büyük bir güvenlik açığıdır. Doğru yöntemler şunlardır:

Environment Variable ile:

# /etc/environment dosyasina ekleyin (sistem geneli)
echo 'SLACK_WEBHOOK_URL="https://hooks.slack.com/services/T00000/B00000/XXXXX"' >> /etc/environment

# Ya da cron icin /etc/cron.d/ altindaki dosyaya:
# SLACK_WEBHOOK_URL=https://hooks.slack.com/...
# 0 * * * * root /usr/local/bin/disk_monitor.sh

# Script icinde kullanim:
WEBHOOK="${SLACK_WEBHOOK_URL:?Slack webhook URL tanimli degil!}"

Ayrı Konfigürasyon Dosyası ile:

# /etc/slack-notify.conf (sadece root okuyabilsin)
# chmod 600 /etc/slack-notify.conf
# chown root:root /etc/slack-notify.conf

cat > /etc/slack-notify.conf << 'EOF'
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/T00000/B00000/XXXXX"
SLACK_DEFAULT_CHANNEL="#alerts"
SLACK_USERNAME="ServerBot"
EOF

chmod 600 /etc/slack-notify.conf

# Script icinde kullanim:
source /etc/slack-notify.conf

Systemd Service ile:

# /etc/systemd/system/myapp.service dosyasina
[Service]
EnvironmentFile=/etc/myapp/secrets
ExecStart=/usr/local/bin/myapp

Logrotate Post-Action Bildirimi

Log rotasyonu tamamlandığında bildirim göndermek için:

# /etc/logrotate.d/nginx dosyasina eklenecek
/var/log/nginx/*.log {
    daily
    rotate 14
    compress
    postrotate
        SLACK_WEBHOOK_URL=$(cat /etc/slack-notify.conf | grep SLACK_WEBHOOK | cut -d'"' -f2)
        LOG_SIZE=$(du -sh /var/log/nginx/ | cut -f1)
        curl -s -X POST -H 'Content-type: application/json' 
            --data "{"text":":arrows_counterclockwise: Nginx log rotasyonu tamamlandi. Toplam log boyutu: ${LOG_SIZE}"}" 
            "$SLACK_WEBHOOK_URL" > /dev/null 2>&1
    endscript
}

Webhook Hata Ayıklama ve Sorun Giderme

Bir şeyler yanlış gittiğinde nereye bakmalısınız:

HTTP 400 – Bad Request: JSON formatınız hatalıdır. Payload’ı validate edin:

# JSON payload'i dogrula
echo '{"text": "test"}' | python3 -m json.tool

# Verbose curl ile detayli hata gorme
curl -v -X POST -H 'Content-type: application/json' 
    --data '{"text":"test"}' 
    "$SLACK_WEBHOOK_URL" 2>&1

HTTP 403 – Forbidden: Webhook URL geçersiz veya iptal edilmiştir. Slack admin panelinden yeni webhook oluşturun.

HTTP 429 – Too Many Requests: Rate limit’e takıldınız. Slack Incoming Webhooks için saniyede 1 mesaj sınırı var. Script’inize bekleme ekleyin:

# Rate limiting icin mesajlar arasina bekleme ekle
send_bulk_notifications() {
    local messages=("$@")
    for msg in "${messages[@]}"; do
        send_slack_message "$msg"
        sleep 1  # Rate limit: saniyede 1 mesaj
    done
}

“no_service” hatası: Webhook URL’nizin üçüncü bölümündeki token yanlış veya eksik.

SSL sertifika hatası: Eski sistemlerde ca-certificates paketi güncel olmayabilir:

# Ubuntu/Debian
sudo apt-get update && sudo apt-get install ca-certificates

# CentOS/RHEL
sudo yum update ca-certificates

# curl ile SSL dogrulamayi gecici devre disi birakmak (SADECE test icin!)
curl -k -X POST ...

Monitoring Entegrasyonu: Cronjob ile Periyodik Kontroller

Tüm öğrendiklerimizi birleştiren kapsamlı bir sistem health check scripti:

#!/bin/bash
# /usr/local/bin/system_health_check.sh
# Her 5 dakikada bir calistir: */5 * * * * root /usr/local/bin/system_health_check.sh

source /etc/slack-notify.conf

HOSTNAME=$(hostname -f)
ALERTS=()
ALERT_SENT=false

# CPU kontrolu
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1 | cut -d',' -f1)
CPU_INT=${CPU_USAGE%.*}
if [[ "$CPU_INT" -gt 90 ]]; then
    ALERTS+=(":fire: CPU kullanimi: %${CPU_INT}")
fi

# RAM kontrolu
RAM_USAGE=$(free | awk '/Mem/{printf("%.0f", $3/$2*100)}')
if [[ "$RAM_USAGE" -gt 85 ]]; then
    ALERTS+=(":warning: RAM kullanimi: %${RAM_USAGE}")
fi

# Load average kontrolu
LOAD_AVG=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | tr -d ',')
CPU_COUNT=$(nproc)
LOAD_INT=${LOAD_AVG%.*}
if [[ "$LOAD_INT" -gt "$CPU_COUNT" ]]; then
    ALERTS+=(":chart_with_upwards_trend: Yuksek load average: ${LOAD_AVG} (${CPU_COUNT} CPU)")
fi

# Kritik servis kontrolu
SERVICES=("nginx" "mysql" "redis")
for service in "${SERVICES[@]}"; do
    if ! systemctl is-active --quiet "$service" 2>/dev/null; then
        ALERTS+=(":rotating_light: ${service} servisi calismiyor!")
    fi
done

# Alert varsa gonder
if [[ "${#ALERTS[@]}" -gt 0 ]]; then
    ALERT_TEXT="*:hospital: ${HOSTNAME} - Sistem Uyarilari*n"
    for alert in "${ALERTS[@]}"; do
        ALERT_TEXT+="• ${alert}n"
    done
    ALERT_TEXT+="n_$(date '+%d.%m.%Y %H:%M:%S')_"

    curl -s -X POST -H 'Content-type: application/json' 
        --data "{"text":"${ALERT_TEXT}"}" 
        "$SLACK_WEBHOOK_URL" > /dev/null

    ALERT_SENT=true
fi

exit 0

Pratik İpuçları ve En İyi Uygulamalar

Webhook entegrasyonlarınızda dikkat etmeniz gereken birkaç önemli nokta var.

Kanal stratejisi belirleyin: Her şeyi tek bir kanala göndermek yerine, önem seviyesine göre farklı webhook’lar oluşturun. #alerts-critical sadece acil durumlar için, #alerts-info ise rutin bildirimler için kullanılabilir.

Mesaj deduplication uygulayın: Aynı hatayı her dakika göndermek yerine, gönderilen uyarıları lock dosyasıyla takip edin:

LOCK_FILE="/tmp/slack_disk_alert_$(echo $mount_point | tr '/' '_').lock"
# Lock dosyasi son 4 saatten eskiyse alert gonder
if [[ ! -f "$LOCK_FILE" ]] || [[ $(find "$LOCK_FILE" -mmin +240 2>/dev/null) ]]; then
    send_alert "$mount" "$usage" "warning"
    touch "$LOCK_FILE"
fi

Tüm Slack mesajlarını logla: Bir şeyler ters gittiğinde geriye dönüp bakabilmek için:

LOG_FILE="/var/log/slack-notifications.log"
log_and_send() {
    local message="$1"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $message" >> "$LOG_FILE"
    send_slack_message "$message"
}

Timeout ekleyin: Ağ sorunlarında scriptlerinizin takılıp kalmaması için curl komutlarınıza her zaman --max-time ve --connect-timeout parametresi ekleyin:

curl --max-time 10 --connect-timeout 5 
    -s -X POST -H 'Content-type: application/json' 
    --data "$payload" "$SLACK_WEBHOOK_URL"

Sonuç

Slack webhook entegrasyonu, sysadmin araç kutunuzun vazgeçilmez bir parçası olmalı. Birkaç satır bash veya Python kodu ile monitoring sistemleriniz, cron job’larınız ve deployment pipeline’larınız artık sessizce değil, sesli çalışmaya başlıyor. Bir disk dolduğunda, bir servis çöktüğünde veya bir deploy tamamlandığında anında haberdar olmak; sorunları kullanıcılar fark etmeden çözmenizi sağlıyor.

Başlamak için karmaşık bir kuruluma ihtiyacınız yok: Slack’te bir app oluşturun, webhook URL’nizi alın ve ilk curl komutunuzu çalıştırın. Ardından bu yazıdaki örnekleri kendi altyapınıza göre uyarlayın. Disk monitor’den başlayın, çalıştığını gördükten sonra servisleri, load average’ı ve deployment süreçlerini ekleyin. Zamanla tüm kritik olaylarınızın Slack’te toplandığını ve ekibinizin çok daha hızlı tepki verdiğini göreceksiniz.

Son olarak şunu unutmayın: Webhook URL’nizi güvende tutun. Bu URL sızdığında, yapılandırma yönetim sisteminizden yenisini hızlıca oluşturup dağıtabilmeniz için webhook URL’lerini merkezi bir secrets yönetim aracında (HashiCorp Vault, AWS Secrets Manager veya en azından şifrelenmiş bir dosyada) tutma alışkanlığı edinin.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir