From bc20664c1896b6a4259111a124437e3caa665c87 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 7 Dec 2025 02:25:55 +0100 Subject: [PATCH] tools: add clawlog helper for unified logs --- scripts/clawlog.sh | 309 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100755 scripts/clawlog.sh diff --git a/scripts/clawlog.sh b/scripts/clawlog.sh new file mode 100755 index 000000000..2259a2271 --- /dev/null +++ b/scripts/clawlog.sh @@ -0,0 +1,309 @@ +#!/bin/bash + +# VibeTunnel Logging Utility +# Simplifies access to VibeTunnel logs using macOS unified logging system + +set -euo pipefail + +# Configuration +SUBSYSTEM="com.steipete.clawdis" +DEFAULT_LEVEL="info" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to handle sudo password errors +handle_sudo_error() { + echo -e "\n${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${YELLOW}⚠️ Password Required for Log Access${NC}" + echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n" + echo -e "vtlog needs to use sudo to show complete log data (Apple hides sensitive info by default)." + echo -e "\nTo avoid password prompts, configure passwordless sudo for the log command:" + echo -e "See: ${BLUE}apple/docs/logging-private-fix.md${NC}\n" + echo -e "Quick fix:" + echo -e " 1. Run: ${GREEN}sudo visudo${NC}" + echo -e " 2. Add: ${GREEN}$(whoami) ALL=(ALL) NOPASSWD: /usr/bin/log${NC}" + echo -e " 3. Save and exit (:wq)\n" + echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n" + exit 1 +} + +# Default values +STREAM_MODE=false +TIME_RANGE="5m" # Default to last 5 minutes +CATEGORY="" +LOG_LEVEL="$DEFAULT_LEVEL" +SEARCH_TEXT="" +OUTPUT_FILE="" +ERRORS_ONLY=false +SERVER_ONLY=false +TAIL_LINES=50 # Default number of lines to show +SHOW_TAIL=true +SHOW_HELP=false + +# Function to show usage +show_usage() { + cat << EOF +clawlog - Clawdis Logging Utility + +USAGE: + vtlog [OPTIONS] + +DESCRIPTION: + View Clawdis logs with full details (bypasses Apple's privacy redaction). + Requires sudo access configured for /usr/bin/log command. + +LOG FLOW ARCHITECTURE: + Clawdis logs flow through the macOS unified log (subsystem: com.steipete.clawdis). + +LOG CATEGORIES (examples): + • voicewake - Voice wake detection/test harness + • relay - Relay process manager + • xpc - XPC service calls + • notifications - Notification helper + • screenshot - Screenshotter + • shell - ShellRunner + +QUICK START: + vtlog -n 100 Show last 100 lines from all components + vtlog -f Follow logs in real-time + vtlog -e Show only errors + vtlog -c ServerManager Show logs from ServerManager only + +OPTIONS: + -h, --help Show this help message + -f, --follow Stream logs continuously (like tail -f) + -n, --lines NUM Number of lines to show (default: 50) + -l, --last TIME Time range to search (default: 5m) + Examples: 5m, 1h, 2d, 1w + -c, --category CAT Filter by category (e.g., ServerManager, SessionService) + -e, --errors Show only error messages + -d, --debug Show debug level logs (more verbose) + -s, --search TEXT Search for specific text in log messages + -o, --output FILE Export logs to file + --server Show only server output logs + --all Show all logs without tail limit + --list-categories List all available log categories + --json Output in JSON format + +EXAMPLES: + vtlog Show last 50 lines from past 5 minutes (default) + vtlog -f Stream logs continuously + vtlog -n 100 Show last 100 lines + vtlog -e Show only recent errors + vtlog -l 30m -n 200 Show last 200 lines from past 30 minutes + vtlog -c ServerManager Show recent ServerManager logs + vtlog -s "fail" Search for "fail" in recent logs + vtlog --server -e Show recent server errors + vtlog -f -d Stream debug logs continuously + +CATEGORIES: + Common categories include: + - ServerManager - Server lifecycle and configuration + - SessionService - Terminal session management + - TerminalManager - Terminal spawning and control + - GitRepository - Git integration features + - ScreencapService - Screen capture functionality + - WebRTCManager - WebRTC connections + - UnixSocket - Unix socket communication + - WindowTracker - Window tracking and focus + - NgrokService - Ngrok tunnel management + - ServerOutput - Node.js server output + +TIME FORMATS: + - 5m = 5 minutes - 1h = 1 hour + - 2d = 2 days - 1w = 1 week + +EOF +} + +# Function to list categories +list_categories() { + echo -e "${BLUE}Fetching VibeTunnel log categories from the last hour...${NC}\n" + + # Get unique categories from recent logs + log show --predicate "subsystem == \"$SUBSYSTEM\"" --last 1h 2>/dev/null | \ + grep -E "category: \"[^\"]+\"" | \ + sed -E 's/.*category: "([^"]+)".*/\1/' | \ + sort | uniq | \ + while read -r cat; do + echo " • $cat" + done + + echo -e "\n${YELLOW}Note: Only categories with recent activity are shown${NC}" +} + +# Show help if no arguments provided +if [[ $# -eq 0 ]]; then + show_usage + exit 0 +fi + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_usage + exit 0 + ;; + -f|--follow) + STREAM_MODE=true + SHOW_TAIL=false + shift + ;; + -n|--lines) + TAIL_LINES="$2" + shift 2 + ;; + -l|--last) + TIME_RANGE="$2" + shift 2 + ;; + -c|--category) + CATEGORY="$2" + shift 2 + ;; + -e|--errors) + ERRORS_ONLY=true + shift + ;; + -d|--debug) + LOG_LEVEL="debug" + shift + ;; + -s|--search) + SEARCH_TEXT="$2" + shift 2 + ;; + -o|--output) + OUTPUT_FILE="$2" + shift 2 + ;; + --server) + SERVER_ONLY=true + CATEGORY="ServerOutput" + shift + ;; + --list-categories) + list_categories + exit 0 + ;; + --json) + STYLE_ARGS="--style json" + shift + ;; + --all) + SHOW_TAIL=false + shift + ;; + *) + echo -e "${RED}Unknown option: $1${NC}" + echo "Use -h or --help for usage information" + exit 1 + ;; + esac +done + +# Build the predicate +PREDICATE="subsystem == \"$SUBSYSTEM\"" + +# Add category filter if specified +if [[ -n "$CATEGORY" ]]; then + PREDICATE="$PREDICATE AND category == \"$CATEGORY\"" +fi + +# Add error filter if specified +if [[ "$ERRORS_ONLY" == true ]]; then + PREDICATE="$PREDICATE AND (eventType == \"error\" OR messageType == \"error\" OR eventMessage CONTAINS \"ERROR\" OR eventMessage CONTAINS \"[31m\")" +fi + +# Add search filter if specified +if [[ -n "$SEARCH_TEXT" ]]; then + PREDICATE="$PREDICATE AND eventMessage CONTAINS[c] \"$SEARCH_TEXT\"" +fi + +# Build the command - always use sudo with --info to show private data +if [[ "$STREAM_MODE" == true ]]; then + # Streaming mode + CMD="sudo log stream --predicate '$PREDICATE' --level $LOG_LEVEL --info" + + echo -e "${GREEN}Streaming VibeTunnel logs continuously...${NC}" + echo -e "${YELLOW}Press Ctrl+C to stop${NC}\n" +else + # Show mode + CMD="sudo log show --predicate '$PREDICATE'" + + # Add log level for show command + if [[ "$LOG_LEVEL" == "debug" ]]; then + CMD="$CMD --debug" + else + CMD="$CMD --info" + fi + + # Add time range + CMD="$CMD --last $TIME_RANGE" + + if [[ "$SHOW_TAIL" == true ]]; then + echo -e "${GREEN}Showing last $TAIL_LINES log lines from the past $TIME_RANGE${NC}" + else + echo -e "${GREEN}Showing all logs from the past $TIME_RANGE${NC}" + fi + + # Show applied filters + if [[ "$ERRORS_ONLY" == true ]]; then + echo -e "${RED}Filter: Errors only${NC}" + fi + if [[ -n "$CATEGORY" ]]; then + echo -e "${BLUE}Category: $CATEGORY${NC}" + fi + if [[ -n "$SEARCH_TEXT" ]]; then + echo -e "${YELLOW}Search: \"$SEARCH_TEXT\"${NC}" + fi + echo "" # Empty line for readability +fi + +# Add style arguments if specified +if [[ -n "${STYLE_ARGS:-}" ]]; then + CMD="$CMD $STYLE_ARGS" +fi + +# Execute the command +if [[ -n "$OUTPUT_FILE" ]]; then + # First check if sudo works without password for the log command + if sudo -n /usr/bin/log show --last 1s 2>&1 | grep -q "password"; then + handle_sudo_error + fi + + echo -e "${BLUE}Exporting logs to: $OUTPUT_FILE${NC}\n" + if [[ "$SHOW_TAIL" == true ]] && [[ "$STREAM_MODE" == false ]]; then + eval "$CMD" 2>&1 | tail -n "$TAIL_LINES" > "$OUTPUT_FILE" + else + eval "$CMD" > "$OUTPUT_FILE" 2>&1 + fi + + # Check if file was created and has content + if [[ -s "$OUTPUT_FILE" ]]; then + LINE_COUNT=$(wc -l < "$OUTPUT_FILE" | tr -d ' ') + echo -e "${GREEN}✓ Exported $LINE_COUNT lines to $OUTPUT_FILE${NC}" + else + echo -e "${YELLOW}⚠ No logs found matching the criteria${NC}" + fi +else + # Run interactively + # First check if sudo works without password for the log command + if sudo -n /usr/bin/log show --last 1s 2>&1 | grep -q "password"; then + handle_sudo_error + fi + + if [[ "$SHOW_TAIL" == true ]] && [[ "$STREAM_MODE" == false ]]; then + # Apply tail for non-streaming mode + eval "$CMD" 2>&1 | tail -n "$TAIL_LINES" + echo -e "\n${YELLOW}Showing last $TAIL_LINES lines. Use --all or -n to see more.${NC}" + else + eval "$CMD" + fi +fi