mcp-code-indexer 3.1.3__py3-none-any.whl → 3.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,96 +19,92 @@ def setup_logging(
19
19
  log_file: Optional[Path] = None,
20
20
  enable_file_logging: bool = False,
21
21
  max_bytes: int = 50 * 1024 * 1024, # 50MB
22
- backup_count: int = 2
22
+ backup_count: int = 2,
23
23
  ) -> logging.Logger:
24
24
  """
25
25
  Set up comprehensive logging configuration.
26
-
26
+
27
27
  Args:
28
28
  log_level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
29
29
  log_file: Path to log file (optional)
30
30
  enable_file_logging: Whether to enable file logging
31
31
  max_bytes: Maximum size of log file before rotation
32
32
  backup_count: Number of backup files to keep
33
-
33
+
34
34
  Returns:
35
35
  Configured root logger
36
36
  """
37
37
  # Get root logger
38
38
  root_logger = logging.getLogger()
39
39
  root_logger.setLevel(getattr(logging, log_level.upper()))
40
-
40
+
41
41
  # Clear existing handlers
42
42
  root_logger.handlers.clear()
43
-
43
+
44
44
  # Console handler (stderr to avoid interfering with MCP stdout)
45
45
  console_handler = logging.StreamHandler(sys.stderr)
46
46
  console_handler.setLevel(getattr(logging, log_level.upper()))
47
-
47
+
48
48
  # Use structured formatter for all handlers
49
49
  structured_formatter = StructuredFormatter()
50
50
  console_handler.setFormatter(structured_formatter)
51
-
51
+
52
52
  root_logger.addHandler(console_handler)
53
-
53
+
54
54
  # File handler (optional)
55
55
  if enable_file_logging and log_file:
56
56
  try:
57
57
  # Ensure log directory exists
58
58
  log_file.parent.mkdir(parents=True, exist_ok=True)
59
-
59
+
60
60
  # Rotating file handler
61
61
  if max_bytes > 0:
62
62
  file_handler = logging.handlers.RotatingFileHandler(
63
63
  log_file,
64
64
  maxBytes=max_bytes,
65
65
  backupCount=backup_count,
66
- encoding='utf-8'
66
+ encoding="utf-8",
67
67
  )
68
68
  else:
69
69
  # No size limit - use regular FileHandler
70
- file_handler = logging.FileHandler(
71
- log_file,
72
- mode='a',
73
- encoding='utf-8'
74
- )
70
+ file_handler = logging.FileHandler(log_file, mode="a", encoding="utf-8")
75
71
  file_handler.setLevel(logging.DEBUG) # File gets all levels
76
72
  file_handler.setFormatter(structured_formatter)
77
-
73
+
78
74
  root_logger.addHandler(file_handler)
79
-
75
+
80
76
  except (OSError, PermissionError) as e:
81
77
  # Log to console if file logging fails
82
78
  root_logger.warning(f"Failed to set up file logging: {e}")
83
-
79
+
84
80
  # Configure specific loggers
85
-
81
+
86
82
  # Quiet down noisy libraries
87
83
  logging.getLogger("aiosqlite").setLevel(logging.WARNING)
88
84
  logging.getLogger("tiktoken").setLevel(logging.WARNING)
89
-
85
+
90
86
  # MCP specific loggers
91
87
  mcp_logger = logging.getLogger("mcp")
92
88
  mcp_logger.setLevel(logging.INFO)
93
-
89
+
94
90
  # Database logger
95
91
  db_logger = logging.getLogger("src.database")
96
92
  db_logger.setLevel(logging.INFO)
97
-
93
+
98
94
  # Server logger
99
95
  server_logger = logging.getLogger("src.server")
100
96
  server_logger.setLevel(logging.INFO)
101
-
97
+
102
98
  return root_logger
103
99
 
104
100
 
105
101
  def get_logger(name: str) -> logging.Logger:
106
102
  """
107
103
  Get a logger with the specified name.
108
-
104
+
109
105
  Args:
110
106
  name: Logger name (usually __name__)
111
-
107
+
112
108
  Returns:
113
109
  Logger instance
114
110
  """
@@ -116,76 +112,71 @@ def get_logger(name: str) -> logging.Logger:
116
112
 
117
113
 
118
114
  def setup_command_logger(
119
- command_name: str,
120
- cache_dir: Path,
121
- log_level: str = "DEBUG"
115
+ command_name: str, cache_dir: Path, log_level: str = "DEBUG"
122
116
  ) -> logging.Logger:
123
117
  """
124
118
  Set up a dedicated logger for specific commands (runcommand, githook).
125
-
119
+
126
120
  Args:
127
121
  command_name: Name of the command (e.g., 'runcommand', 'githook')
128
122
  cache_dir: Cache directory path
129
123
  log_level: Logging level
130
-
124
+
131
125
  Returns:
132
126
  Configured logger for the command
133
127
  """
134
128
  logger_name = f"mcp_code_indexer.{command_name}"
135
129
  logger = logging.getLogger(logger_name)
136
-
130
+
137
131
  # Don't propagate to parent loggers to avoid duplicate console output
138
132
  logger.propagate = False
139
133
  logger.setLevel(getattr(logging, log_level.upper()))
140
-
134
+
141
135
  # Clear existing handlers
142
136
  logger.handlers.clear()
143
-
137
+
144
138
  # Create log file path
145
139
  log_file = cache_dir / f"{command_name}.log"
146
-
140
+
147
141
  try:
148
142
  # Ensure cache directory exists
149
143
  cache_dir.mkdir(parents=True, exist_ok=True)
150
-
144
+
151
145
  # File handler with 50MB limit
152
146
  file_handler = logging.handlers.RotatingFileHandler(
153
- log_file,
154
- maxBytes=50 * 1024 * 1024, # 50MB
155
- backupCount=2,
156
- encoding='utf-8'
147
+ log_file, maxBytes=50 * 1024 * 1024, backupCount=2, encoding="utf-8" # 50MB
157
148
  )
158
149
  file_handler.setLevel(logging.DEBUG)
159
-
150
+
160
151
  # Use structured formatter
161
152
  structured_formatter = StructuredFormatter()
162
153
  file_handler.setFormatter(structured_formatter)
163
-
154
+
164
155
  logger.addHandler(file_handler)
165
-
156
+
166
157
  # Set up component loggers to also log to this command's log file
167
- _setup_component_loggers_for_command(command_name, file_handler, structured_formatter)
168
-
158
+ _setup_component_loggers_for_command(
159
+ command_name, file_handler, structured_formatter
160
+ )
161
+
169
162
  logger.info(f"=== {command_name.upper()} SESSION STARTED ===")
170
-
163
+
171
164
  except (OSError, PermissionError) as e:
172
165
  # Fallback to console logging
173
166
  console_handler = logging.StreamHandler(sys.stderr)
174
167
  console_handler.setFormatter(StructuredFormatter())
175
168
  logger.addHandler(console_handler)
176
169
  logger.warning(f"Failed to set up {command_name} file logging: {e}")
177
-
170
+
178
171
  return logger
179
172
 
180
173
 
181
174
  def _setup_component_loggers_for_command(
182
- command_name: str,
183
- file_handler: logging.Handler,
184
- formatter: logging.Formatter
175
+ command_name: str, file_handler: logging.Handler, formatter: logging.Formatter
185
176
  ) -> None:
186
177
  """
187
178
  Set up component loggers to also send logs to the command's log file.
188
-
179
+
189
180
  Args:
190
181
  command_name: Name of the command
191
182
  file_handler: File handler to add to component loggers
@@ -194,49 +185,51 @@ def _setup_component_loggers_for_command(
194
185
  # List of component logger names that should also log to command files
195
186
  component_loggers = [
196
187
  "mcp_code_indexer.database.database",
197
- "mcp_code_indexer.server.mcp_server",
188
+ "mcp_code_indexer.server.mcp_server",
198
189
  "mcp_code_indexer.token_counter",
199
190
  "mcp_code_indexer.file_scanner",
200
191
  "mcp_code_indexer.error_handler",
201
-
202
192
  ]
203
-
193
+
204
194
  for component_logger_name in component_loggers:
205
195
  component_logger = logging.getLogger(component_logger_name)
206
-
196
+
207
197
  # Create a separate handler for this command to avoid interference
208
198
  command_handler = logging.handlers.RotatingFileHandler(
209
199
  file_handler.baseFilename,
210
200
  maxBytes=file_handler.maxBytes,
211
201
  backupCount=file_handler.backupCount,
212
- encoding='utf-8'
202
+ encoding="utf-8",
213
203
  )
214
204
  command_handler.setLevel(logging.DEBUG)
215
205
  command_handler.setFormatter(formatter)
216
-
206
+
217
207
  # Add a marker to identify which command this handler belongs to
218
208
  command_handler._command_name = command_name
219
-
209
+
220
210
  # Remove any existing handlers for this command (in case of multiple calls)
221
- existing_handlers = [h for h in component_logger.handlers if hasattr(h, '_command_name') and h._command_name == command_name]
211
+ existing_handlers = [
212
+ h
213
+ for h in component_logger.handlers
214
+ if hasattr(h, "_command_name") and h._command_name == command_name
215
+ ]
222
216
  for handler in existing_handlers:
223
217
  component_logger.removeHandler(handler)
224
218
  handler.close()
225
-
219
+
226
220
  # Add the new handler
227
221
  component_logger.addHandler(command_handler)
228
- component_logger.setLevel(logging.DEBUG) # Ensure component loggers capture all levels
222
+ component_logger.setLevel(
223
+ logging.DEBUG
224
+ ) # Ensure component loggers capture all levels
229
225
 
230
226
 
231
227
  def log_performance_metrics(
232
- logger: logging.Logger,
233
- operation: str,
234
- duration: float,
235
- **metrics
228
+ logger: logging.Logger, operation: str, duration: float, **metrics
236
229
  ) -> None:
237
230
  """
238
231
  Log performance metrics in structured format.
239
-
232
+
240
233
  Args:
241
234
  logger: Logger instance
242
235
  operation: Name of the operation
@@ -246,12 +239,12 @@ def log_performance_metrics(
246
239
  perf_data = {
247
240
  "operation": operation,
248
241
  "duration_seconds": duration,
249
- "metrics": metrics
242
+ "metrics": metrics,
250
243
  }
251
-
244
+
252
245
  logger.info(
253
246
  f"Performance: {operation} completed in {duration:.3f}s",
254
- extra={"structured_data": {"performance": perf_data}}
247
+ extra={"structured_data": {"performance": perf_data}},
255
248
  )
256
249
 
257
250
 
@@ -259,28 +252,25 @@ def log_database_metrics(
259
252
  logger: logging.Logger,
260
253
  operation_name: str,
261
254
  metrics: dict,
262
- health_status: Optional[dict] = None
255
+ health_status: Optional[dict] = None,
263
256
  ) -> None:
264
257
  """
265
258
  Log database performance and health metrics.
266
-
259
+
267
260
  Args:
268
261
  logger: Logger instance
269
262
  operation_name: Name of the database operation
270
263
  metrics: Database performance metrics
271
264
  health_status: Current health status (optional)
272
265
  """
273
- log_data = {
274
- "operation": operation_name,
275
- "metrics": metrics
276
- }
277
-
266
+ log_data = {"operation": operation_name, "metrics": metrics}
267
+
278
268
  if health_status:
279
269
  log_data["health_status"] = health_status
280
-
270
+
281
271
  logger.info(
282
272
  f"Database metrics for {operation_name}",
283
- extra={"structured_data": {"database_metrics": log_data}}
273
+ extra={"structured_data": {"database_metrics": log_data}},
284
274
  )
285
275
 
286
276
 
@@ -290,11 +280,11 @@ def log_tool_usage(
290
280
  arguments: dict,
291
281
  success: bool,
292
282
  duration: Optional[float] = None,
293
- result_size: Optional[int] = None
283
+ result_size: Optional[int] = None,
294
284
  ) -> None:
295
285
  """
296
286
  Log MCP tool usage for analytics.
297
-
287
+
298
288
  Args:
299
289
  logger: Logger instance
300
290
  tool_name: Name of the MCP tool
@@ -310,24 +300,16 @@ def log_tool_usage(
310
300
  safe_args[key] = f"{value[:50]}..."
311
301
  else:
312
302
  safe_args[key] = value
313
-
314
- usage_data = {
315
- "tool_name": tool_name,
316
- "arguments": safe_args,
317
- "success": success
318
- }
319
-
303
+
304
+ usage_data = {"tool_name": tool_name, "arguments": safe_args, "success": success}
305
+
320
306
  if duration is not None:
321
307
  usage_data["duration_seconds"] = duration
322
-
308
+
323
309
  if result_size is not None:
324
310
  usage_data["result_size"] = result_size
325
-
311
+
326
312
  level = logging.INFO if success else logging.WARNING
327
313
  message = f"Tool {tool_name}: {'SUCCESS' if success else 'FAILED'}"
328
-
329
- logger.log(
330
- level,
331
- message,
332
- extra={"structured_data": {"tool_usage": usage_data}}
333
- )
314
+
315
+ logger.log(level, message, extra={"structured_data": {"tool_usage": usage_data}})