#!/bin/bash # Debug logs tail wrapper for Salesforce CLI # Provides real-time debug log monitoring with filtering and formatting # Source utilities for cross-platform compatibility source "$(dirname "$0")/utils/utils.sh" # Color codes for output formatting readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[0;33m' readonly BLUE='\033[0;34m' readonly CYAN='\033[0;36m' readonly GRAY='\033[0;37m' readonly MAGENTA='\033[0;35m' readonly NC='\033[0m' # No Color # Function to display usage information show_usage() { echo -e "${BLUE}sf-logs-tail - Debug Logs Tail Wrapper for Salesforce CLI${NC}" echo "" echo "USAGE:" echo " sf-logs-tail [OPTIONS]" echo "" echo "OPTIONS:" echo " -to Target org username or alias" echo " -ui Specific user ID to monitor (default: current user)" echo " -lv Log level: ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST" echo " -dr How long to tail logs in minutes (default: 30)" echo " -ft Filter log entries containing pattern" echo " -ax Show only Apex-related log entries" echo " -nc Disable colored output" echo " -ve Enable verbose output with timestamps" echo " -hp Show this help message" echo "" echo "EXAMPLES:" echo " sf-logs-tail -to MYORG # Tail logs for specified org" echo " sf-logs-tail -to MYORG -lv DEBUG -dr 60 # Debug level for 1 hour" echo " sf-logs-tail -to MYORG -ft \"MyClass\" -ax # Filter Apex logs for MyClass" echo " sf-logs-tail -to sandbox -ui USER123 # Specific org and user" echo "" echo "KEYBOARD SHORTCUTS:" echo " Ctrl+C Stop tailing logs and exit" echo "" echo "This script automatically checks for Salesforce CLI installation." } # Function to check if Salesforce CLI is installed check_salesforce_cli() { if ! command -v sf &> /dev/null; then return 1 fi return 0 } # Function to run sf-check diagnostics run_salesforce_check() { if [[ -f "sf-check" ]]; then echo -e "${YELLOW}Running Salesforce CLI diagnostics...${NC}" ./sf-check elif [[ -f "sf-check.sh" ]]; then echo -e "${YELLOW}Running Salesforce CLI diagnostics...${NC}" bash sf-check.sh elif [[ -f "sf-check.ps1" ]]; then echo -e "${YELLOW}Running Salesforce CLI diagnostics...${NC}" pwsh sf-check.ps1 else echo -e "${RED}Salesforce CLI not found and no diagnostic script available.${NC}" echo -e "${RED}Please install the Salesforce CLI: https://developer.salesforce.com/tools/salesforcecli${NC}" fi } # Function to colorize log level colorize_log_level() { local level="$1" case "$level" in *ERROR*) echo -e "${RED}$level${NC}" ;; *WARN*) echo -e "${YELLOW}$level${NC}" ;; *INFO*) echo -e "${GREEN}$level${NC}" ;; *DEBUG*) echo -e "${CYAN}$level${NC}" ;; *FINE*) echo -e "${BLUE}$level${NC}" ;; *APEX*) echo -e "${MAGENTA}$level${NC}" ;; *) echo "$level" ;; esac } # Function to format log entry format_log_entry() { local line="$1" local show_colors="$2" local show_timestamp="$3" if [[ "$show_colors" == true ]]; then # Add timestamp if verbose if [[ "$show_timestamp" == true ]]; then local timestamp=$(date '+%H:%M:%S') echo -e "${GRAY}[$timestamp]${NC} $line" else # Try to colorize based on content if [[ "$line" =~ (ERROR|EXCEPTION|FATAL) ]]; then echo -e "${RED}$line${NC}" elif [[ "$line" =~ (WARN|WARNING) ]]; then echo -e "${YELLOW}$line${NC}" elif [[ "$line" =~ (DEBUG|FINE) ]]; then echo -e "${CYAN}$line${NC}" elif [[ "$line" =~ (APEX|USER_DEBUG) ]]; then echo -e "${MAGENTA}$line${NC}" else echo "$line" fi fi else echo "$line" fi } # Function to filter log entry should_show_log_entry() { local line="$1" local filter_pattern="$2" local apex_only="$3" # Apply apex-only filter if [[ "$apex_only" == true ]]; then if [[ ! "$line" =~ (APEX|USER_DEBUG|EXCEPTION|METHOD_|CONSTRUCTOR_|DML_|SOQL_|VALIDATION_|FLOW_) ]]; then return 1 fi fi # Apply custom filter if [[ -n "$filter_pattern" ]]; then if [[ ! "$line" =~ $filter_pattern ]]; then return 1 fi fi return 0 } # Function to setup signal handlers setup_signal_handlers() { trap 'echo -e "\n${YELLOW}Stopping log tail...${NC}"; exit 0' INT TERM } # Initialize variables TARGET_ORG="" USER_ID="" LOG_LEVEL="" DURATION="30" FILTER_PATTERN="" APEX_ONLY=false NO_COLORS=false VERBOSE=false # 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 -to) TARGET_ORG="$2" shift 2 ;; -ui) USER_ID="$2" shift 2 ;; -lv) LOG_LEVEL="$2" shift 2 ;; -dr) DURATION="$2" shift 2 ;; -ft) FILTER_PATTERN="$2" shift 2 ;; -ax) APEX_ONLY=true shift ;; -nc) NO_COLORS=true shift ;; -ve) VERBOSE=true shift ;; -hp) show_usage exit 0 ;; *) echo -e "${RED}Unknown option: $1${NC}" echo "" show_usage exit 1 ;; esac done # Silently check for Salesforce CLI if ! check_salesforce_cli; then run_salesforce_check exit 1 fi # Validate log level if specified if [[ -n "$LOG_LEVEL" ]]; then case "$LOG_LEVEL" in ERROR|WARN|INFO|DEBUG|FINE|FINER|FINEST) ;; *) echo -e "${RED}Error: Invalid log level '$LOG_LEVEL'${NC}" echo -e "${YELLOW}Valid levels: ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST${NC}" exit 1 ;; esac fi # Validate duration if ! [[ "$DURATION" =~ ^[0-9]+$ ]]; then echo -e "${RED}Error: Duration must be a number (minutes)${NC}" exit 1 fi # Build the sf command SF_ARGS=("apex" "tail" "log") # Add optional parameters if [[ -n "$TARGET_ORG" ]]; then SF_ARGS+=("--target-org" "$TARGET_ORG") fi if [[ -n "$USER_ID" ]]; then SF_ARGS+=("--user-id" "$USER_ID") fi if [[ -n "$LOG_LEVEL" ]]; then SF_ARGS+=("--debug-level" "$LOG_LEVEL") fi # Set up signal handlers setup_signal_handlers # Display log tail information echo -e "${BLUE}📡 Starting Debug Log Tail${NC}" echo -e "${BLUE}===========================${NC}" if [[ -n "$TARGET_ORG" ]]; then echo -e "${CYAN}Target org: $TARGET_ORG${NC}" fi if [[ -n "$USER_ID" ]]; then echo -e "${CYAN}User ID: $USER_ID${NC}" else echo -e "${CYAN}User: Current user${NC}" fi if [[ -n "$LOG_LEVEL" ]]; then echo -e "${CYAN}Log level: $(colorize_log_level "$LOG_LEVEL")${NC}" fi echo -e "${CYAN}Duration: $DURATION minutes${NC}" if [[ -n "$FILTER_PATTERN" ]]; then echo -e "${CYAN}Filter: $FILTER_PATTERN${NC}" fi if [[ "$APEX_ONLY" == true ]]; then echo -e "${YELLOW}Mode: Apex-only logs${NC}" fi if [[ "$VERBOSE" == true ]]; then echo -e "${YELLOW}Verbose: Enabled (with timestamps)${NC}" fi # Color settings SHOW_COLORS=true if [[ "$NO_COLORS" == true ]]; then SHOW_COLORS=false echo -e "${GRAY}Colors: Disabled${NC}" fi echo "" echo -e "${YELLOW}Press Ctrl+C to stop tailing logs${NC}" echo "" # Display the command being run if [[ "$VERBOSE" == true ]]; then echo -e "${GRAY}Executing: sf ${SF_ARGS[*]}${NC}" echo "" fi # Start the log tailing with timeout portable_timeout "$DURATION" sf "${SF_ARGS[@]}" 2>/dev/null | while IFS= read -r line; do if should_show_log_entry "$line" "$FILTER_PATTERN" "$APEX_ONLY"; then format_log_entry "$line" "$SHOW_COLORS" "$VERBOSE" fi done # Check the exit status EXIT_CODE=${PIPESTATUS[0]} echo "" if [[ $EXIT_CODE -eq 124 ]]; then echo -e "${YELLOW}⏰ Log tail timed out after $DURATION minutes${NC}" elif [[ $EXIT_CODE -eq 0 ]]; then echo -e "${GREEN}✅ Log tail completed successfully${NC}" else echo -e "${RED}❌ Log tail failed with exit code: $EXIT_CODE${NC}" echo -e "${YELLOW}💡 Check org connectivity and user permissions${NC}" fi echo -e "${GRAY}Tip: Use different filters to focus on specific log types${NC}"