Files
sam-api/app/Services/SlackNotificationService.php
권혁성 fb0155624f feat: DB 백업 시스템 구축 (Phase 1,2,4)
- Phase 1: backup.conf.example + sam-db-backup.sh 백업 스크립트
- Phase 2: BackupCheckCommand + StatMonitorService.recordBackupFailure()
- Phase 2: routes/console.php에 db:backup-check 05:00 스케줄 등록
- Phase 4: SlackNotificationService 생성 (웹훅 알림)
- Phase 4: BackupCheckCommand/StatMonitorService에 Slack 알림 연동

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 08:33:19 +09:00

136 lines
4.1 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class SlackNotificationService
{
private ?string $webhookUrl;
private string $serverName;
private bool $enabled;
public function __construct()
{
$this->webhookUrl = env('SLACK_ALERT_WEBHOOK_URL') ?: env('LOG_SLACK_WEBHOOK_URL');
$this->serverName = env('SLACK_ALERT_SERVER_NAME', config('app.env', 'unknown'));
$this->enabled = (bool) env('SLACK_ALERT_ENABLED', false);
}
/**
* 일반 알림 전송
*/
public function sendAlert(string $title, string $message, string $severity = 'critical'): void
{
$color = match ($severity) {
'critical' => '#FF0000',
'warning' => '#FFA500',
default => '#3498DB',
};
$emoji = match ($severity) {
'critical' => ':rotating_light:',
'warning' => ':warning:',
default => ':information_source:',
};
$this->send([
'attachments' => [
[
'color' => $color,
'blocks' => [
[
'type' => 'header',
'text' => [
'type' => 'plain_text',
'text' => "{$emoji} {$title}",
'emoji' => true,
],
],
[
'type' => 'section',
'fields' => [
[
'type' => 'mrkdwn',
'text' => "*서버:*\n{$this->serverName}",
],
[
'type' => 'mrkdwn',
'text' => '*시간:*\n' . now()->format('Y-m-d H:i:s'),
],
],
],
[
'type' => 'section',
'text' => [
'type' => 'mrkdwn',
'text' => "*상세:*\n{$message}",
],
],
[
'type' => 'context',
'elements' => [
[
'type' => 'mrkdwn',
'text' => "환경: `" . config('app.env') . "` | 심각도: `{$severity}`",
],
],
],
],
],
],
]);
}
/**
* 백업 실패 알림
*/
public function sendBackupAlert(string $title, string $message): void
{
$this->sendAlert("[SAM 백업 실패] {$title}", $message, 'critical');
}
/**
* 통계/모니터링 알림
*/
public function sendStatAlert(string $title, string $message, string $domain): void
{
$this->sendAlert("[SAM {$domain}] {$title}", $message, 'critical');
}
/**
* Slack 웹훅으로 메시지 전송
*/
private function send(array $payload): void
{
if (! $this->enabled) {
Log::debug('Slack 알림 비활성화 상태 (SLACK_ALERT_ENABLED=false)');
return;
}
if (empty($this->webhookUrl)) {
Log::warning('Slack 웹훅 URL 미설정');
return;
}
try {
$response = Http::timeout(10)->post($this->webhookUrl, $payload);
if (! $response->successful()) {
Log::error('Slack 알림 전송 실패', [
'status' => $response->status(),
'body' => $response->body(),
]);
}
} catch (\Throwable $e) {
Log::error('Slack 알림 전송 예외', [
'error' => $e->getMessage(),
]);
}
}
}