sql-cli 1.73.1

SQL query tool for CSV/JSON with both interactive TUI and non-interactive CLI modes - perfect for exploration and automation
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# Neovim Plugin Logging System

**Date**: 2025-10-04
**Status**: ✅ Implemented

## Overview

Comprehensive file-based logging system for the SQL CLI Neovim plugin. Logs are written to the same directory as the TUI logs (`~/.local/share/sql-cli/logs/`) with automatic rotation and cleanup.

## Features

### Core Functionality
- **File-based logging** - All logs written to timestamped files
- **Automatic rotation** - New log file per Neovim session
- **Configurable retention** - Automatically deletes old log files (default: keep 20 most recent)
- **Log levels** - TRACE, DEBUG, INFO, WARN, ERROR
- **Buffered writes** - Performance-optimized with configurable buffer size
- **Auto-flush** - Periodic flushing with configurable interval
- **Thread-safe** - Safe for concurrent access
- **Cross-platform** - Works on Unix and Windows

### Integration
- **Unified log directory** - Same location as TUI logs
- **Symlink to latest** - `latest.log` always points to current session
- **Easy access** - Commands to open, tail, and locate log files
- **Module-level logging** - Each module logs with its own target/context

## Configuration

### Default Settings

```lua
require('sql-cli').setup({
  logging = {
    enabled = true,                -- Enable file logging
    level = "INFO",                -- Log level: TRACE, DEBUG, INFO, WARN, ERROR
    max_files = 20,                -- Maximum number of log files to keep
    buffer_size = 100,             -- Messages to buffer before flush
    auto_flush_interval = 5000,    -- Auto-flush every 5 seconds (ms)
  },
})
```

### Changing Log Level

For debugging, set level to DEBUG or TRACE:

```lua
require('sql-cli').setup({
  logging = {
    level = "DEBUG",  -- More verbose logging
  },
})
```

### Disabling Logging

```lua
require('sql-cli').setup({
  logging = {
    enabled = false,  -- Completely disable logging
  },
})
```

## Usage

### Commands

| Command | Description |
|---------|-------------|
| `:SqlCliOpenLog` | Open current log file in a split |
| `:SqlCliTailLog` | Tail log file with live updates |
| `:SqlCliLogPath` | Show and copy log path to clipboard |

### File Locations

**Unix/Linux:**
```
~/.local/share/sql-cli/logs/nvim-plugin_YYYYMMDD_HHMMSS.log
~/.local/share/sql-cli/logs/latest.log (symlink)
```

**Windows:**
```
%LOCALAPPDATA%\sql-cli\logs\nvim-plugin_YYYYMMDD_HHMMSS.log
%LOCALAPPDATA%\sql-cli\logs\latest.log (text pointer file)
```

### Viewing Logs

#### In Terminal
```bash
# View current log
cat ~/.local/share/sql-cli/logs/latest.log

# Tail current log
tail -f ~/.local/share/sql-cli/logs/latest.log

# List all plugin logs
ls -lh ~/.local/share/sql-cli/logs/nvim-plugin*.log

# Search logs
grep ERROR ~/.local/share/sql-cli/logs/nvim-plugin*.log
```

#### In Neovim
```vim
:SqlCliOpenLog    " Open in split
:SqlCliTailLog    " Tail with auto-refresh
```

## For Developers

### Adding Logging to a Module

```lua
-- At top of module
local M = {}

-- Get logger (lazy load to avoid circular dependencies)
local logger = nil
local function get_logger()
  if not logger then
    logger = require('sql-cli').logger
  end
  return logger
end

-- Use in functions
function M.some_function(arg)
  local log = get_logger()
  if log then
    log.info('my_module', 'some_function called with arg: ' .. tostring(arg))
  end

  -- ... function logic ...

  if some_error then
    if log then
      log.error('my_module', 'Error occurred: ' .. error_msg)
    end
  end
end
```

### Log Level Functions

```lua
local log = require('sql-cli').logger

-- Different log levels
log.trace('module', 'Very detailed trace message')
log.debug('module', 'Debug information')
log.info('module', 'Informational message')
log.warn('module', 'Warning message')
log.error('module', 'Error message')

-- Auto-detect module context
log.auto('INFO', 'Message with auto-detected module')

-- Log a table
log.log_table('DEBUG', 'module', some_table, 'table_name')
```

### Direct Logger Access

```lua
-- Access logger from any module
local sql_cli = require('sql-cli')
local log = sql_cli.logger

-- Check if logging is enabled
if log and log.config.enabled then
  log.info('init', 'Logging is active')
end

-- Flush immediately
log.flush()

-- Get log file path
local path = log.get_log_path()
```

### Best Practices

1. **Use appropriate log levels**:
   - `TRACE`: Very detailed flow tracking
   - `DEBUG`: Diagnostic information
   - `INFO`: General informational messages
   - `WARN`: Potentially problematic situations
   - `ERROR`: Error events

2. **Use meaningful targets**:
   ```lua
   -- Good
   log.info('executor', 'Executing query: ' .. query)
   log.debug('fuzzy_filter', 'Parsed ' .. row_count .. ' rows')

   -- Bad
   log.info('general', 'Doing something')
   log.info('unknown', 'An event occurred')
   ```

3. **Lazy load logger**:
   - Prevents circular dependencies
   - Doesn't fail if logging is disabled
   - Always check if logger exists before using

4. **Log meaningful context**:
   ```lua
   -- Good
   log.error('parser', 'Failed to parse query at line ' .. line .. ': ' .. error)

   -- Bad
   log.error('parser', 'Parse error')
   ```

5. **Use structured logging**:
   ```lua
   log.info('query', string.format('Query executed in %.2fms, returned %d rows',
     elapsed_ms, row_count))
   ```

## Log Format

```
[HH:MM:SS] LEVEL [target] message
```

Example:
```
[14:32:15] INFO [executor] Executing query: SELECT * FROM data
[14:32:15] DEBUG [fuzzy_filter] Parsed table with 1000 rows, 5 columns
[14:32:16] WARN [parser] Query contains deprecated syntax
[14:32:17] ERROR [loader] Failed to load data file: file not found
```

## Automatic Cleanup

The logger automatically:
- Deletes old log files when count exceeds `max_files`
- Keeps the most recent logs based on modification time
- Runs cleanup on initialization
- Logs cleanup activity

Example:
```
[14:30:00] INFO [logger] SQL CLI Neovim Plugin logging initialized
[14:30:00] DEBUG [logger] Deleted old log file: nvim-plugin_20250901_120000.log
[14:30:00] DEBUG [logger] Deleted old log file: nvim-plugin_20250902_080000.log
```

## Performance

### Buffering
- Logs are buffered in memory (default: 100 messages)
- Automatically flushed when buffer is full
- Auto-flush timer ensures periodic writes (default: 5 seconds)
- Manual flush available via `log.flush()`

### Impact
- Minimal performance impact with buffering
- File I/O only on flush events
- No overhead when logging is disabled

## Troubleshooting

### Log File Not Created

1. **Check if logging is enabled**:
   ```lua
   :lua print(require('sql-cli').logger.config.enabled)
   ```

2. **Check directory permissions**:
   ```bash
   ls -ld ~/.local/share/sql-cli/logs/
   ```

3. **Check for initialization errors**:
   ```vim
   :messages
   ```

### Logs Not Appearing

1. **Check log level**:
   ```lua
   :lua print(require('sql-cli').logger.config.level)
   ```

2. **Manually flush**:
   ```lua
   :lua require('sql-cli').logger.flush()
   ```

3. **Check buffer hasn't filled**:
   - Increase buffer_size or decrease auto_flush_interval

### Too Many Log Files

1. **Reduce retention**:
   ```lua
   require('sql-cli').setup({
     logging = { max_files = 10 }
   })
   ```

2. **Manual cleanup**:
   ```bash
   cd ~/.local/share/sql-cli/logs
   ls -t nvim-plugin*.log | tail -n +11 | xargs rm
   ```

## Comparison with TUI Logs

| Aspect | TUI Logs | Plugin Logs |
|--------|----------|-------------|
| Location | `~/.local/share/sql-cli/logs/sql-cli_*.log` | `~/.local/share/sql-cli/logs/nvim-plugin_*.log` |
| Language | Rust (tracing crate) | Lua (custom logger) |
| Rotation | Per TUI session | Per Neovim session |
| Format | Same format | Same format |
| Viewing | F5 in TUI + file | Commands + file |

Both log to the same directory for centralized troubleshooting.

## Examples

### Example 1: Debugging Query Execution

```lua
-- In executor.lua
local log = get_logger()

function execute_query(query, config, state)
  if log then
    log.info('executor', 'Executing query: ' .. query)
    log.debug('executor', 'Config: output_format=' .. config.output_format)
  end

  local start_time = vim.loop.hrtime()

  -- Execute query...

  local elapsed = (vim.loop.hrtime() - start_time) / 1000000  -- Convert to ms

  if log then
    log.info('executor', string.format('Query completed in %.2fms', elapsed))
  end
end
```

**Log output:**
```
[14:45:00] INFO [executor] Executing query: SELECT * FROM sales WHERE amount > 100
[14:45:00] DEBUG [executor] Config: output_format=table
[14:45:00] INFO [executor] Query completed in 23.45ms
```

### Example 2: Debugging Fuzzy Filter

```lua
-- In fuzzy_filter.lua
function M.open_fuzzy_finder(bufnr)
  local log = get_logger()
  if log then
    log.debug('fuzzy_filter', 'Opening fuzzy finder for buffer ' .. bufnr)
  end

  local data = parse_table_from_buffer(bufnr)
  if not data then
    if log then
      log.warn('fuzzy_filter', 'No table found in buffer ' .. bufnr)
    end
    return
  end

  if log then
    log.info('fuzzy_filter', string.format('Parsed table: %d rows, %d columns',
      #data.rows, #data.headers))
    log.debug('fuzzy_filter', 'Match mode: ' .. M.config.match_mode)
  end

  -- Continue...
end
```

**Log output:**
```
[15:00:00] DEBUG [fuzzy_filter] Opening fuzzy finder for buffer 3
[15:00:00] INFO [fuzzy_filter] Parsed table: 1000 rows, 5 columns
[15:00:00] DEBUG [fuzzy_filter] Match mode: exact
```

## Related Files

- `nvim-plugin/lua/sql-cli/logger.lua` - Logger implementation
- `nvim-plugin/lua/sql-cli/init.lua` - Initialization and commands
- `nvim-plugin/lua/sql-cli/config.lua` - Configuration defaults
- `nvim-plugin/test_logger.lua` - Test suite

## See Also

- [FUZZY_FILTER_EXACT_MODE.md]FUZZY_FILTER_EXACT_MODE.md - Uses logging for debug
- TUI logging in `src/utils/logging.rs` - Similar concepts in Rust