Skip to content

📋 מדריך מימוש מלא - ChatOps ומעקב ביצועים לבוט #808

Description

@amirbiron

📋 מדריך מימוש מלא - ChatOps ומעקב ביצועים לבוט CodeBot

📑 תוכן עניינים

  1. סקירה כללית
  2. דרישות מוקדמות
  3. דיאגרמות ארכיטקטורה
  4. ארכיטקטורה טכנית
  5. מבני נתונים ו-APIs
  6. תוכנית מימוש מדורגת
  7. מימוש מפורט לכל רכיב
  8. בדיקות ו-QA
  9. אבטחה ו-Best Practices
  10. ניטור ותחזוקה

📌 סקירה כללית

מטרת הפרויקט

הוספת יכולות ChatOps מתקדמות לבוט CodeBot, כולל:

  • 🔍 ניטור ביצועים בזמן אמת דרך הצ'אט
  • 📊 מעקב אחר מטריקות ו-KPIs
  • 🚨 התראות חכמות עם המלצות לפתרון
  • 🔎 זיהוי כפילויות בקוד
  • 🛠️ כלי triage לחקירת תקלות

יעדים עיקריים

  1. שיפור זמן תגובה לתקלות - מ-30 דקות ל-5 דקות
  2. הפחתת כפילויות קוד - זיהוי וצמצום של 20% מהכפילויות
  3. שיפור חווית משתמש - גישה מהירה למידע קריטי
  4. אוטומציה - הפחתת 50% מהזמן הנדרש לחקירת תקלות

⚙️ דרישות מוקדמות

תשתית נדרשת

requirements:
python: ">=3.11"telegram_bot: "python-telegram-bot>=20.0"database: "PostgreSQL >= 14"monitoring: - prometheus_client
- grafana (optional, for dashboards)dependencies:
- aiohttp # For async HTTP requests
- asyncpg # For async PostgreSQL
- redis # For caching and rate limiting
- structlog # For structured logging
- pydantic # For data validation

הכנות בקוד הקיים

  • Request ID Tracking - הוספת מזהה ייחודי לכל פעולה
  • Structured Logging - מעבר ללוגים מובנים עם metadata
  • Metrics Collection - הטמעת prometheus_client
  • Error Tracking - קודי שגיאה סטנדרטיים

דוגמת הטמעת Request ID:

# src/core/request_context.pyimportuuidfromcontextvarsimportContextVarfromtypingimportOptionalrequest_id_var: ContextVar[Optional[str]] =ContextVar('request_id', default=None)
classRequestContext:
@staticmethoddefset_request_id(request_id: Optional[str] =None) ->str:
"""Set or generate request ID for current context"""ifrequest_idisNone:
request_id=f"req-{uuid.uuid4().hex[:8]}"request_id_var.set(request_id)
returnrequest_id@staticmethoddefget_request_id() ->Optional[str]:
"""Get current request ID"""returnrequest_id_var.get()
# Decorator for automatic request trackingdeftrack_request(func):
asyncdefwrapper(*args, **kwargs):
request_id=RequestContext.set_request_id()
logger.info("request_started", request_id=request_id, operation=func.__name__)
try:
result=awaitfunc(*args, **kwargs)
logger.info("request_completed", request_id=request_id)
returnresultexceptExceptionase:
logger.error("request_failed", request_id=request_id, error=str(e))
raisereturnwrapper

🎨 דיאגרמות ארכיטקטורה

1. זרימת פקודה בסיסית - Command Flow

graph LR
A[User Command] --> B{Permission Check}
B -->|Authorized| C[Validate Args]
B -->|Denied| D[Error Response]
C --> E[Metrics Collection]
E --> F[Execute Command]
F --> G[Format Response]
G --> H[Send to User]
F --> I[Log Metrics]
I --> J{Alert Check}
J -->|Threshold Exceeded| K[Trigger Alert]
J -->|Normal| L[Store Metrics]
Loading

2. ארכיטקטורת המערכת הכללית - System Architecture

graph TB
subgraph "Telegram Interface"
U[User] --> TB[Telegram Bot]
end
subgraph "Command Processing Layer"
TB --> CR[Command Router]
CR --> PH[Permission Handler]
PH --> CH[Command Handlers]
end
subgraph "Core Services"
CH --> MC[Metrics Collector]
CH --> GH[GitHub API Handler]
CH --> CD[Code Analyzer]
MC --> MS[Metrics Storage]
MC --> MA[Metrics Analyzer]
end
subgraph "Storage Layer"
MS --> PG[(PostgreSQL)]
MS --> RD[(Redis Cache)]
CD --> FS[File System]
end
subgraph "Monitoring & Alerts"
MA --> AM[Alert Manager]
AM --> NS[Notification Service]
MA --> PE[Prometheus Exporter]
PE --> GD[Grafana Dashboards]
end
NS -->|Alert| TB
Loading

3. זרימת איסוף מטריקות - Metrics Collection Flow

sequenceDiagram
participant App as Application
participant RC as Request Context
participant MC as Metrics Collector
participant BQ as Batch Queue
participant BW as Batch Writer
participant DB as PostgreSQL
participant PM as Prometheus
App->>RC: Start Request
RC->>RC: Generate Request ID
RC->>MC: Track Request Start
MC->>PM: Increment Counter
App->>App: Execute Operation
alt Success
App->>MC: Track Success
MC->>PM: Update Metrics
else Error
App->>MC: Track Error
MC->>PM: Increment Error Counter
end
MC->>BQ: Queue Metric
BQ->>BW: Batch (100 items or 5s)
BW->>DB: Bulk Insert
DB-->>BW: Acknowledge
Loading

4. מערכת התראות חכמות - Smart Alert System

graph TD
subgraph "Detection Layer"
M1[Error Rate Monitor]
M2[Latency Monitor]
M3[Rate Limit Monitor]
M4[System Health Monitor]
end
subgraph "Analysis Layer"
M1 --> AE[Alert Engine]
M2 --> AE
M3 --> AE
M4 --> AE
AE --> TA{Threshold Analysis}
end
subgraph "Decision Layer"
TA -->|Critical| C[Create Alert]
TA -->|Warning| W[Create Warning]
TA -->|Normal| N[No Action]
C --> ES[Enrich with Suggestions]
W --> ES
ES --> GL[Add Grafana Links]
GL --> RP[Add Runbook]
end
subgraph "Delivery Layer"
RP --> TN[Telegram Notification]
RP --> DB[(Store Alert)]
RP --> WH[Webhook]
TN --> U[User]
end
Loading

5. זיהוי כפילויות קוד - Duplicate Detection Pipeline

graph LR
subgraph "Input"
CF[Code Files]
end
subgraph "Phase 1: Exact Matching"
CF --> NM[Normalize Code]
NM --> HG[Generate Hash]
HG --> EM[Exact Match Map]
end
subgraph "Phase 2: Fuzzy Matching"
CF --> TK[Tokenize]
TK --> MH[MinHash]
MH --> FM[Find Similar >85%]
end
subgraph "Phase 3: AST Analysis"
CF --> AP[AST Parser]
AP --> ST[Structure Tree]
ST --> SC[Structure Compare]
end
subgraph "Results"
EM --> MR[Merge Results]
FM --> MR
SC --> MR
MR --> RS[Refactor Suggestions]
RS --> RE[Report]
end
Loading

6. Triage Investigation Flow

graph TD
subgraph "Input"
RID[Request ID]
end
subgraph "Data Collection"
RID --> DG{Data Gathering}
DG --> M[Metrics]
DG --> L[Logs]
DG --> T[Traces]
DG --> RR[Related Requests]
end
subgraph "Analysis"
M --> TL[Build Timeline]
L --> TL
T --> TL
RR --> TL
TL --> RC[Root Cause Analysis]
RC --> SG[Generate Suggestions]
end
subgraph "Output"
SG --> FR[Format Report]
FR --> HTML[HTML Report]
FR --> MSG[Telegram Message]
HTML --> U[User]
MSG --> U
end
Loading

7. Database Schema Relationships

erDiagram
METRICS ||--o{ ALERTS : triggers
METRICS {
string request_id PK
datetime timestamp
string metric_type
string operation
string status
float value
json metadata
string user_id FK
string error_code
}
ALERTS ||--o{ ALERT_ACTIONS : has
ALERTS {
string alert_id PK
datetime timestamp
string severity
string alert_type
string title
text description
array affected_services
json metrics_snapshot
datetime resolved_at
}
ALERT_ACTIONS {
int id PK
string alert_id FK
string action_type
text suggestion
string runbook_url
}
CODE_DUPLICATES ||--|| FILES : references
CODE_DUPLICATES {
string duplicate_id PK
datetime detection_time
string file1
int file1_start_line
int file1_end_line
string file2
int file2_start_line
int file2_end_line
float similarity_score
string detection_method
}
METRICS_AGGREGATES ||--|| METRICS : summarizes
METRICS_AGGREGATES {
int id PK
datetime period_start
datetime period_end
string operation
int total_requests
int success_count
int error_count
float avg_latency_ms
float p95_latency_ms
}
Loading

8. Command Handler Architecture

graph TB
subgraph "Bot Interface"
U[User Input] --> DP[Dispatcher]
end
subgraph "Command Handlers"
DP --> SH[/status Handler]
DP --> EH[/errors Handler]
DP --> LH[/latency Handler]
DP --> RH[/rate_limit Handler]
DP --> TH[/triage Handler]
DP --> DH[/dashboard Handler]
end
subgraph "Services Layer"
SH --> HS[Health Service]
EH --> MS[Metrics Service]
LH --> MS
RH --> GS[GitHub Service]
TH --> IS[Investigation Service]
DH --> AS[Aggregation Service]
end
subgraph "Data Layer"
HS --> DB[(Database)]
MS --> DB
MS --> RC[(Redis)]
GS --> GA[GitHub API]
IS --> DB
IS --> ES[Elastic/Logs]
AS --> DB
end
Loading

9. Performance Optimization Flow

graph LR
subgraph "Incoming Requests"
R1[Request 1]
R2[Request 2]
R3[Request 3]
end
subgraph "Caching Layer"
R1 --> CK{Cache Check}
R2 --> CK
R3 --> CK
CK -->|Hit| CR[Return Cached]
CK -->|Miss| QL[Query Load]
end
subgraph "Batching"
QL --> BQ[Batch Queue]
BQ --> BT{Batch Trigger}
BT -->|Size=100| BP[Process Batch]
BT -->|Time=5s| BP
end
subgraph "Processing"
BP --> PP[Parallel Processing]
PP --> DB[(Database)]
DB --> UC[Update Cache]
UC --> RR[Return Results]
end
Loading

10. Rate Limiting and Backoff Strategy

stateDiagram-v2
[*] --> Normal: System Start
Normal --> Warning: 80% Quota Used
Warning --> Critical: 90% Quota Used
Critical --> Backoff: 95% Quota Used
Warning --> Normal: Quota Reset
Critical --> Warning: Quota < 90%
Backoff --> Critical: Manual Override
Backoff --> Normal: Quota Reset
state Normal {
[*] --> FullSpeed
FullSpeed: All Operations Normal
}
state Warning {
[*] --> Reduced
Reduced: Non-critical Ops Delayed
}
state Critical {
[*] --> Minimal
Minimal: Only Critical Ops
}
state Backoff {
[*] --> Paused
Paused: All GitHub Ops Suspended
}
Loading

11. Real-time Dashboard Data Flow

graph TD
subgraph "Data Sources"
M[Metrics DB]
R[Redis Cache]
G[GitHub API]
S[System Stats]
end
subgraph "Aggregation"
M --> AG[Aggregator]
R --> AG
G --> AG
S --> AG
AG --> DP[Data Processor]
end
subgraph "Formatting"
DP --> SF[Status Formatter]
DP --> PF[Performance Formatter]
DP --> EF[Error Formatter]
DP --> KF[KPI Formatter]
end
subgraph "Visualization"
SF --> DB[Dashboard Builder]
PF --> DB
EF --> DB
KF --> DB
DB --> PB[Progress Bars]
DB --> EM[Emoji Status]
DB --> TB[Tables]
TB --> TM[Telegram Message]
end
Loading

12. Error Handling and Recovery

graph TD
E[Error Occurs] --> ET{Error Type}
ET -->|Database| DBE[DB Error Handler]
ET -->|API| APE[API Error Handler]
ET -->|Timeout| TE[Timeout Handler]
ET -->|Unknown| UE[Generic Handler]
DBE --> RT1{Retry?}
RT1 -->|Yes| RTC1[Retry with Backoff]
RT1 -->|No| FO1[Failover to Cache]
APE --> RT2{Rate Limited?}
RT2 -->|Yes| BK[Activate Backoff]
RT2 -->|No| RTC2[Retry Request]
TE --> CX[Cancel Operation]
CX --> NF[Notify User]
UE --> LOG[Log Error]
LOG --> ALT[Alert Admin]
RTC1 --> SR{Success?}
RTC2 --> SR
FO1 --> SR
BK --> SR
SR -->|Yes| RES[Return Result]
SR -->|No| ERR[Return Error]
Loading

13. CI/CD Pipeline for Monitoring Features

graph LR
subgraph "Development"
DC[Code Changes] --> PR[Pull Request]
end
subgraph "Testing"
PR --> UT[Unit Tests]
PR --> IT[Integration Tests]
PR --> PT[Performance Tests]
UT --> TG{Tests Pass?}
IT --> TG
PT --> TG
end
subgraph "Deployment"
TG -->|Yes| STG[Deploy to Staging]
TG -->|No| FIX[Fix Issues]
STG --> ST[Staging Tests]
ST --> MT[Monitor Metrics]
MT --> PD{Metrics OK?}
end
subgraph "Production"
PD -->|Yes| PRD[Deploy to Production]
PD -->|No| RB[Rollback]
PRD --> PM[Production Monitoring]
PM --> AL[Alert Setup]
end
Loading

🏗️ ארכיטקטורה טכנית

מבנה המודולים

src/
├── monitoring/
│ ├── __init__.py
│ ├── metrics_collector.py # איסוף מטריקות
│ ├── metrics_storage.py # שמירה ב-DB/Redis
│ ├── metrics_analyzer.py # ניתוח וחישובים
│ └── alerts_manager.py # ניהול התראות
│
├── chatops/
│ ├── __init__.py
│ ├── handlers/
│ │ ├── status_handler.py # /status, /health
│ │ ├── metrics_handler.py # /errors, /latency, /kpis
│ │ ├── github_handler.py # /rate_limit
│ │ ├── triage_handler.py # /triage
│ │ └── dashboard_handler.py # /dashboard
│ ├── formatters/
│ │ ├── message_formatter.py # עיצוב הודעות
│ │ └── chart_generator.py # יצירת גרפים
│ └── permissions.py # הרשאות ואבטחה
│
├── code_analysis/
│ ├── __init__.py
│ ├── duplicate_detector.py # זיהוי כפילויות
│ ├── similarity_analyzer.py # ניתוח דמיון
│ └── ast_parser.py # ניתוח AST
│
└── integrations/
├── prometheus_exporter.py # חשיפת מטריקות
├── grafana_client.py # יצירת לינקים לדשבורדים
└── sentry_client.py # אינטגרציה עם Sentry

הערה על דיאגרמות

הדיאגרמות המפורטות מופיעות בסעיף דיאגרמות ארכיטקטורה למעלה.
הדיאגרמות כוללות:

  • זרימת פקודות וטיפול בשגיאות
  • ארכיטקטורת המערכת המלאה
  • זרימת איסוף מטריקות
  • מערכת התראות חכמות
  • Pipeline לזיהוי כפילויות
  • ועוד...

📊 מבני נתונים ו-APIs

1. מבנה מטריקה בסיסית

fromdatetimeimportdatetimefromtypingimportOptional, Dict, AnyfrompydanticimportBaseModel, FieldfromenumimportEnumclassMetricType(Enum):
COUNTER="counter"GAUGE="gauge"HISTOGRAM="histogram"SUMMARY="summary"classOperationType(Enum):
SEARCH="search"GITHUB_SYNC="github_sync"FILE_SAVE="file_save"DB_QUERY="db_query"API_CALL="api_call"classMetricStatus(Enum):
SUCCESS="success"ERROR="error"TIMEOUT="timeout"RATE_LIMITED="rate_limited"classMetric(BaseModel):
"""Base metric model"""request_id: str=Field(..., description="Unique request identifier")
timestamp: datetime=Field(default_factory=datetime.utcnow)
metric_type: MetricTypeoperation: OperationTypestatus: MetricStatusvalue: float=Field(..., description="Metric value (ms for latency, count for errors)")
metadata: Dict[str, Any] =Field(default_factory=dict)
user_id: Optional[str] =Noneerror_code: Optional[str] =Noneerror_message: Optional[str] =NoneclassConfig:
json_encoders= {
datetime: lambdav: v.isoformat()
}
# דוגמה לשימושmetric=Metric(
request_id="req-abc123",
metric_type=MetricType.HISTOGRAM,
operation=OperationType.GITHUB_SYNC,
status=MetricStatus.SUCCESS,
value=1250.5, # millisecondsmetadata={
"repo": "amirbiron/CodeBot",
"files_synced": 42,
"branch": "main"
},
user_id="user_123"
)

2. מבנה התראה חכמה

classAlertSeverity(Enum):
INFO="info"WARNING="warning"ERROR="error"CRITICAL="critical"classAlertType(Enum):
HIGH_ERROR_RATE="high_error_rate"SLOW_RESPONSE="slow_response"RATE_LIMIT_WARNING="rate_limit_warning"DB_CONNECTION_ISSUE="db_connection_issue"JOB_FAILURE="job_failure"classSmartAlert(BaseModel):
"""Enhanced alert with remediation suggestions"""alert_id: str=Field(default_factory=lambda: f"alert-{uuid.uuid4().hex[:8]}")
timestamp: datetime=Field(default_factory=datetime.utcnow)
severity: AlertSeverityalert_type: AlertTypetitle: strdescription: straffected_services: List[str]
metrics_snapshot: Dict[str, Any]
# Enhanced fieldsgrafana_links: List[str] =Field(default_factory=list)
suggested_actions: List[str] =Field(default_factory=list)
runbook_url: Optional[str] =Nonerelated_alerts: List[str] =Field(default_factory=list)
auto_resolve_after: Optional[int] =None# minutesdefformat_telegram_message(self) ->str:
"""Format alert for Telegram"""severity_emoji= {
AlertSeverity.INFO: "ℹ️",
AlertSeverity.WARNING: "⚠️",
AlertSeverity.ERROR: "🚨",
AlertSeverity.CRITICAL: "🔴"
}
message=f"{severity_emoji[self.severity]} **{self.title}**\n\n"message+=f"📝 {self.description}\n\n"ifself.affected_services:
message+=f"🎯 **Affected Services:**\n"forserviceinself.affected_services:
message+=f" • {service}\n"message+="\n"ifself.suggested_actions:
message+=f"💡 **Suggested Actions:**\n"fori, actioninenumerate(self.suggested_actions, 1):
message+=f" {i}. {action}\n"message+="\n"ifself.grafana_links:
message+=f"📊 **Dashboards:**\n"forlinkinself.grafana_links:
message+=f" • [View Dashboard]({link})\n"ifself.runbook_url:
message+=f"\n📖 [Runbook]({self.runbook_url})"returnmessage

3. מבנה לזיהוי כפילויות

classCodeDuplicate(BaseModel):
"""Code duplication finding"""duplicate_id: str=Field(default_factory=lambda: f"dup-{uuid.uuid4().hex[:8]}")
detection_time: datetime=Field(default_factory=datetime.utcnow)
# Location infofile1: strfile1_lines: Tuple[int, int] # (start_line, end_line)file2: strfile2_lines: Tuple[int, int]
# Similarity metricssimilarity_score: float=Field(..., ge=0, le=1) # 0-1lines_duplicated: inttokens_duplicated: int# Detection methoddetection_method: Literal["exact", "fuzzy", "ast"]
code_snippet: Optional[str] =None# Suggestionsrefactoring_suggestion: Optional[str] =Noneestimated_savings: Optional[int] =None# lines of code

4. Database Schema

-- מטריקותCREATETABLEmetrics (
id SERIALPRIMARY KEY,
request_id VARCHAR(50) NOT NULL,
timestampTIMESTAMPNOT NULL DEFAULT NOW(),
metric_type VARCHAR(20) NOT NULL,
operation VARCHAR(50) NOT NULL,
status VARCHAR(20) NOT NULL,
value FLOAT NOT NULL,
metadata JSONB,
user_id VARCHAR(50),
error_code VARCHAR(50),
error_message TEXT,
-- Indexes for quick queries
INDEX idx_timestamp (timestamp),
INDEX idx_request_id (request_id),
INDEX idx_operation_status (operation, status),
INDEX idx_user_id (user_id)
);
-- התראותCREATETABLEalerts (
id SERIALPRIMARY KEY,
alert_id VARCHAR(50) UNIQUE NOT NULL,
timestampTIMESTAMPNOT NULL DEFAULT NOW(),
severity VARCHAR(20) NOT NULL,
alert_type VARCHAR(50) NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
affected_services TEXT[],
metrics_snapshot JSONB,
grafana_links TEXT[],
suggested_actions TEXT[],
runbook_url TEXT,
resolved_at TIMESTAMP,
resolved_by VARCHAR(50),
INDEX idx_alert_timestamp (timestamp),
INDEX idx_alert_severity (severity),
INDEX idx_alert_type (alert_type)
);
-- כפילויות קודCREATETABLEcode_duplicates (
id SERIALPRIMARY KEY,
duplicate_id VARCHAR(50) UNIQUE NOT NULL,
detection_time TIMESTAMPNOT NULL DEFAULT NOW(),
file1 TEXTNOT NULL,
file1_start_line INTNOT NULL,
file1_end_line INTNOT NULL,
file2 TEXTNOT NULL,
file2_start_line INTNOT NULL,
file2_end_line INTNOT NULL,
similarity_score FLOAT NOT NULL,
lines_duplicated INTNOT NULL,
detection_method VARCHAR(20) NOT NULL,
code_snippet TEXT,
refactoring_suggestion TEXT,
is_resolved BOOLEAN DEFAULT FALSE,
resolved_at TIMESTAMP,
INDEX idx_detection_time (detection_time),
INDEX idx_similarity (similarity_score),
INDEX idx_files (file1, file2)
);
-- Cache for aggregated metrics (for performance)CREATETABLEmetrics_aggregates (
id SERIALPRIMARY KEY,
period_start TIMESTAMPNOT NULL,
period_end TIMESTAMPNOT NULL,
operation VARCHAR(50) NOT NULL,
total_requests INTNOT NULL,
success_count INTNOT NULL,
error_count INTNOT NULL,
avg_latency_ms FLOAT,
p50_latency_ms FLOAT,
p95_latency_ms FLOAT,
p99_latency_ms FLOAT,
UNIQUE(period_start, period_end, operation),
INDEX idx_period (period_start, period_end)
);

📅 תוכנית מימוש מדורגת

Phase 1: תשתית בסיסית (3-4 ימים)

יום 1-2: Request Tracking & Structured Logging

# Tasks:tasks= [
"הטמעת RequestContext בכל הפעולות המרכזיות",
"מעבר ל-structlog עם metadata",
"הוספת decorators לטראקינג אוטומטי",
"יצירת טבלאות DB למטריקות"
]
# Deliverables:- [ ] מודולrequest_context.py- [ ] מודולstructured_logger.py- [ ] Migrationscriptsל-DB- [ ] Unittests

יום 3-4: Metrics Collection Infrastructure

# Implementation checklist:- [ ] MetricsCollectorclassעםsingletonpattern- [ ] Prometheusmetricsexposure (/metricsendpoint)
- [ ] Backgroundtaskלשמירתמטריקותב-DB- [ ] Redisconnectionpoolלקאשינג- [ ] Healthcheckendpoint

Phase 2: ChatOps בסיסי (4-5 ימים)

יום 5-6: פקודות Status & Health

# Commands to implement:commands= {
"/status": "בדיקת בריאות כללית של המערכת",
"/health": "בדיקת קומפוננטים ספציפיים",
"/uptime": "זמן פעילות ויציבות"
}
# Code example:@track_requestasyncdefhandle_status_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle /status command"""health_checks=awaitperform_health_checks()
message=format_status_message(health_checks)
awaitupdate.message.reply_text(
message,
parse_mode=ParseMode.HTML,
reply_markup=get_status_keyboard()
)
asyncdefperform_health_checks():
"""Run all health checks in parallel"""checks=awaitasyncio.gather(
check_database_connection(),
check_redis_connection(),
check_github_api(),
check_disk_space(),
return_exceptions=True
)
return {
"database": checks[0],
"redis": checks[1],
"github_api": checks[2],
"disk_space": checks[3]
}

יום 7-8: פקודות Metrics & Errors

# Implementation for /errors command:classErrorsHandler:
def__init__(self, metrics_storage: MetricsStorage):
self.storage=metrics_storageasyncdefhandle_errors_command(
self, update: Update, context: ContextTypes.DEFAULT_TYPE
):
"""Show recent errors with analysis"""# Parse time range from argstime_range=self._parse_time_range(context.args)
# Fetch errors from storageerrors=awaitself.storage.get_recent_errors(
since=time_range,
limit=100
)
# Analyze and group errorsanalysis=self._analyze_errors(errors)
# Format message with inline buttonsmessage=self._format_error_report(analysis)
keyboard=self._create_error_keyboard(analysis)
awaitupdate.message.reply_text(
message,
parse_mode=ParseMode.HTML,
reply_markup=keyboard
)
def_analyze_errors(self, errors: List[Metric]) ->Dict:
"""Analyze errors and find patterns"""return {
"total_count": len(errors),
"by_type": self._group_by_error_code(errors),
"by_operation": self._group_by_operation(errors),
"top_errors": self._get_top_errors(errors, limit=5),
"error_rate": self._calculate_error_rate(errors),
"trending": self._find_trending_errors(errors)
}

יום 9: GitHub Rate Limit Monitoring

classGitHubMonitor:
asyncdefcheck_rate_limit(self) ->Dict:
"""Check GitHub API rate limit status"""asyncwithaiohttp.ClientSession() assession:
headers= {"Authorization": f"token {self.github_token}"}
asyncwithsession.get(
"https://api.github.com/rate_limit",
headers=headers
) asresponse:
data=awaitresponse.json()
return {
"core": {
"limit": data["resources"]["core"]["limit"],
"remaining": data["resources"]["core"]["remaining"],
"reset": datetime.fromtimestamp(
data["resources"]["core"]["reset"]
),
"used_percentage": self._calculate_usage_percentage(
data["resources"]["core"]
)
},
"search": data["resources"]["search"],
"graphql": data["resources"]["graphql"]
}
asyncdefhandle_rate_limit_command(self, update, context):
"""Display GitHub rate limit status"""status=awaitself.check_rate_limit()
# Create visual representationmessage=self._format_rate_limit_message(status)
# Add warning if approaching limitifstatus["core"]["used_percentage"] >80:
message+="\n\n⚠️ **Warning:** Approaching rate limit!"message+="\nConsider enabling backoff mode: /enable_backoff"awaitupdate.message.reply_text(message, parse_mode=ParseMode.HTML)

Phase 3: Advanced Features (5-6 ימים)

יום 10-11: Duplicate Detection System

classDuplicateDetector:
def__init__(self):
self.exact_matcher=ExactMatcher()
self.fuzzy_matcher=FuzzyMatcher()
self.ast_analyzer=ASTAnalyzer()
asyncdefscan_codebase(self, path: str) ->List[CodeDuplicate]:
"""Scan codebase for duplicates"""# Collect all Python filesfiles=self._collect_python_files(path)
# Phase 1: Exact matchingexact_duplicates=awaitself.exact_matcher.find_duplicates(files)
# Phase 2: Fuzzy matching (MinHash)fuzzy_duplicates=awaitself.fuzzy_matcher.find_near_duplicates(
files, threshold=0.85
)
# Phase 3: AST-based analysisast_duplicates=awaitself.ast_analyzer.find_structural_duplicates(files)
# Merge and deduplicate resultsall_duplicates=self._merge_results(
exact_duplicates, fuzzy_duplicates, ast_duplicates
)
# Calculate refactoring suggestionsforduplicateinall_duplicates:
duplicate.refactoring_suggestion=self._suggest_refactoring(duplicate)
returnall_duplicatesclassExactMatcher:
asyncdeffind_duplicates(self, files: List[Path]) ->List[CodeDuplicate]:
"""Find exact code duplicates"""# Create hash map of code blockshash_map=defaultdict(list)
forfile_pathinfiles:
content=awaitself._read_file(file_path)
blocks=self._extract_code_blocks(content, min_lines=5)
forblockinblocks:
# Normalize whitespace and commentsnormalized=self._normalize_code(block.content)
block_hash=hashlib.sha256(normalized.encode()).hexdigest()
hash_map[block_hash].append({
"file": file_path,
"lines": block.lines,
"content": block.content
})
# Find duplicatesduplicates= []
forblock_hash, occurrencesinhash_map.items():
iflen(occurrences) >1:
# Create duplicate entries for each pairforiinrange(len(occurrences)):
forjinrange(i+1, len(occurrences)):
duplicates.append(
CodeDuplicate(
file1=occurrences[i]["file"],
file1_lines=occurrences[i]["lines"],
file2=occurrences[j]["file"],
file2_lines=occurrences[j]["lines"],
similarity_score=1.0,
lines_duplicated=len(occurrences[i]["content"].splitlines()),
detection_method="exact",
code_snippet=occurrences[i]["content"][:500]
)
)
returnduplicates

יום 12-13: Triage System

classTriageHandler:
asyncdefhandle_triage_command(self, update, context):
"""Deep dive into a specific request"""ifnotcontext.args:
awaitupdate.message.reply_text(
"Usage: /triage <request_id>\n""Example: /triage req-abc123"
)
returnrequest_id=context.args[0]
# Gather all data about this requestinvestigation=awaitself._investigate_request(request_id)
ifnotinvestigation["found"]:
awaitupdate.message.reply_text(
f"❌ Request {request_id} not found in logs"
)
return# Generate comprehensive reportreport=self._generate_triage_report(investigation)
# Send as HTML file if too longiflen(report) >4096:
file_path=awaitself._save_report_as_html(report, request_id)
awaitupdate.message.reply_document(
document=file_path,
caption=f"📋 Triage Report for {request_id}"
)
else:
awaitupdate.message.reply_text(
report,
parse_mode=ParseMode.HTML,
disable_web_page_preview=True
)
asyncdef_investigate_request(self, request_id: str) ->Dict:
"""Gather all information about a request"""# Parallel data gatheringresults=awaitasyncio.gather(
self._get_metrics(request_id),
self._get_logs(request_id),
self._get_traces(request_id),
self._get_related_requests(request_id),
return_exceptions=True
)
return {
"found": any(rforrinresultsifr),
"metrics": results[0] or [],
"logs": results[1] or [],
"traces": results[2] or [],
"related": results[3] or [],
"timeline": self._build_timeline(results),
"root_cause": self._analyze_root_cause(results),
"suggestions": self._generate_suggestions(results)
}

יום 14-15: Dashboard & Visualizations

classDashboardGenerator:
asyncdefgenerate_dashboard(self, time_range: str="1h") ->str:
"""Generate comprehensive dashboard"""# Gather all metrics in paralleldata=awaitasyncio.gather(
self._get_system_status(),
self._get_performance_metrics(time_range),
self._get_error_metrics(time_range),
self._get_business_kpis(time_range),
self._get_github_status()
)
dashboard=self._format_dashboard(data)
returndashboarddef_format_dashboard(self, data: List) ->str:
"""Format dashboard with visual elements"""status, perf, errors, kpis, github=data# Create status indicatorstatus_emoji="🟢"ifstatus["healthy"] else"🔴"dashboard=f"""📊 **CodeBot Dashboard**{'─'*30}{status_emoji} **System Status:** {status["status"]}⏱ **Uptime:** {status["uptime"]}🔄 **Last Check:** {status["last_check"]}**Performance (last {perf["time_range"]}):**├─ 🔍 Search: {self._format_latency(perf["search"])}├─ 📁 File Ops: {self._format_latency(perf["file_ops"])}├─ 🔄 GitHub Sync: {self._format_latency(perf["github"])}└─ 💾 Database: {self._format_latency(perf["database"])}**Activity:**├─ 📊 Requests: {kpis["total_requests"]:,}├─ ✅ Success Rate: {kpis["success_rate"]:.1f}%├─ 📝 Files Saved: {kpis["files_saved"]:,}└─ 🔍 Searches: {kpis["searches"]:,}**Errors (last hour):**{self._format_error_summary(errors)}**GitHub API:**├─ 📊 Remaining: {github["remaining"]:,}/{github["limit"]:,}├─ 📈 Usage: {self._create_progress_bar(github["used_percentage"])}└─ 🔄 Reset: {github["reset_in"]}**Quick Actions:**/errors - View recent errors/triage <id> - Investigate request/metrics - Detailed metrics"""returndashboarddef_create_progress_bar(self, percentage: float, width: int=20) ->str:
"""Create text-based progress bar"""filled=int(width*percentage/100)
bar="█"*filled+"░"* (width-filled)
color="🟢"ifpercentage<60else"🟡"ifpercentage<80else"🔴"returnf"{color} [{bar}] {percentage:.0f}%"

Phase 4: Integration & Testing (3-4 ימים)

יום 16-17: Integration Tests

# tests/test_chatops_integration.pyimportpytestfromunittest.mockimportAsyncMock, patchimportasyncioclassTestChatOpsIntegration:
@pytest.fixtureasyncdefbot_context(self):
"""Create test bot context"""return {
"metrics_collector": MetricsCollector(),
"storage": AsyncMock(),
"handlers": {}
}
@pytest.mark.asyncioasyncdeftest_status_command_full_flow(self, bot_context):
"""Test full flow of status command"""# Setup mock databot_context["storage"].get_health_status.return_value= {
"database": "healthy",
"redis": "healthy",
"github": "rate_limited"
}
# Create handlerhandler=StatusHandler(bot_context)
# Create mock updateupdate=create_mock_update("/status")
# Execute commandawaithandler.handle_status_command(update, None)
# Verify responseupdate.message.reply_text.assert_called_once()
response=update.message.reply_text.call_args[0][0]
assert"🟢"inresponse# Healthy indicatorsassert"⚠️"inresponse# Warning for rate limitassert"Database"inresponse@pytest.mark.asyncioasyncdeftest_concurrent_metrics_collection(self, bot_context):
"""Test that metrics are collected concurrently"""collector=bot_context["metrics_collector"]
# Add delay to simulate slow operationsasyncdefslow_operation():
awaitasyncio.sleep(0.1)
return {"status": "ok"}
# Measure concurrent executionstart=asyncio.get_event_loop().time()
results=awaitasyncio.gather(
collector.collect_metric("op1", slow_operation),
collector.collect_metric("op2", slow_operation),
collector.collect_metric("op3", slow_operation)
)
elapsed=asyncio.get_event_loop().time() -start# Should complete in ~0.1s, not 0.3sassertelapsed<0.15assertlen(results) ==3

יום 18: Load Testing

# tests/load_test.pyimportasyncioimportaiohttpimporttimefromtypingimportList, DictclassLoadTester:
def__init__(self, base_url: str, num_users: int=10):
self.base_url=base_urlself.num_users=num_usersself.results= []
asyncdefsimulate_user(self, user_id: int):
"""Simulate single user making requests"""commands= [
"/status",
"/errors",
"/latency",
"/dashboard",
f"/triage req-test{user_id}"
]
asyncwithaiohttp.ClientSession() assession:
forcommandincommands:
start=time.time()
try:
asyncwithsession.post(
f"{self.base_url}/webhook",
json={"message": {"text": command}}
) asresponse:
awaitresponse.text()
latency= (time.time() -start) *1000self.results.append({
"user_id": user_id,
"command": command,
"latency_ms": latency,
"status": response.status
})
exceptExceptionase:
self.results.append({
"user_id": user_id,
"command": command,
"error": str(e)
})
# Small delay between commandsawaitasyncio.sleep(0.5)
asyncdefrun_test(self):
"""Run load test with multiple users"""print(f"Starting load test with {self.num_users} users...")
tasks= [
self.simulate_user(i) foriinrange(self.num_users)
]
start=time.time()
awaitasyncio.gather(*tasks)
total_time=time.time() -start# Analyze resultsself._print_results(total_time)
def_print_results(self, total_time: float):
"""Print test results"""successful= [rforrinself.resultsif"error"notinr]
failed= [rforrinself.resultsif"error"inr]
ifsuccessful:
latencies= [r["latency_ms"] forrinsuccessful]
avg_latency=sum(latencies) /len(latencies)
p95_latency=sorted(latencies)[int(len(latencies) *0.95)]
print(f"""Load Test Results:─────────────────Total Time: {total_time:.2f}sTotal Requests: {len(self.results)}Successful: {len(successful)}Failed: {len(failed)}Latency Stats: Average: {avg_latency:.2f}ms P95: {p95_latency:.2f}ms Max: {max(latencies):.2f}ms Min: {min(latencies):.2f}msSuccess Rate: {len(successful)/len(self.results)*100:.1f}%""")
# Run testif__name__=="__main__":
tester=LoadTester("http://localhost:8080", num_users=20)
asyncio.run(tester.run_test())

🔧 מימוש מפורט לכל רכיב

1. Metrics Collector Implementation

# src/monitoring/metrics_collector.pyimportasynciofromtypingimportOptional, Dict, Any, Listfromdatetimeimportdatetime, timedeltafromprometheus_clientimportCounter, Histogram, Gauge, generate_latestimportstructlogfromcontextlibimportasynccontextmanagerlogger=structlog.get_logger()
classMetricsCollector:
"""Centralized metrics collection system"""# Prometheus metricsrequest_counter=Counter(
'codebot_requests_total', 'Total requests',
['operation', 'status']
)
request_duration=Histogram(
'codebot_request_duration_seconds',
'Request duration',
['operation'],
buckets=[0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]
)
active_requests=Gauge(
'codebot_active_requests',
'Currently active requests',
['operation']
)
error_counter=Counter(
'codebot_errors_total',
'Total errors',
['operation', 'error_code']
)
def__init__(self, storage: MetricsStorage):
self.storage=storageself._batch_queue=asyncio.Queue(maxsize=1000)
self._batch_task=Noneasyncdefstart(self):
"""Start background tasks"""self._batch_task=asyncio.create_task(self._batch_writer())
logger.info("metrics_collector_started")
asyncdefstop(self):
"""Stop background tasks"""ifself._batch_task:
self._batch_task.cancel()
awaitasyncio.gather(self._batch_task, return_exceptions=True)
logger.info("metrics_collector_stopped")
@asynccontextmanagerasyncdeftrack_request(
self, operation: str, request_id: Optional[str] =None
):
"""Context manager for tracking requests"""ifnotrequest_id:
request_id=RequestContext.get_request_id()
# Increment active requestsself.active_requests.labels(operation=operation).inc()
start_time=asyncio.get_event_loop().time()
status=MetricStatus.SUCCESSerror_code=Noneerror_message=Nonetry:
yieldexceptExceptionase:
status=MetricStatus.ERRORerror_code=getattr(e, 'error_code', 'unknown')
error_message=str(e)
# Track errorself.error_counter.labels(
operation=operation,
error_code=error_code
).inc()
logger.error(
"request_failed",
request_id=request_id,
operation=operation,
error=error_message
)
raisefinally:
# Calculate durationduration=asyncio.get_event_loop().time() -start_time# Update Prometheus metricsself.request_counter.labels(
operation=operation,
status=status.value
).inc()
self.request_duration.labels(
operation=operation
).observe(duration)
self.active_requests.labels(
operation=operation
).dec()
# Create metric recordmetric=Metric(
request_id=request_id,
metric_type=MetricType.HISTOGRAM,
operation=operation,
status=status,
value=duration*1000, # Convert to mserror_code=error_code,
error_message=error_message
)
# Queue for batch writingawaitself._batch_queue.put(metric)
asyncdef_batch_writer(self):
"""Write metrics in batches for performance"""batch= []
last_write=asyncio.get_event_loop().time()
whileTrue:
try:
# Wait for metric with timeouttimeout=5.0- (asyncio.get_event_loop().time() -last_write)
metric=awaitasyncio.wait_for(
self._batch_queue.get(),
timeout=max(0.1, timeout)
)
batch.append(metric)
# Write batch if size or time threshold reachedshould_write= (
len(batch) >=100orasyncio.get_event_loop().time() -last_write>5.0
)
ifshould_writeandbatch:
awaitself.storage.write_metrics(batch)
batch= []
last_write=asyncio.get_event_loop().time()
exceptasyncio.TimeoutError:
# Timeout reached, write if we have dataifbatch:
awaitself.storage.write_metrics(batch)
batch= []
last_write=asyncio.get_event_loop().time()
exceptasyncio.CancelledError:
# Shutdown, write remainingifbatch:
awaitself.storage.write_metrics(batch)
raiseexceptExceptionase:
logger.error("batch_writer_error", error=str(e))
awaitasyncio.sleep(1)
asyncdefget_metrics_summary(
self, time_range: timedelta=timedelta(hours=1)
) ->Dict[str, Any]:
"""Get summary of recent metrics"""since=datetime.utcnow() -time_rangemetrics=awaitself.storage.get_metrics(since=since)
# Calculate summariessummary= {
"time_range": str(time_range),
"total_requests": len(metrics),
"operations": {}
}
# Group by operationfromcollectionsimportdefaultdictby_operation=defaultdict(list)
formetricinmetrics:
by_operation[metric.operation].append(metric)
# Calculate stats per operationforoperation, op_metricsinby_operation.items():
latencies= [m.valueforminop_metricsifm.status==MetricStatus.SUCCESS]
errors= [mforminop_metricsifm.status==MetricStatus.ERROR]
summary["operations"][operation] = {
"count": len(op_metrics),
"success_count": len(latencies),
"error_count": len(errors),
"success_rate": len(latencies) /len(op_metrics) *100ifop_metricselse0,
"latency": {
"avg": sum(latencies) /len(latencies) iflatencieselse0,
"p50": self._percentile(latencies, 50),
"p95": self._percentile(latencies, 95),
"p99": self._percentile(latencies, 99),
"max": max(latencies) iflatencieselse0
},
"top_errors": self._get_top_errors(errors, limit=3)
}
returnsummarydef_percentile(self, values: List[float], p: int) ->float:
"""Calculate percentile"""ifnotvalues:
return0values_sorted=sorted(values)
index=int(len(values_sorted) *p/100)
returnvalues_sorted[min(index, len(values_sorted) -1)]
def_get_top_errors(self, errors: List[Metric], limit: int) ->List[Dict]:
"""Get most common errors"""fromcollectionsimportCountererror_counts=Counter(e.error_codeforeinerrors)
return [
{"code": code, "count": count}
forcode, countinerror_counts.most_common(limit)
]
defexport_prometheus_metrics(self) ->bytes:
"""Export metrics in Prometheus format"""returngenerate_latest()

2. Smart Alerts Implementation

# src/monitoring/alerts_manager.pyfromtypingimportList, Optional, Dict, Anyimportasynciofromdatetimeimportdatetime, timedeltaimportstructloglogger=structlog.get_logger()
classAlertsManager:
"""Intelligent alerting system with remediation suggestions"""# Alert thresholds configurationTHRESHOLDS= {
"error_rate": {
"warning": 5.0, # 5% error rate"critical": 10.0# 10% error rate
},
"latency_p95": {
"warning": 2000, # 2 seconds"critical": 5000# 5 seconds
},
"github_rate_limit": {
"warning": 20, # 20% remaining"critical": 10# 10% remaining
}
}
# Remediation playbooksPLAYBOOKS= {
AlertType.HIGH_ERROR_RATE: [
"Check application logs for stack traces",
"Verify database connection status",
"Check external API availability",
"Consider enabling circuit breaker",
"Review recent deployments"
],
AlertType.SLOW_RESPONSE: [
"Check database query performance",
"Review database indexes",
"Check CPU and memory usage",
"Look for N+1 query patterns",
"Consider enabling caching"
],
AlertType.RATE_LIMIT_WARNING: [
"Enable GitHub API backoff mode",
"Reduce sync frequency temporarily",
"Check for unnecessary API calls",
"Consider using webhooks instead of polling"
],
AlertType.DB_CONNECTION_ISSUE: [
"Check database server status",
"Verify connection pool settings",
"Check for long-running transactions",
"Review max_connections setting",
"Check network connectivity"
]
}
def__init__(
self, metrics_collector: MetricsCollector,
notification_service: NotificationService,
storage: AlertStorage
):
self.metrics=metrics_collectorself.notifications=notification_serviceself.storage=storageself.active_alerts: Dict[str, SmartAlert] = {}
self._monitoring_task=Noneasyncdefstart(self):
"""Start monitoring for alerts"""self._monitoring_task=asyncio.create_task(self._monitor_loop())
logger.info("alerts_manager_started")
asyncdefstop(self):
"""Stop monitoring"""ifself._monitoring_task:
self._monitoring_task.cancel()
awaitasyncio.gather(self._monitoring_task, return_exceptions=True)
asyncdef_monitor_loop(self):
"""Main monitoring loop"""whileTrue:
try:
# Check various conditionsawaitasyncio.gather(
self._check_error_rate(),
self._check_latency(),
self._check_github_rate_limit(),
self._check_system_health(),
return_exceptions=True
)
# Check for auto-resolveawaitself._check_auto_resolve()
# Wait before next checkawaitasyncio.sleep(30) # Check every 30 secondsexceptasyncio.CancelledError:
raiseexceptExceptionase:
logger.error("alert_monitoring_error", error=str(e))
awaitasyncio.sleep(60)
asyncdef_check_error_rate(self):
"""Check error rate and create alert if needed"""# Get metrics for last 5 minutessummary=awaitself.metrics.get_metrics_summary(
time_range=timedelta(minutes=5)
)
# Calculate overall error ratetotal=summary["total_requests"]
iftotal==0:
returnerrors=sum(
op["error_count"] foropinsummary["operations"].values()
)
error_rate= (errors/total) *100# Determine severityseverity=Noneiferror_rate>=self.THRESHOLDS["error_rate"]["critical"]:
severity=AlertSeverity.CRITICALeliferror_rate>=self.THRESHOLDS["error_rate"]["warning"]:
severity=AlertSeverity.WARNINGifseverity:
# Find top errorsall_errors= []
forop_datainsummary["operations"].values():
all_errors.extend(op_data.get("top_errors", []))
# Create or update alertalert_key="high_error_rate"ifalert_keynotinself.active_alerts:
alert=SmartAlert(
severity=severity,
alert_type=AlertType.HIGH_ERROR_RATE,
title=f"High Error Rate: {error_rate:.1f}%",
description=f"Error rate is {error_rate:.1f}% in the last 5 minutes",
affected_services=list(summary["operations"].keys()),
metrics_snapshot={
"error_rate": error_rate,
"total_requests": total,
"total_errors": errors,
"top_errors": all_errors[:5]
}
)
# Add remediation suggestionsalert.suggested_actions=self.PLAYBOOKS[AlertType.HIGH_ERROR_RATE]
# Add Grafana linksalert.grafana_links= [
self._create_grafana_link("errors", minutes=5),
self._create_grafana_link("latency", minutes=5)
]
# Store and notifyself.active_alerts[alert_key] =alertawaitself._send_alert(alert)
asyncdef_check_latency(self):
"""Check response times"""summary=awaitself.metrics.get_metrics_summary(
time_range=timedelta(minutes=5)
)
# Check P95 latency for each operationslow_operations= []
forop_name, op_datainsummary["operations"].items():
p95=op_data["latency"]["p95"]
ifp95>self.THRESHOLDS["latency_p95"]["critical"]:
slow_operations.append({
"operation": op_name,
"p95": p95,
"severity": "critical"
})
elifp95>self.THRESHOLDS["latency_p95"]["warning"]:
slow_operations.append({
"operation": op_name,
"p95": p95,
"severity": "warning"
})
ifslow_operations:
# Determine overall severityseverity= (
AlertSeverity.CRITICALifany(op["severity"] =="critical"foropinslow_operations)
elseAlertSeverity.WARNING
)
alert=SmartAlert(
severity=severity,
alert_type=AlertType.SLOW_RESPONSE,
title="Slow Response Times Detected",
description=f"{len(slow_operations)} operations are responding slowly",
affected_services=[op["operation"] foropinslow_operations],
metrics_snapshot={"slow_operations": slow_operations},
suggested_actions=self.PLAYBOOKS[AlertType.SLOW_RESPONSE],
grafana_links=[
self._create_grafana_link("performance", minutes=15)
]
)
awaitself._send_alert(alert)
asyncdef_check_github_rate_limit(self):
"""Monitor GitHub API rate limit"""github_monitor=GitHubMonitor()
status=awaitgithub_monitor.check_rate_limit()
remaining_pct=status["core"]["used_percentage"]
ifremaining_pct>90:
severity=AlertSeverity.CRITICALelifremaining_pct>80:
severity=AlertSeverity.WARNINGelse:
returnalert=SmartAlert(
severity=severity,
alert_type=AlertType.RATE_LIMIT_WARNING,
title=f"GitHub API Rate Limit: {remaining_pct:.0f}% Used",
description=(
f"Only {status['core']['remaining']} requests remaining. "f"Resets at {status['core']['reset'].strftime('%H:%M')}"
),
affected_services=["github_sync"],
metrics_snapshot=status,
suggested_actions=self.PLAYBOOKS[AlertType.RATE_LIMIT_WARNING],
auto_resolve_after=30# Auto-resolve after reset
)
awaitself._send_alert(alert)
def_create_grafana_link(self, dashboard: str, minutes: int=15) ->str:
"""Create pre-filtered Grafana link"""base_url="https://grafana.example.com"from_time=f"now-{minutes}m"to_time="now"dashboards= {
"errors": "d/errors/error-analysis",
"latency": "d/latency/performance-metrics",
"performance": "d/perf/system-performance"
}
dashboard_path=dashboards.get(dashboard, "d/main/overview")
returnf"{base_url}/{dashboard_path}?from={from_time}&to={to_time}&refresh=10s"asyncdef_send_alert(self, alert: SmartAlert):
"""Send alert via configured channels"""# Store in databaseawaitself.storage.save_alert(alert)
# Send via Telegrammessage=alert.format_telegram_message()
awaitself.notifications.send_telegram(message)
# Loglogger.warning(
"alert_triggered",
alert_id=alert.alert_id,
type=alert.alert_type.value,
severity=alert.severity.value
)
asyncdef_check_auto_resolve(self):
"""Check if alerts can be auto-resolved"""current_time=datetime.utcnow()
foralert_key, alertinlist(self.active_alerts.items()):
ifalert.auto_resolve_after:
age_minutes= (current_time-alert.timestamp).total_seconds() /60ifage_minutes>alert.auto_resolve_after:
# Auto-resolvelogger.info(
"alert_auto_resolved",
alert_id=alert.alert_id
)
awaitself.storage.resolve_alert(
alert.alert_id,
resolved_by="auto"
)
delself.active_alerts[alert_key]

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions