Skip to content

Commit 9b7792b

Browse files
committed
scripts/debug: Add debugging helper tool.
1 parent 8e91fde commit 9b7792b

File tree

4 files changed

+222
-1
lines changed

4 files changed

+222
-1
lines changed

README.md

+40
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,46 @@ $ telnet 127.0.0.1 6899
799799
in another terminal, where `127.0.0.1` is the IP address and `6899` is port you
800800
find in `./debug.log`.
801801

802+
#### Remote debugging example
803+
804+
Here's a complete example of how to debug a specific issue:
805+
806+
1. Let's say you suspect an issue when sending messages. Find the function in the codebase that handles this (e.g., in `zulipterminal/ui/ui.py`).
807+
808+
2. Add the debugger statement just before the suspicious code:
809+
```python
810+
def send_message(self):
811+
from pudb.remote import set_trace
812+
set_trace() # This will pause execution here
813+
# Rest of the function...
814+
```
815+
816+
3. Run Zulip Terminal with debug mode enabled:
817+
```bash
818+
zulip-term -d
819+
```
820+
821+
4. When you trigger the send_message function, check debug.log for telnet connection details:
822+
```bash
823+
tail -f debug.log
824+
```
825+
826+
5. Connect with telnet and you'll get an interactive debugger to step through the code.
827+
828+
#### Profiling for performance issues
829+
830+
If you're experiencing performance problems, you can run Zulip Terminal with profiling enabled:
831+
832+
```bash
833+
zulip-term --profile
834+
```
835+
836+
This will create a profile output file which you can analyze using:
837+
838+
```bash
839+
snakeviz zulip-terminal.prof
840+
```
841+
802842
#### There's no effect in Zulip Terminal after making local changes!
803843

804844
This likely means that you have installed both normal and development versions

makefile

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: install-devel check lint test check-clean-tree fix force-fix venv
1+
.PHONY: install-devel check lint test check-clean-tree fix force-fix venv debug debug-profile debug-clean
22

33
# NOTE: ZT_VENV and BASEPYTHON are advanced undocumented features
44
# Customize your venv name by running make as "ZT_VENV=my_venv_name make <command>"
@@ -24,6 +24,20 @@ lint: venv
2424
test: venv
2525
@pytest
2626

27+
### DEBUG TARGETS ###
28+
29+
debug: venv
30+
@echo "=== Running with debug enabled ==="
31+
$(PYTHON) -m zulipterminal.cli.run -d
32+
33+
debug-profile: venv
34+
@echo "=== Running with profiling enabled ==="
35+
$(PYTHON) -m zulipterminal.cli.run --profile
36+
37+
debug-clean:
38+
@echo "=== Cleaning debug files ==="
39+
rm -f debug.log zulip-terminal.prof zulip-terminal-tracebacks.log
40+
2741
### FIX FILES ###
2842

2943
check-clean-tree:

setup.py

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def long_description():
5454
helper_deps = [
5555
"pudb==2022.1.1",
5656
"snakeviz>=2.1.1",
57+
"requests>=2.25.0", # Added for debug_helper.py
5758
]
5859

5960
setup(
@@ -93,6 +94,8 @@ def long_description():
9394
"console_scripts": [
9495
"zulip-term = zulipterminal.cli.run:main",
9596
"zulip-term-check-symbols = zulipterminal.scripts.render_symbols:main",
97+
# Added debug helper with proper path
98+
"zulip-term-debug = zulipterminal.scripts.debug_helper:main",
9699
],
97100
},
98101
extras_require={

zulipterminal/scripts/debug_helper.py

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Helper script for debugging Zulip Terminal.
4+
5+
This script provides utilities for common debugging tasks:
6+
1. Analyzing debug logs
7+
2. Testing connectivity to Zulip server
8+
3. Checking terminal capabilities
9+
"""
10+
11+
import argparse
12+
import json
13+
import logging
14+
import os
15+
import re
16+
import subprocess
17+
from typing import Optional
18+
19+
20+
# Configure logging
21+
logging.basicConfig(level=logging.INFO)
22+
logger = logging.getLogger(__name__)
23+
24+
25+
def analyze_debug_log(log_file: str = "debug.log") -> None:
26+
"""
27+
Analyze a debug log file for common issues.
28+
"""
29+
if not os.path.exists(log_file):
30+
logger.error("Log file '%s' not found", log_file)
31+
return
32+
33+
logger.info("Analyzing %s...", log_file)
34+
with open(log_file, "r") as f:
35+
content = f.read()
36+
37+
# Look for error patterns
38+
error_patterns = [r"ERROR", r"Exception", r"Traceback", r"Failed to"]
39+
40+
errors_found = False
41+
for pattern in error_patterns:
42+
matches = re.finditer(pattern, content, re.IGNORECASE)
43+
for match in matches:
44+
line_start = content.rfind("\n", 0, match.start()) + 1
45+
line_end = content.find("\n", match.end())
46+
if line_end == -1:
47+
line_end = len(content)
48+
49+
line = content[line_start:line_end].strip()
50+
logger.warning("Potential issue found: %s", line)
51+
errors_found = True
52+
53+
if not errors_found:
54+
logger.info("No obvious errors found in the log file.")
55+
56+
57+
def test_connectivity(server_url: Optional[str] = None) -> None:
58+
"""
59+
Test connectivity to a Zulip server.
60+
"""
61+
if not server_url:
62+
# Try to get server URL from zuliprc
63+
zuliprc_path = os.path.expanduser("~/.zuliprc")
64+
if os.path.exists(zuliprc_path):
65+
with open(zuliprc_path, "r") as f:
66+
for line in f:
67+
if line.startswith("site="):
68+
server_url = line.split("=")[1].strip()
69+
break
70+
71+
if not server_url:
72+
logger.error("No server URL provided and couldn't find one in ~/.zuliprc")
73+
return
74+
75+
logger.info("Testing connectivity to %s...", server_url)
76+
try:
77+
import requests
78+
79+
response = requests.get(f"{server_url}/api/v1/server_settings")
80+
if response.status_code == 200:
81+
logger.info("Successfully connected to %s", server_url)
82+
try:
83+
settings = response.json()
84+
logger.info(
85+
"Server version: %s", settings.get("zulip_version", "unknown")
86+
)
87+
except json.JSONDecodeError:
88+
logger.error("Received response, but couldn't parse as JSON")
89+
else:
90+
logger.error("Failed to connect: HTTP status %s", response.status_code)
91+
except Exception as e:
92+
logger.error("Connection error: %s", e)
93+
94+
95+
def check_terminal_capabilities() -> None:
96+
"""
97+
Check for terminal capabilities that might affect Zulip Terminal.
98+
"""
99+
logger.info("Checking terminal capabilities...")
100+
101+
# Check for color support
102+
colors = os.environ.get("TERM", "unknown")
103+
logger.info("TERM environment: %s", colors)
104+
105+
if "COLORTERM" in os.environ:
106+
logger.info("COLORTERM: %s", os.environ["COLORTERM"])
107+
108+
# Check for Unicode support
109+
logger.info("Testing Unicode rendering capabilities:")
110+
test_chars = [
111+
("Basic symbols", "▶ ◀ ✓ ✗"),
112+
("Emoji (simple)", "😀 🙂 👍"),
113+
("Box drawing", "│ ┌ ┐ └ ┘ ├ ┤ ┬ ┴ ┼"),
114+
("Math symbols", "∞ ∑ √ ∫ π"),
115+
]
116+
117+
for name, chars in test_chars:
118+
logger.info(" %s: %s", name, chars)
119+
120+
121+
def main() -> None:
122+
"""
123+
Main entry point for the debugging helper.
124+
"""
125+
parser = argparse.ArgumentParser(description="Zulip Terminal Debugging Helper")
126+
subparsers = parser.add_subparsers(dest="command", help="Command to run")
127+
128+
# Log analyzer
129+
log_parser = subparsers.add_parser("log", help="Analyze debug logs")
130+
log_parser.add_argument("--file", default="debug.log", help="Log file to analyze")
131+
132+
# Connectivity test
133+
conn_parser = subparsers.add_parser("connect", help="Test connectivity")
134+
conn_parser.add_argument(
135+
"--server", help="Server URL (e.g., https://chat.zulip.org)"
136+
)
137+
138+
# Terminal test
139+
subparsers.add_parser("terminal", help="Check terminal capabilities")
140+
141+
# Run zulip-term with debug
142+
run_parser = subparsers.add_parser("run", help="Run zulip-term with debugging")
143+
run_parser.add_argument("--profile", action="store_true", help="Enable profiling")
144+
145+
args = parser.parse_args()
146+
147+
if args.command == "log":
148+
analyze_debug_log(args.file)
149+
elif args.command == "connect":
150+
test_connectivity(args.server)
151+
elif args.command == "terminal":
152+
check_terminal_capabilities()
153+
elif args.command == "run":
154+
cmd = ["zulip-term", "-d"]
155+
if args.profile:
156+
cmd.append("--profile")
157+
logger.info("Running: %s", " ".join(cmd))
158+
subprocess.run(cmd, check=False)
159+
else:
160+
parser.print_help()
161+
162+
163+
if __name__ == "__main__":
164+
main()

0 commit comments

Comments
 (0)