feat(phase-5-3): Logger, Metrics, 알림 시스템 통합

Phase 5-3 모니터링 강화 작업의 통합을 완료했습니다.

변경사항:
- Logger 통합: console.log를 구조화된 로깅으로 전환 (9개 파일)
  - JSON 기반 로그, 환경별 자동 전환 (개발/프로덕션)
  - 타입 안전성 보장, 성능 측정 타이머 내장

- Metrics 통합: 실시간 성능 모니터링 시스템 연결 (3개 파일)
  - Circuit Breaker 상태 추적 (api_call_count, error_count, state)
  - Retry 재시도 횟수 추적 (retry_count)
  - OpenAI API 응답 시간 측정 (api_call_duration)

- 알림 통합: 장애 자동 알림 시스템 구현 (2개 파일)
  - Circuit Breaker OPEN 상태 → 관리자 Telegram 알림
  - 재시도 실패 → 관리자 Telegram 알림
  - Rate Limiting 적용 (1시간에 1회)

- 문서 업데이트:
  - CLAUDE.md: coder 에이전트 설명 강화 (20년+ 시니어 전문가)
  - README.md, docs/: 아키텍처 문서 추가

영향받은 파일: 16개 (수정 14개, 신규 2개)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-19 21:23:38 +09:00
parent 410676e322
commit eee934391a
16 changed files with 675 additions and 777 deletions

View File

@@ -1,5 +1,8 @@
import type { Env } from '../types';
import { retryWithBackoff, RetryError } from '../utils/retry';
import { createLogger } from '../utils/logger';
const logger = createLogger('search-tool');
// Cloudflare AI Gateway를 통해 OpenAI API 호출 (지역 제한 우회)
const OPENAI_API_URL = 'https://gateway.ai.cloudflare.com/v1/d8e5997eb4040f8b489f09095c0f623c/telegram-bot/openai/chat/completions';
@@ -86,12 +89,12 @@ export async function executeSearchWeb(args: { query: string }, env?: Env): Prom
if (translateRes.ok) {
const translateData = await translateRes.json() as any;
translatedQuery = translateData.choices?.[0]?.message?.content?.trim() || query;
console.log(`[search_web] 번역: "${query}" → "${translatedQuery}"`);
logger.info('번역', { original: query, translated: translatedQuery });
}
} catch (error) {
// 번역 실패 시 원본 사용 (RetryError 포함)
if (error instanceof RetryError) {
console.log(`[search_web] 번역 재시도 실패, 원본 사용: ${error.message}`);
logger.info('번역 재시도 실패, 원본 사용', { message: error.message });
}
}
}
@@ -130,7 +133,7 @@ export async function executeSearchWeb(args: { query: string }, env?: Env): Prom
return `🔍 검색 결과: ${queryDisplay}\n\n${results}`;
} catch (error) {
console.error('[search_web] 오류:', error);
logger.error('오류', error as Error);
if (error instanceof RetryError) {
return `🔍 검색 서비스에 일시적으로 접근할 수 없습니다. 잠시 후 다시 시도해주세요.`;
}
@@ -171,7 +174,7 @@ export async function executeLookupDocs(args: { library: string; query: string }
const content = docsData.context || docsData.content || JSON.stringify(docsData, null, 2);
return `📚 ${library} 문서 (${query}):\n\n${content.slice(0, 1500)}`;
} catch (error) {
console.error('[lookup_docs] 오류:', error);
logger.error('오류', error as Error);
if (error instanceof RetryError) {
return `📚 문서 조회 서비스에 일시적으로 접근할 수 없습니다. 잠시 후 다시 시도해주세요.`;
}