-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcapture-logs.sh
More file actions
executable file
·270 lines (243 loc) · 8.91 KB
/
Copy pathcapture-logs.sh
File metadata and controls
executable file
·270 lines (243 loc) · 8.91 KB
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
#!/bin/bash
# ZMK USB Logging Capture Script
# Usage: ./capture-logs.sh
DEVICE="/dev/ttyACM0"
LOGFILE=""
USB_LOG=""
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PID_FILE="logs/capture.pid"
CHILD_PID=""
USB_MONITOR_PID=""
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Stop current script/tio child and strip ANSI from its log
stop_child() {
if [ -n "$CHILD_PID" ] && kill -0 "$CHILD_PID" 2>/dev/null; then
kill "$CHILD_PID" 2>/dev/null
wait "$CHILD_PID" 2>/dev/null
fi
# Kill any tio still holding the device (script doesn't always forward signals)
fuser -k "$DEVICE" 2>/dev/null
sleep 0.5
# Strip ANSI escape codes and script header/footer now that script is done writing
if [ -f "$LOGFILE" ]; then
sed -i 's/\x1b\[[0-9;]*m//g; s/\r//g' "$LOGFILE"
sed -i '/^Script started on/d; /^Script done on/d' "$LOGFILE"
fi
}
# Monitor USB connection status and kernel events for the device.
# Writes timestamped events to a sidecar log alongside the serial capture.
start_usb_monitor() {
# Find the USB bus path for our device (e.g. "1-1.3")
local usb_path
usb_path=$(udevadm info "$DEVICE" 2>/dev/null | grep -oP 'usb\d+/\K[0-9.-]+(?=/)' | head -1)
if [ -z "$usb_path" ]; then
echo -e "${YELLOW}Could not determine USB bus path — USB monitoring disabled${NC}"
return
fi
USB_LOG="${LOGFILE%.log}_usb.log"
echo "[$(date '+%H:%M:%S')] USB monitor started for $DEVICE (bus $usb_path)" > "$USB_LOG"
echo "[$(date '+%H:%M:%S')] USB device: $(lsusb -d 1d50:615e 2>/dev/null)" >> "$USB_LOG"
(
# Stream kernel USB events for this device
journalctl -k -f --no-pager -g "$usb_path" 2>/dev/null | while IFS= read -r line; do
echo "[$(date '+%H:%M:%S')] KERNEL: $line" >> "$USB_LOG"
# Also print to terminal for visibility
echo -e "${RED}[USB] $line${NC}"
done
) &
USB_MONITOR_PID=$!
# Periodic device health check (every 60s)
(
while true; do
sleep 60
if [ -e "$DEVICE" ]; then
# Check if device is still enumerated
if lsusb -d 1d50:615e >/dev/null 2>&1; then
echo "[$(date '+%H:%M:%S')] POLL: device present" >> "$USB_LOG"
else
echo "[$(date '+%H:%M:%S')] POLL: DEVICE MISSING from lsusb!" >> "$USB_LOG"
echo -e "${RED}[USB] Device disappeared from lsusb!${NC}"
fi
else
echo "[$(date '+%H:%M:%S')] POLL: $DEVICE node gone!" >> "$USB_LOG"
echo -e "${RED}[USB] $DEVICE no longer exists!${NC}"
fi
done
) &
USB_POLL_PID=$!
}
stop_usb_monitor() {
# Kill subshells and their children (journalctl, sleep)
[ -n "$USB_MONITOR_PID" ] && pkill -P "$USB_MONITOR_PID" 2>/dev/null && kill "$USB_MONITOR_PID" 2>/dev/null
[ -n "$USB_POLL_PID" ] && pkill -P "$USB_POLL_PID" 2>/dev/null && kill "$USB_POLL_PID" 2>/dev/null
USB_MONITOR_PID=""
USB_POLL_PID=""
# Strip ANSI from USB log too
[ -f "$USB_LOG" ] && sed -i 's/\x1b\[[0-9;]*m//g; s/\r//g' "$USB_LOG"
}
# Start a new capture child with a fresh log file
start_child() {
LOGFILE="logs/zmk_$(date +%Y%m%d_%H%M%S).log"
if command -v tio &> /dev/null; then
script -q "$LOGFILE" -c "tio -t $DEVICE" &
CHILD_PID=$!
else
script -q "$LOGFILE" -c "cat $DEVICE" &
CHILD_PID=$!
fi
start_usb_monitor
echo -e "${GREEN}Log file: $LOGFILE${NC}"
}
# Generate report on current log without stopping capture
generate_report() {
if [ -f "$LOGFILE" ] && [ -s "$LOGFILE" ]; then
echo -e "\n${BLUE}Generating analysis report...${NC}"
local report="logs/report_$(date +%Y%m%d_%H%M%S).txt"
"$SCRIPT_DIR/analyze-log.sh" "$LOGFILE" "$report"
echo -e "${GREEN}Report: $report${NC}"
fi
}
# SIGUSR1: generate report on current log, then start fresh log
generate_report_and_rotate() {
stop_usb_monitor
stop_child
generate_report
start_child
}
trap generate_report_and_rotate USR1
# Ctrl+C / SIGTERM: request stop. The wait loop checks this flag.
STOP_REQUESTED=0
trap 'STOP_REQUESTED=1' INT TERM
# Cleanup on exit: stop child, generate final report
cleanup() {
echo -e "\n${YELLOW}Stopping log capture...${NC}"
stop_usb_monitor
stop_child
if [ -f "$LOGFILE" ] && [ -s "$LOGFILE" ]; then
echo -e "${BLUE}Generating final report...${NC}"
local report="logs/report_$(date +%Y%m%d_%H%M%S).txt"
"$SCRIPT_DIR/analyze-log.sh" "$LOGFILE" "$report"
echo -e "${GREEN}Report: $report${NC}"
fi
rm -f "$PID_FILE"
}
trap cleanup EXIT
echo "=== ZMK USB Logging Capture ==="
echo ""
# Create logs directory if it doesn't exist
mkdir -p logs
# Check for tio and offer to install if missing
if ! command -v tio &> /dev/null; then
echo -e "${YELLOW}⚠ 'tio' is not installed${NC}"
echo ""
echo "'tio' is a modern serial device tool with better features than cat."
echo "It provides:"
echo " - Proper terminal handling"
echo " - Auto-reconnect on disconnect"
echo " - Built-in timestamping"
echo " - Color output"
echo ""
read -p "Would you like to install tio? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Installing tio (requires sudo)..."
sudo apt-get update -qq && sudo apt-get install -y tio
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ tio installed successfully${NC}"
echo ""
else
echo -e "${RED}✗ Failed to install tio${NC}"
echo "Continuing with 'cat' fallback..."
echo ""
fi
else
echo "Continuing with 'cat' fallback..."
echo ""
fi
fi
# Wait for device if not connected yet
if [ ! -e "$DEVICE" ]; then
echo -e "${YELLOW}Waiting for $DEVICE — plug in the keyboard...${NC}"
while [ ! -e "$DEVICE" ]; do
sleep 1
done
echo -e "${GREEN}✓ Device appeared${NC}"
fi
echo -e "${GREEN}✓ Found device: $DEVICE${NC}"
echo ""
echo -e "${YELLOW}⚠ IMPORTANT: Make sure keyboard output is set to BLE, not USB${NC}"
echo -e "${YELLOW} Press the &out OUT_BLE key combo (OS_FnNumbers layer) if needed.${NC}"
echo -e "${YELLOW} This ensures keyboard data flows over BT while logs stream over USB.${NC}"
echo -e "${YELLOW} The setting persists across reboots - you only need to set it once.${NC}"
# Check if we have permission to access the device
if [ ! -r "$DEVICE" ] || [ ! -w "$DEVICE" ]; then
echo -e "${YELLOW}⚠ No permission to access $DEVICE${NC}"
echo ""
echo "Options:"
echo "1. Add your user to the 'dialout' group (recommended, permanent):"
echo " sudo usermod -a -G dialout $USER"
echo " Then log out and log back in"
echo ""
echo "2. Use sudo for this session (temporary):"
echo " sudo chmod 666 $DEVICE"
echo ""
read -p "Would you like to add yourself to the dialout group? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sudo usermod -a -G dialout $USER
echo -e "${GREEN}✓ Added to dialout group${NC}"
echo ""
echo -e "${YELLOW}⚠ You must log out and log back in for this to take effect${NC}"
echo ""
read -p "Use sudo for this session? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sudo chmod 666 $DEVICE
echo -e "${GREEN}✓ Device permissions updated for this session${NC}"
else
echo "Please log out and log back in, then run this script again."
exit 0
fi
else
read -p "Use sudo for this session? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sudo chmod 666 $DEVICE
echo -e "${GREEN}✓ Device permissions updated for this session${NC}"
else
echo "Cannot continue without device access. Exiting."
exit 1
fi
fi
echo ""
fi
# Clean all previous logs and reports for a fresh session
rm -f logs/zmk_*.log logs/zmk_*_usb.log logs/report_*.txt
# Display capture info
echo "Device: $DEVICE"
echo ""
echo -e "${GREEN}Starting log capture...${NC}"
echo "Press Ctrl+C to stop and generate report"
echo "Run ./generate-report.sh from another terminal to rotate log and generate report"
echo "---"
echo ""
# Write PID file for generate-report.sh
echo $$ > "$PID_FILE"
# Start capture: `script` gives tio a real PTY (tio exits if stdout is a pipe).
# Runs in background; `wait` is signal-interruptible unlike `read`.
start_child
# Wait for Enter (or Ctrl+C / SIGTERM) to stop capture.
# `read -t 1` polls with a 1-second timeout to also check child liveness.
echo "Press Enter or Ctrl+C to stop and generate report"
echo ""
while kill -0 "$CHILD_PID" 2>/dev/null; do
if read -t 1 -r input 2>/dev/null; then
break
fi
[ "$STOP_REQUESTED" -eq 1 ] && break
done