quantumbit commited on
Commit
1860a28
·
verified ·
1 Parent(s): 4cc9df6

Delete logger

Browse files
Files changed (2) hide show
  1. logger/__init__.py +0 -1
  2. logger/logger.py +0 -340
logger/__init__.py DELETED
@@ -1 +0,0 @@
1
- # Logger Package
 
 
logger/logger.py DELETED
@@ -1,340 +0,0 @@
1
- """
2
- Enhanced in-memory logging system for RAG API with detailed pipeline timing.
3
- Since HuggingFace doesn't allow persistent file storage, logs are stored in memory.
4
- """
5
-
6
- import json
7
- import time
8
- from datetime import datetime
9
- from typing import List, Dict, Any, Optional
10
- from dataclasses import dataclass, asdict, field
11
- import threading
12
-
13
- @dataclass
14
- class PipelineTimings:
15
- """Detailed timing for each stage of the RAG pipeline."""
16
- query_expansion_time: float = 0.0
17
- hybrid_search_time: float = 0.0
18
- semantic_search_time: float = 0.0
19
- bm25_search_time: float = 0.0
20
- score_fusion_time: float = 0.0
21
- reranking_time: float = 0.0
22
- context_creation_time: float = 0.0
23
- llm_generation_time: float = 0.0
24
- total_pipeline_time: float = 0.0
25
-
26
- @dataclass
27
- class LogEntry:
28
- """Enhanced structure for a single log entry with detailed timing."""
29
- timestamp: str
30
- request_id: str
31
- document_url: str
32
- questions: List[str]
33
- answers: List[str]
34
- processing_time_seconds: float
35
- total_questions: int
36
- status: str # 'success', 'error', 'partial'
37
- error_message: Optional[str] = None
38
- document_id: Optional[str] = None
39
- was_preprocessed: bool = False
40
- # Enhanced timing details
41
- request_start_time: str = ""
42
- request_end_time: str = ""
43
- pipeline_timings: Dict[str, Any] = field(default_factory=dict)
44
- # Per-question timings
45
- question_timings: List[Dict[str, Any]] = field(default_factory=list)
46
-
47
- class RAGLogger:
48
- """Enhanced in-memory logging system for RAG API requests with detailed pipeline timing."""
49
-
50
- def __init__(self):
51
- self.logs: List[LogEntry] = []
52
- self.server_start_time = datetime.now().isoformat()
53
- self.request_counter = 0
54
- self._lock = threading.Lock()
55
- # Active request tracking for timing
56
- self._active_requests: Dict[str, Dict[str, Any]] = {}
57
-
58
- def generate_request_id(self) -> str:
59
- """Generate a unique request ID."""
60
- with self._lock:
61
- self.request_counter += 1
62
- return f"req_{self.request_counter:06d}"
63
-
64
- def start_request_timing(self, request_id: str) -> None:
65
- """Start timing for a new request."""
66
- self._active_requests[request_id] = {
67
- 'start_time': time.time(),
68
- 'start_timestamp': datetime.now().isoformat(),
69
- 'pipeline_stages': {},
70
- 'question_timings': []
71
- }
72
-
73
- def log_pipeline_stage(self, request_id: str, stage_name: str, duration: float) -> None:
74
- """Log the timing for a specific pipeline stage."""
75
- if request_id in self._active_requests:
76
- self._active_requests[request_id]['pipeline_stages'][stage_name] = {
77
- 'duration_seconds': round(duration, 4),
78
- 'timestamp': datetime.now().isoformat()
79
- }
80
- print(f"⏱️ [{request_id}] {stage_name}: {duration:.4f}s")
81
-
82
- def log_question_timing(self, request_id: str, question_index: int, question: str,
83
- answer: str, duration: float, pipeline_timings: Dict[str, float]) -> None:
84
- """Log timing for individual question processing."""
85
- if request_id in self._active_requests:
86
- question_timing = {
87
- 'question_index': question_index,
88
- 'question': question[:100] + "..." if len(question) > 100 else question,
89
- 'answer_length': len(answer),
90
- 'total_time_seconds': round(duration, 4),
91
- 'pipeline_breakdown': {k: round(v, 4) for k, v in pipeline_timings.items()},
92
- 'timestamp': datetime.now().isoformat()
93
- }
94
- self._active_requests[request_id]['question_timings'].append(question_timing)
95
-
96
- # Enhanced console logging
97
- print(f"\n❓ [{request_id}] Question {question_index + 1}: {question[:60]}...")
98
- print(f" 📊 Processing time: {duration:.4f}s")
99
- if pipeline_timings:
100
- breakdown_str = " | ".join([f"{k}: {v:.4f}s" for k, v in pipeline_timings.items() if v > 0])
101
- if breakdown_str:
102
- print(f" ⚙️ Pipeline breakdown: {breakdown_str}")
103
- print(f" 💬 Answer length: {len(answer)} characters")
104
-
105
- def end_request_timing(self, request_id: str) -> Dict[str, Any]:
106
- """End timing for a request and return timing data."""
107
- if request_id not in self._active_requests:
108
- return {}
109
-
110
- request_data = self._active_requests[request_id]
111
- total_time = time.time() - request_data['start_time']
112
-
113
- timing_data = {
114
- 'start_time': request_data['start_timestamp'],
115
- 'end_time': datetime.now().isoformat(),
116
- 'total_time_seconds': round(total_time, 4),
117
- 'pipeline_stages': request_data['pipeline_stages'],
118
- 'question_timings': request_data['question_timings']
119
- }
120
-
121
- # Cleanup
122
- del self._active_requests[request_id]
123
-
124
- return timing_data
125
-
126
- def log_request(
127
- self,
128
- document_url: str,
129
- questions: List[str],
130
- answers: List[str],
131
- processing_time: float,
132
- status: str = "success",
133
- error_message: Optional[str] = None,
134
- document_id: Optional[str] = None,
135
- was_preprocessed: bool = False,
136
- timing_data: Optional[Dict[str, Any]] = None
137
- ) -> str:
138
- """
139
- Log a RAG API request with enhanced timing information.
140
-
141
- Args:
142
- document_url: URL of the document processed
143
- questions: List of questions asked
144
- answers: List of answers generated
145
- processing_time: Time taken in seconds
146
- status: Request status ('success', 'error', 'partial')
147
- error_message: Error message if any
148
- document_id: Generated document ID
149
- was_preprocessed: Whether document was already processed
150
- timing_data: Detailed timing breakdown from pipeline
151
-
152
- Returns:
153
- str: Request ID
154
- """
155
- request_id = self.generate_request_id()
156
-
157
- # Extract timing information
158
- pipeline_timings = {}
159
- question_timings = []
160
- request_start_time = ""
161
- request_end_time = ""
162
-
163
- if timing_data:
164
- request_start_time = timing_data.get('start_time', '')
165
- request_end_time = timing_data.get('end_time', '')
166
- pipeline_timings = timing_data.get('pipeline_stages', {})
167
- question_timings = timing_data.get('question_timings', [])
168
-
169
- log_entry = LogEntry(
170
- timestamp=datetime.now().isoformat(),
171
- request_id=request_id,
172
- document_url=document_url,
173
- questions=questions,
174
- answers=answers,
175
- processing_time_seconds=round(processing_time, 2),
176
- total_questions=len(questions),
177
- status=status,
178
- error_message=error_message,
179
- document_id=document_id,
180
- was_preprocessed=was_preprocessed,
181
- request_start_time=request_start_time,
182
- request_end_time=request_end_time,
183
- pipeline_timings=pipeline_timings,
184
- question_timings=question_timings
185
- )
186
-
187
- with self._lock:
188
- self.logs.append(log_entry)
189
-
190
- # Enhanced console logging summary
191
- print(f"\n📊 [{request_id}] REQUEST COMPLETED:")
192
- print(f" 🕐 Duration: {processing_time:.2f}s")
193
- print(f" 📄 Document: {document_url[:60]}...")
194
- print(f" ❓ Questions processed: {len(questions)}")
195
- print(f" ✅ Status: {status.upper()}")
196
-
197
- if pipeline_timings:
198
- print(f" ⚙️ Pipeline performance:")
199
- for stage, data in pipeline_timings.items():
200
- duration = data.get('duration_seconds', 0)
201
- print(f" • {stage.replace('_', ' ').title()}: {duration:.4f}s")
202
-
203
- if error_message:
204
- print(f" ❌ Error: {error_message}")
205
-
206
- print(f" 🆔 Request ID: {request_id}")
207
- print(" " + "="*50)
208
-
209
- return request_id
210
-
211
- def get_logs(self, limit: Optional[int] = None) -> List[Dict[str, Any]]:
212
- """
213
- Get all logs as a list of dictionaries.
214
-
215
- Args:
216
- limit: Maximum number of logs to return (most recent first)
217
-
218
- Returns:
219
- List of log entries as dictionaries
220
- """
221
- with self._lock:
222
- logs_list = [asdict(log) for log in self.logs]
223
-
224
- # Return most recent first
225
- logs_list.reverse()
226
-
227
- if limit:
228
- logs_list = logs_list[:limit]
229
-
230
- return logs_list
231
-
232
- def get_logs_summary(self) -> Dict[str, Any]:
233
- """Get summary statistics of all logs."""
234
- with self._lock:
235
- total_requests = len(self.logs)
236
- if total_requests == 0:
237
- return {
238
- "server_start_time": self.server_start_time,
239
- "total_requests": 0,
240
- "successful_requests": 0,
241
- "error_requests": 0,
242
- "average_processing_time": 0,
243
- "total_questions_processed": 0,
244
- "total_documents_processed": 0
245
- }
246
-
247
- successful_requests = len([log for log in self.logs if log.status == "success"])
248
- error_requests = len([log for log in self.logs if log.status == "error"])
249
- total_processing_time = sum(log.processing_time_seconds for log in self.logs)
250
- total_questions = sum(log.total_questions for log in self.logs)
251
- unique_documents = len(set(log.document_url for log in self.logs))
252
- preprocessed_count = len([log for log in self.logs if log.was_preprocessed])
253
-
254
- # Enhanced timing statistics
255
- pipeline_times = []
256
- question_times = []
257
- stage_times = {'query_expansion': [], 'hybrid_search': [], 'reranking': [],
258
- 'context_creation': [], 'llm_generation': []}
259
-
260
- for log in self.logs:
261
- # Collect question timing data
262
- for q_timing in log.question_timings:
263
- question_times.append(q_timing.get('total_time_seconds', 0))
264
- # Collect stage-specific timings
265
- breakdown = q_timing.get('pipeline_breakdown', {})
266
- for stage, duration in breakdown.items():
267
- if stage in stage_times:
268
- stage_times[stage].append(duration)
269
-
270
- # Calculate averages for each stage
271
- avg_stage_times = {}
272
- for stage, times in stage_times.items():
273
- if times:
274
- avg_stage_times[f'avg_{stage}_time'] = round(sum(times) / len(times), 4)
275
- avg_stage_times[f'max_{stage}_time'] = round(max(times), 4)
276
- else:
277
- avg_stage_times[f'avg_{stage}_time'] = 0
278
- avg_stage_times[f'max_{stage}_time'] = 0
279
-
280
- return {
281
- "server_start_time": self.server_start_time,
282
- "total_requests": total_requests,
283
- "successful_requests": successful_requests,
284
- "error_requests": error_requests,
285
- "partial_requests": total_requests - successful_requests - error_requests,
286
- "success_rate": round((successful_requests / total_requests) * 100, 2),
287
- "average_processing_time": round(total_processing_time / total_requests, 2),
288
- "total_questions_processed": total_questions,
289
- "total_documents_processed": unique_documents,
290
- "documents_already_preprocessed": preprocessed_count,
291
- "documents_newly_processed": total_requests - preprocessed_count,
292
- "average_question_time": round(sum(question_times) / len(question_times), 4) if question_times else 0,
293
- "pipeline_performance": avg_stage_times
294
- }
295
-
296
- def export_logs(self) -> Dict[str, Any]:
297
- """
298
- Export all logs in a structured format for external consumption.
299
-
300
- Returns:
301
- Dict containing metadata and all logs
302
- """
303
- summary = self.get_logs_summary()
304
- logs = self.get_logs()
305
-
306
- return {
307
- "export_timestamp": datetime.now().isoformat(),
308
- "metadata": summary,
309
- "logs": logs
310
- }
311
-
312
- def get_logs_by_document(self, document_url: str) -> List[Dict[str, Any]]:
313
- """Get all logs for a specific document URL."""
314
- with self._lock:
315
- filtered_logs = [
316
- asdict(log) for log in self.logs
317
- if log.document_url == document_url
318
- ]
319
-
320
- # Return most recent first
321
- filtered_logs.reverse()
322
- return filtered_logs
323
-
324
- def get_recent_logs(self, minutes: int = 60) -> List[Dict[str, Any]]:
325
- """Get logs from the last N minutes."""
326
- cutoff_time = datetime.now().timestamp() - (minutes * 60)
327
-
328
- with self._lock:
329
- recent_logs = []
330
- for log in self.logs:
331
- log_time = datetime.fromisoformat(log.timestamp).timestamp()
332
- if log_time >= cutoff_time:
333
- recent_logs.append(asdict(log))
334
-
335
- # Return most recent first
336
- recent_logs.reverse()
337
- return recent_logs
338
-
339
- # Global logger instance
340
- rag_logger = RAGLogger()