Skip to content

Commit b4cc34a

Browse files
committed
feat: add logging and metrics collection for indexing and search operations
1 parent d924d3e commit b4cc34a

File tree

7 files changed

+645
-7
lines changed

7 files changed

+645
-7
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ Checks if the index is ready and healthy.
198198
### `index_health_check`
199199
Maintenance tool to remove stale entries from deleted files and orphaned embeddings/chunks from the database.
200200

201+
### `index_metrics`
202+
Returns collected metrics about indexing and search performance. Requires `debug.enabled` and `debug.metrics` to be `true`.
203+
- **Metrics include**: Files indexed, chunks created, cache hit rate, search timing breakdown, GC stats, embedding API call stats.
204+
205+
### `index_logs`
206+
Returns recent debug logs with optional filtering.
207+
- **Parameters**: `category` (optional: `search`, `embedding`, `cache`, `gc`, `branch`), `level` (optional: `error`, `warn`, `info`, `debug`), `limit` (default: 50).
208+
201209
## 🎮 Slash Commands
202210

203211
The plugin automatically registers these slash commands:
@@ -232,6 +240,11 @@ Zero-config by default (uses `auto` mode). Customize in `.opencode/codebase-inde
232240
"minScore": 0.1,
233241
"hybridWeight": 0.5,
234242
"contextLines": 0
243+
},
244+
"debug": {
245+
"enabled": false,
246+
"logLevel": "info",
247+
"metrics": false
235248
}
236249
}
237250
```
@@ -258,6 +271,15 @@ Zero-config by default (uses `auto` mode). Customize in `.opencode/codebase-inde
258271
| `minScore` | `0.1` | Minimum similarity score (0-1). Lower = more results |
259272
| `hybridWeight` | `0.5` | Balance between keyword (1.0) and semantic (0.0) search |
260273
| `contextLines` | `0` | Extra lines to include before/after each match |
274+
| **debug** | | |
275+
| `enabled` | `false` | Enable debug logging and metrics collection |
276+
| `logLevel` | `"info"` | Log level: `error`, `warn`, `info`, `debug` |
277+
| `logSearch` | `true` | Log search operations with timing breakdown |
278+
| `logEmbedding` | `true` | Log embedding API calls (success, error, rate-limit) |
279+
| `logCache` | `true` | Log cache hits and misses |
280+
| `logGc` | `true` | Log garbage collection operations |
281+
| `logBranch` | `true` | Log branch detection and switches |
282+
| `metrics` | `false` | Enable metrics collection (indexing stats, search timing, cache performance) |
261283

262284
### Embedding Providers
263285
The plugin automatically detects available credentials in this order:

src/config/schema.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,34 @@ export interface SearchConfig {
2525
contextLines: number;
2626
}
2727

28+
export type LogLevel = "error" | "warn" | "info" | "debug";
29+
30+
export interface DebugConfig {
31+
enabled: boolean;
32+
logLevel: LogLevel;
33+
logSearch: boolean;
34+
logEmbedding: boolean;
35+
logCache: boolean;
36+
logGc: boolean;
37+
logBranch: boolean;
38+
metrics: boolean;
39+
}
40+
2841
export interface CodebaseIndexConfig {
2942
embeddingProvider: EmbeddingProvider;
3043
embeddingModel: string;
3144
scope: IndexScope;
3245
indexing?: Partial<IndexingConfig>;
3346
search?: Partial<SearchConfig>;
47+
debug?: Partial<DebugConfig>;
3448
include: string[];
3549
exclude: string[];
3650
}
3751

3852
export type ParsedCodebaseIndexConfig = CodebaseIndexConfig & {
3953
indexing: IndexingConfig;
4054
search: SearchConfig;
55+
debug: DebugConfig;
4156
};
4257

4358
const DEFAULT_INCLUDE = [
@@ -94,8 +109,22 @@ function getDefaultSearchConfig(): SearchConfig {
94109
};
95110
}
96111

112+
function getDefaultDebugConfig(): DebugConfig {
113+
return {
114+
enabled: false,
115+
logLevel: "info",
116+
logSearch: true,
117+
logEmbedding: true,
118+
logCache: true,
119+
logGc: true,
120+
logBranch: true,
121+
metrics: true,
122+
};
123+
}
124+
97125
const VALID_PROVIDERS: EmbeddingProvider[] = ["auto", "github-copilot", "openai", "google", "ollama"];
98126
const VALID_SCOPES: IndexScope[] = ["project", "global"];
127+
const VALID_LOG_LEVELS: LogLevel[] = ["error", "warn", "info", "debug"];
99128

100129
function isValidProvider(value: unknown): value is EmbeddingProvider {
101130
return typeof value === "string" && VALID_PROVIDERS.includes(value as EmbeddingProvider);
@@ -109,11 +138,17 @@ function isStringArray(value: unknown): value is string[] {
109138
return Array.isArray(value) && value.every(item => typeof item === "string");
110139
}
111140

141+
function isValidLogLevel(value: unknown): value is LogLevel {
142+
return typeof value === "string" && VALID_LOG_LEVELS.includes(value as LogLevel);
143+
}
144+
112145
export function parseConfig(raw: unknown): ParsedCodebaseIndexConfig {
113146
const input = (raw && typeof raw === "object" ? raw : {}) as Record<string, unknown>;
114147

115148
const defaultIndexing = getDefaultIndexingConfig();
116149
const defaultSearch = getDefaultSearchConfig();
150+
const defaultDebug = getDefaultDebugConfig();
151+
117152
const rawIndexing = (input.indexing && typeof input.indexing === "object" ? input.indexing : {}) as Record<string, unknown>;
118153
const indexing: IndexingConfig = {
119154
autoIndex: typeof rawIndexing.autoIndex === "boolean" ? rawIndexing.autoIndex : defaultIndexing.autoIndex,
@@ -137,6 +172,18 @@ export function parseConfig(raw: unknown): ParsedCodebaseIndexConfig {
137172
contextLines: typeof rawSearch.contextLines === "number" ? Math.min(50, Math.max(0, rawSearch.contextLines)) : defaultSearch.contextLines,
138173
};
139174

175+
const rawDebug = (input.debug && typeof input.debug === "object" ? input.debug : {}) as Record<string, unknown>;
176+
const debug: DebugConfig = {
177+
enabled: typeof rawDebug.enabled === "boolean" ? rawDebug.enabled : defaultDebug.enabled,
178+
logLevel: isValidLogLevel(rawDebug.logLevel) ? rawDebug.logLevel : defaultDebug.logLevel,
179+
logSearch: typeof rawDebug.logSearch === "boolean" ? rawDebug.logSearch : defaultDebug.logSearch,
180+
logEmbedding: typeof rawDebug.logEmbedding === "boolean" ? rawDebug.logEmbedding : defaultDebug.logEmbedding,
181+
logCache: typeof rawDebug.logCache === "boolean" ? rawDebug.logCache : defaultDebug.logCache,
182+
logGc: typeof rawDebug.logGc === "boolean" ? rawDebug.logGc : defaultDebug.logGc,
183+
logBranch: typeof rawDebug.logBranch === "boolean" ? rawDebug.logBranch : defaultDebug.logBranch,
184+
metrics: typeof rawDebug.metrics === "boolean" ? rawDebug.metrics : defaultDebug.metrics,
185+
};
186+
140187
return {
141188
embeddingProvider: isValidProvider(input.embeddingProvider) ? input.embeddingProvider : "auto",
142189
embeddingModel: typeof input.embeddingModel === "string" ? input.embeddingModel : "auto",
@@ -145,6 +192,7 @@ export function parseConfig(raw: unknown): ParsedCodebaseIndexConfig {
145192
exclude: isStringArray(input.exclude) ? input.exclude : DEFAULT_EXCLUDE,
146193
indexing,
147194
search,
195+
debug,
148196
};
149197
}
150198

src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
index_codebase,
1313
index_status,
1414
index_health_check,
15+
index_metrics,
16+
index_logs,
1517
initializeTools,
1618
} from "./tools/index.js";
1719
import { loadCommandsFromDirectory } from "./commands/loader.js";
@@ -76,6 +78,8 @@ const plugin: Plugin = async ({ directory }) => {
7678
index_codebase,
7779
index_status,
7880
index_health_check,
81+
index_metrics,
82+
index_logs,
7983
},
8084

8185
async config(cfg) {

0 commit comments

Comments
 (0)