AWS CloudWatch Log Grubu Yönetimi
CloudWatch loglarını düzgün yönetmeden AWS üzerinde ciddi bir operasyon yürütmek, gözleri kapalı araba kullanmak gibidir. Bir süre gider, sonra bir yere çarparsın. Özellikle mikroservis mimarisine geçen ekiplerin en çok şikayet ettiği konulardan biri log kaosudur: onlarca log grubu, belirsiz saklama süreleri, şişen maliyetler ve arama yapılamaz hale gelen loglar. Bu yazıda CloudWatch Log Grubu yönetimini sıfırdan ele alacağız; sadece teorik değil, gerçek dünya senaryolarıyla birlikte.
CloudWatch Log Grubu Nedir ve Neden Önemlidir
AWS CloudWatch Logs, uygulamalarından, EC2 instance’larından, Lambda fonksiyonlarından ve diğer AWS servislerinden gelen logları merkezi bir yerde toplamanı sağlar. Log Grubu, bu log yapısının en üst katmanıdır. Her log grubunun altında log stream’ler bulunur ve her stream, belirli bir kaynaktan (örneğin tek bir EC2 instance ya da Lambda invocation) gelen log satırlarını içerir.
Bir log grubunu doğru yapılandırmazsan karşılaşacağın sorunlar şunlardır:
- Saklama süresi tanımlanmamış log grupları sonsuza kadar veri tutar, fatura şişer
- IAM izinleri doğru ayarlanmazsa yanlış ekipler yanlış loglara erişir
- Metrik filter’lar tanımlanmazsa kritik hatalar sessiz sedasız geçer
- Şifreleme yapılandırılmazsa compliance gereksinimleri karşılanamaz
AWS CLI ile Log Grupları Oluşturma ve Listeleme
Önce temel operasyonlardan başlayalım. AWS CLI, log grubu yönetiminde en hızlı ve scriptlenebilir araçtır.
Mevcut log gruplarını listelemek için:
# Tüm log gruplarını listele
aws logs describe-log-groups
--region eu-west-1
--output table
# Belirli bir prefix ile filtrele
aws logs describe-log-groups
--log-group-name-prefix "/aws/lambda/"
--region eu-west-1
--query 'logGroups[*].{Name:logGroupName,RetentionDays:retentionInDays,StoredBytes:storedBytes}'
Yeni bir log grubu oluşturmak:
# Basit log grubu oluşturma
aws logs create-log-group
--log-group-name "/myapp/production/api"
--region eu-west-1
# Tag'lerle birlikte oluşturma
aws logs create-log-group
--log-group-name "/myapp/production/api"
--tags '{"Environment":"production","Team":"backend","Project":"myapp"}'
--region eu-west-1
Tag’ler, maliyet takibi açısından hayat kurtarıcıdır. Özellikle birden fazla ekibin aynı AWS hesabını kullandığı ortamlarda hangi log grubunun kime ait olduğunu tag’ler sayesinde anlarız.
Saklama Süresi Yönetimi
Saklama süresi (retention) ayarlamak, CloudWatch maliyetlerini düşürmenin en etkili yoludur. Varsayılan olarak log grupları sonsuz saklama süresine sahiptir. Bunu fark etmeden bırakmak, aylar sonra beklenmedik bir faturayla karşılaşmak demektir.
# Saklama süresini 30 gün olarak ayarla
aws logs put-retention-policy
--log-group-name "/myapp/production/api"
--retention-in-days 30
--region eu-west-1
# Saklama süresini kaldır (sonsuz saklama)
aws logs delete-retention-policy
--log-group-name "/myapp/production/api"
--region eu-west-1
CloudWatch’ın desteklediği saklama süreleri belirli değerlerle sınırlıdır. Bunlar şunlardır:
- 1, 3, 5, 7 gün: Kısa süreli debug logları için
- 14, 30 gün: Genel uygulama logları için
- 60, 90 gün: Orta vadeli iş logları için
- 120, 150, 180 gün: Compliance gereksinimleri olan sistemler için
- 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653 gün: Uzun vadeli arşiv
Gerçek dünya senaryosu olarak şunu düşün: Bir e-ticaret platformu yönetiyorsun. Ödeme işlemleriyle ilgili logları en az 1 yıl tutman gerekebilir (PCI-DSS), ama debug loglarını 7 günden fazla tutmanın hiçbir anlamı yok.
Tüm Log Gruplarına Toplu Saklama Süresi Atama
Yüzlerce log grubunuz varsa tek tek elle ayarlamak yerine bir script yazarız:
#!/bin/bash
# Saklama süresi tanımlanmamış tüm log gruplarına 90 gün ata
REGION="eu-west-1"
DEFAULT_RETENTION=90
aws logs describe-log-groups
--region "$REGION"
--query 'logGroups[?retentionInDays==`null`].logGroupName'
--output text | tr 't' 'n' | while read -r LOG_GROUP; do
echo "Ayarlaniyor: $LOG_GROUP"
aws logs put-retention-policy
--log-group-name "$LOG_GROUP"
--retention-in-days "$DEFAULT_RETENTION"
--region "$REGION"
echo "Tamam: $LOG_GROUP -> ${DEFAULT_RETENTION} gun"
done
Bu script’i bir cron job’a bağlayarak yeni oluşturulan log gruplarını da otomatik olarak yakalayabilirsin.
KMS ile Log Grubu Şifreleme
Hassas veri işleyen uygulamalarda log verilerini KMS ile şifrelemek hem güvenlik hem de compliance açısından zorunludur.
# Önce KMS key ARN'ini al
KEY_ARN=$(aws kms describe-key
--key-id alias/cloudwatch-logs
--query 'KeyMetadata.Arn'
--output text)
# Log grubunu KMS ile şifrele
aws logs associate-kms-key
--log-group-name "/myapp/production/api"
--kms-key-id "$KEY_ARN"
--region eu-west-1
# Şifrelemeyi kaldır
aws logs disassociate-kms-key
--log-group-name "/myapp/production/api"
--region eu-west-1
KMS key policy’sinde CloudWatch Logs servisine gerekli izinleri vermeden bu işlem hata verir. Key policy’ye şunu eklemelisin:
# KMS key policy'sine CloudWatch Logs iznini ekle
aws kms put-key-policy
--key-id alias/cloudwatch-logs
--policy-name default
--policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "logs.eu-west-1.amazonaws.com"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey",
"kms:Describe*"
],
"Resource": "*",
"Condition": {
"ArnLike": {
"kms:EncryptionContext:aws:logs:arn": "arn:aws:logs:eu-west-1:123456789012:*"
}
}
}
]
}'
Metrik Filter ve Alarm Tanımlama
Log gruplarının en güçlü özelliklerinden biri metrik filter’lardır. Log satırlarındaki belirli desenleri yakalayıp CloudWatch metriğine dönüştürebilirsin, ardından bu metriğe alarm kurabilirsin.
# HTTP 500 hatalarını yakalamak için metrik filter oluştur
aws logs put-metric-filter
--log-group-name "/myapp/production/api"
--filter-name "HTTP500Errors"
--filter-pattern "[timestamp, requestId, level=ERROR, statusCode=500, ...]"
--metric-transformations
metricName=HTTP500ErrorCount,
metricNamespace=MyApp/API,
metricValue=1,
defaultValue=0
--region eu-west-1
# Oluşturulan filter'ları listele
aws logs describe-metric-filters
--log-group-name "/myapp/production/api"
--region eu-west-1
Bu metriğe alarm kurarak SNS ile bildirim alabilirsin:
# Alarm oluştur
aws cloudwatch put-metric-alarm
--alarm-name "MyApp-HTTP500-High"
--alarm-description "5 dakikada 10'dan fazla HTTP 500 hatasi"
--metric-name "HTTP500ErrorCount"
--namespace "MyApp/API"
--statistic Sum
--period 300
--threshold 10
--comparison-operator GreaterThanOrEqualToThreshold
--evaluation-periods 1
--alarm-actions "arn:aws:sns:eu-west-1:123456789012:alerts-topic"
--region eu-west-1
Bu kombinasyon sayesinde loglar sadece depolama alanı değil, gerçek anlamda bir monitoring aracına dönüşür.
Log Gruplarını S3’e Export Etme
Uzun süreli arşivleme için logları S3’e export etmek hem daha ucuzdur hem de başka sistemlerle entegrasyonu kolaylaştırır.
#!/bin/bash
# Log grubunu S3'e export et
LOG_GROUP="/myapp/production/api"
S3_BUCKET="myapp-log-archive"
REGION="eu-west-1"
# Export task başlat (Unix timestamp cinsinden tarih aralığı)
FROM_TIME=$(date -d "yesterday 00:00:00" +%s%3N)
TO_TIME=$(date -d "yesterday 23:59:59" +%s%3N)
DATE_STR=$(date -d "yesterday" +%Y-%m-%d)
TASK_ID=$(aws logs create-export-task
--task-name "export-${DATE_STR}"
--log-group-name "$LOG_GROUP"
--from "$FROM_TIME"
--to "$TO_TIME"
--destination "$S3_BUCKET"
--destination-prefix "logs/api/${DATE_STR}"
--region "$REGION"
--query 'taskId'
--output text)
echo "Export task baslatildi: $TASK_ID"
# Task tamamlanana kadar bekle
while true; do
STATUS=$(aws logs describe-export-tasks
--task-id "$TASK_ID"
--region "$REGION"
--query 'exportTasks[0].status.code'
--output text)
echo "Durum: $STATUS"
if [ "$STATUS" == "COMPLETED" ]; then
echo "Export basariyla tamamlandi"
break
elif [ "$STATUS" == "FAILED" ]; then
echo "Export basarisiz oldu!"
exit 1
fi
sleep 30
done
S3 bucket policy’sinde CloudWatch Logs servisine s3:GetBucketAcl ve s3:PutObject izinleri vermeden bu export işlemi başarısız olur. Bunu sıkça unutulan bir nokta olarak belirtmek gerekir.
Terraform ile Log Grubu Yönetimi
Infrastructure as Code kullanmadan log grubu yönetmek, özellikle birden fazla ortam (dev, staging, prod) varsa kaosa davet çıkarmaktır. Terraform ile log gruplarını kod olarak yönetelim:
# main.tf - CloudWatch Log Grup modülü örneği
# Bu dosyayı Terraform ile uygula: terraform apply
# Önce Terraform planını görüntüle
terraform plan -var="environment=production" -var="app_name=myapp"
# Uygula
terraform apply -var="environment=production" -var="app_name=myapp" -auto-approve
# Belirli bir log grubunu sil
terraform destroy -target=aws_cloudwatch_log_group.app_api
-var="environment=production"
-var="app_name=myapp"
Terraform resource tanımı şu şekilde olur (bu kısım HCL olmasına karşın bash bloğu içinde referans veriyoruz):
cat > cloudwatch_logs.tf << 'EOF'
resource "aws_cloudwatch_log_group" "app_api" {
name = "/myapp/${var.environment}/api"
retention_in_days = var.environment == "production" ? 365 : 30
kms_key_id = var.environment == "production" ? aws_kms_key.logs.arn : null
tags = {
Environment = var.environment
Application = var.app_name
ManagedBy = "terraform"
Team = var.team_name
}
}
resource "aws_cloudwatch_log_metric_filter" "error_filter" {
name = "error-count"
pattern = "ERROR"
log_group_name = aws_cloudwatch_log_group.app_api.name
metric_transformation {
name = "ErrorCount"
namespace = "MyApp/${var.environment}"
value = "1"
default_value = "0"
}
}
EOF
echo "Terraform dosyasi olusturuldu"
Log Grubu Sorgulama: CloudWatch Logs Insights
Log Insights, CloudWatch’ın güçlü sorgulama motorudur. AWS CLI üzerinden de kullanılabilir:
# Son 1 saatteki ERROR loglarını bul
aws logs start-query
--log-group-name "/myapp/production/api"
--start-time $(date -d "1 hour ago" +%s)
--end-time $(date +%s)
--query-string 'fields @timestamp, @message | filter @message like /ERROR/ | sort @timestamp desc | limit 50'
--region eu-west-1
# Sorgu sonuçlarını al (query-id'yi yukarıdaki komuttan al)
aws logs get-query-results
--query-id "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
--region eu-west-1
Birden fazla log grubunu aynı anda sorgulamak için:
# Tüm production log gruplarında hata ara
aws logs start-query
--log-group-names "/myapp/production/api" "/myapp/production/worker" "/myapp/production/scheduler"
--start-time $(date -d "24 hours ago" +%s)
--end-time $(date +%s)
--query-string '
fields @timestamp, @logStream, @message
| filter @message like /CRITICAL/
| stats count(*) as errorCount by @logStream
| sort errorCount desc
'
--region eu-west-1
Gerçek Dünya Senaryosu: Log Maliyeti Optimizasyonu
Bir müşteri projesinde aylık CloudWatch faturası beklenmedik şekilde 800 dolara çıkmıştı. İncelediğimizde şunları bulduk:
- 200’den fazla log grubunun saklama süresi tanımlı değildi
- Lambda’ların yarattığı log grupları temizlenmiyordu
- Bazı uygulamalar her request için ayrı satır yerine JSON blob yazıyordu, bu da sıkıştırma verimliliğini düşürüyordu
Aşağıdaki script ile önce durumu analiz ettik:
#!/bin/bash
# Log grubu maliyet analizi
REGION="eu-west-1"
echo "=== SAKLAMA SURESI TANIMLANMAMIS LOG GRUPLARI ==="
aws logs describe-log-groups
--region "$REGION"
--query 'logGroups[?retentionInDays==`null`].[logGroupName,storedBytes]'
--output text | sort -k2 -rn | head -20
echo ""
echo "=== EN BUYUK LOG GRUPLARI (TOP 10) ==="
aws logs describe-log-groups
--region "$REGION"
--query 'logGroups[*].[logGroupName,storedBytes,retentionInDays]'
--output text | sort -k2 -rn | head -10
echo ""
echo "=== TOPLAM DEPOLANAN VERI ==="
TOTAL=$(aws logs describe-log-groups
--region "$REGION"
--query 'sum(logGroups[*].storedBytes)'
--output text)
echo "Toplam: $(echo "$TOTAL / 1073741824" | bc) GB"
Bu analiz sonucunda saklama sürelerini düzenledik, kullanılmayan Lambda log gruplarını sildik ve aylık maliyet 180 dolara düştü. Yüzde 77 tasarruf.
Subscription Filter ile Log’ları Başka Servislere İletme
Log’ları gerçek zamanlı olarak Lambda, Kinesis veya başka bir servis üzerinden işlemek isteyebilirsin. Subscription filter tam bu iş için:
# Lambda'ya subscription filter ekle
aws logs put-subscription-filter
--log-group-name "/myapp/production/api"
--filter-name "SendToLambda"
--filter-pattern "ERROR"
--destination-arn "arn:aws:lambda:eu-west-1:123456789012:function:log-processor"
--region eu-west-1
# Mevcut subscription filter'ları listele
aws logs describe-subscription-filters
--log-group-name "/myapp/production/api"
--region eu-west-1
# Subscription filter'ı sil
aws logs delete-subscription-filter
--log-group-name "/myapp/production/api"
--filter-name "SendToLambda"
--region eu-west-1
Her log grubunun maksimum 1 adet subscription filter’ı olabilir. Bu kısıtlamayı aşmak için Kinesis Data Stream kullanarak birden fazla hedefe yönlendirebilirsin.
Log Grubu Silme ve Temizlik Operasyonları
Özellikle test ortamlarında biriken gereksiz log gruplarını düzenli aralıklarla temizlemek gerekir:
#!/bin/bash
# 30 gunden fazla suredir log yazilmayan gruplari sil
# DIKKAT: Uretim ortaminda calistirmadan once ciktiyi incele
REGION="eu-west-1"
DRY_RUN=true # true: sadece listele, false: sil
CUTOFF=$(date -d "30 days ago" +%s%3N)
echo "Son 30 gunde log yazilmayan gruplar:"
aws logs describe-log-groups
--region "$REGION"
--query 'logGroups[*].[logGroupName,creationTime]'
--output text | while read -r GROUP CREATION_TIME; do
LAST_EVENT=$(aws logs describe-log-streams
--log-group-name "$GROUP"
--order-by LastEventTime
--descending
--max-items 1
--region "$REGION"
--query 'logStreams[0].lastEventTimestamp'
--output text 2>/dev/null)
if [ "$LAST_EVENT" == "None" ] || [ -z "$LAST_EVENT" ]; then
LAST_EVENT="$CREATION_TIME"
fi
if [ "$LAST_EVENT" -lt "$CUTOFF" ] 2>/dev/null; then
echo "Eski: $GROUP (Son event: $LAST_EVENT)"
if [ "$DRY_RUN" == "false" ]; then
aws logs delete-log-group
--log-group-name "$GROUP"
--region "$REGION"
echo "Silindi: $GROUP"
fi
fi
done
Sonuç
CloudWatch Log Grubu yönetimi, ilk bakışta basit bir operasyon gibi görünür ama ihmal edildiğinde hem fatura hem de operasyonel sorunlara yol açar. Bu yazıda ele aldıklarımızı özetleyelim:
- Saklama süresi her log grubunda mutlaka tanımlanmalı, environment’a göre farklılaştırılmalı
- Tag stratejisi ekip, proje ve environment bazında tutarlı uygulanmalı, maliyet takibi için kritik
- KMS şifreleme hassas veri içeren log gruplarında ihmal edilmemeli
- Metrik filter ve alarmlar logları pasif depolama alanından aktif monitoring aracına dönüştürür
- Terraform veya CloudFormation ile log grupları kod olarak yönetilmeli, manuel işlemlerden kaçınılmalı
- Subscription filter’lar log verilerini gerçek zamanlı işleme imkanı sunar
- Düzenli temizlik scriptleri gereksiz log gruplarının birikmesini önler
En önemli tavsiyem şu: Yeni bir AWS hesabı veya ortamı ayağa kaldırırken log grubu yönetim politikasını en baştan belirle. Sonradan düzeltmek, baştan doğru yapmaktan çok daha maliyetlidir. Hem para hem de zaman açısından.
