Files
sf-cli-wrapper/sf-logs-tail.ps1
2025-08-28 16:34:16 +08:00

316 lines
8.2 KiB
PowerShell

#!/usr/bin/env pwsh
<#
.SYNOPSIS
Debug logs tail wrapper for Salesforce CLI with real-time monitoring
.DESCRIPTION
A user-friendly wrapper around 'sf apex tail log' that provides real-time
debug log monitoring with filtering, formatting, and intelligent output colorization.
.PARAMETER TargetOrg
Target org username or alias
.PARAMETER UserId
Specific user ID to monitor (default: current user)
.PARAMETER Level
Log level: ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST
.PARAMETER Duration
How long to tail logs in minutes (default: 30)
.PARAMETER Filter
Filter log entries containing pattern
.PARAMETER ApexOnly
Show only Apex-related log entries
.PARAMETER NoColors
Disable colored output
.PARAMETER Verbose
Enable verbose output with timestamps
.PARAMETER Help
Show this help message
.EXAMPLE
.\sf-logs-tail.ps1
.\sf-logs-tail.ps1 -Level DEBUG -Duration 60
.\sf-logs-tail.ps1 -Filter "MyClass" -ApexOnly
.\sf-logs-tail.ps1 -TargetOrg sandbox -UserId USER123
.NOTES
This script automatically checks for Salesforce CLI installation and runs
diagnostics if the CLI is not found.
Use Ctrl+C to stop tailing logs and exit.
#>
param(
[string]$TargetOrg,
[string]$UserId,
[ValidateSet("ERROR", "WARN", "INFO", "DEBUG", "FINE", "FINER", "FINEST")]
[string]$Level,
[int]$Duration = 30,
[string]$Filter,
[switch]$ApexOnly,
[switch]$NoColors,
[switch]$Verbose,
[switch]$Help
)
# Show help if requested
if ($Help) {
Get-Help $MyInvocation.MyCommand.Path -Detailed
exit 0
}
# Function to check if Salesforce CLI is installed
function Test-SalesforceCLI {
try {
$null = Get-Command sf -ErrorAction Stop
return $true
} catch {
return $false
}
}
# Function to run sf-check diagnostics
function Invoke-SalesforceCheck {
$checkScript = if (Test-Path "sf-check.ps1") {
".\sf-check.ps1"
} elseif (Test-Path "sf-check.sh") {
"bash sf-check.sh"
} else {
$null
}
if ($checkScript) {
Write-Host "Running Salesforce CLI diagnostics..." -ForegroundColor Yellow
Invoke-Expression $checkScript
} else {
Write-Host "Salesforce CLI not found and no diagnostic script available." -ForegroundColor Red
Write-Host "Please install the Salesforce CLI: https://developer.salesforce.com/tools/salesforcecli" -ForegroundColor Red
}
}
# Function to colorize log level
function Write-ColorizedLogLevel {
param([string]$Level)
switch -Regex ($Level) {
"ERROR" { return Write-Host $Level -ForegroundColor Red -NoNewline; "" }
"WARN" { return Write-Host $Level -ForegroundColor Yellow -NoNewline; "" }
"INFO" { return Write-Host $Level -ForegroundColor Green -NoNewline; "" }
"DEBUG" { return Write-Host $Level -ForegroundColor Cyan -NoNewline; "" }
"FINE" { return Write-Host $Level -ForegroundColor Blue -NoNewline; "" }
"APEX" { return Write-Host $Level -ForegroundColor Magenta -NoNewline; "" }
default { return $Level }
}
}
# Function to format log entry
function Write-FormattedLogEntry {
param([string]$Line, [bool]$ShowColors, [bool]$ShowTimestamp)
if ($ShowColors) {
if ($ShowTimestamp) {
$timestamp = Get-Date -Format "HH:mm:ss"
Write-Host "[$timestamp] " -ForegroundColor Gray -NoNewline
}
# Colorize based on content
switch -Regex ($Line) {
"(ERROR|EXCEPTION|FATAL)" {
Write-Host $Line -ForegroundColor Red
}
"(WARN|WARNING)" {
Write-Host $Line -ForegroundColor Yellow
}
"(DEBUG|FINE)" {
Write-Host $Line -ForegroundColor Cyan
}
"(APEX|USER_DEBUG)" {
Write-Host $Line -ForegroundColor Magenta
}
default {
Write-Host $Line
}
}
} else {
Write-Host $Line
}
}
# Function to test if log entry should be shown
function Test-ShowLogEntry {
param([string]$Line, [string]$FilterPattern, [bool]$ApexOnlyMode)
# Apply apex-only filter
if ($ApexOnlyMode) {
if ($Line -notmatch "(APEX|USER_DEBUG|EXCEPTION|METHOD_|CONSTRUCTOR_|DML_|SOQL_|VALIDATION_|FLOW_)") {
return $false
}
}
# Apply custom filter
if ($FilterPattern) {
if ($Line -notmatch $FilterPattern) {
return $false
}
}
return $true
}
# Function to setup signal handlers
function Set-SignalHandlers {
# PowerShell equivalent of trap - handle Ctrl+C gracefully
$null = Register-EngineEvent PowerShell.Exiting -Action {
Write-Host ""
Write-Host "Stopping log tail..." -ForegroundColor Yellow
}
}
# Silently check for Salesforce CLI
if (-not (Test-SalesforceCLI)) {
Invoke-SalesforceCheck
exit 1
}
# Validate duration
if ($Duration -lt 1) {
Write-Host "Error: Duration must be at least 1 minute" -ForegroundColor Red
exit 1
}
# Build the sf command
$sfArgs = @("apex", "tail", "log")
# Add optional parameters
if ($TargetOrg) {
$sfArgs += "--target-org"
$sfArgs += $TargetOrg
}
if ($UserId) {
$sfArgs += "--user-id"
$sfArgs += $UserId
}
if ($Level) {
$sfArgs += "--debug-level"
$sfArgs += $Level
}
# Set up signal handlers
Set-SignalHandlers
# Display log tail information
Write-Host "📡 Starting Debug Log Tail" -ForegroundColor Blue
Write-Host "===========================" -ForegroundColor Blue
if ($TargetOrg) {
Write-Host "Target org: $TargetOrg" -ForegroundColor Cyan
}
if ($UserId) {
Write-Host "User ID: $UserId" -ForegroundColor Cyan
} else {
Write-Host "User: Current user" -ForegroundColor Cyan
}
if ($Level) {
Write-Host "Log level: " -ForegroundColor Cyan -NoNewline
Write-ColorizedLogLevel $Level
Write-Host ""
}
Write-Host "Duration: $Duration minutes" -ForegroundColor Cyan
if ($Filter) {
Write-Host "Filter: $Filter" -ForegroundColor Cyan
}
if ($ApexOnly) {
Write-Host "Mode: Apex-only logs" -ForegroundColor Yellow
}
if ($Verbose) {
Write-Host "Verbose: Enabled (with timestamps)" -ForegroundColor Yellow
}
# Color settings
$showColors = -not $NoColors
if ($NoColors) {
Write-Host "Colors: Disabled" -ForegroundColor Gray
}
Write-Host ""
Write-Host "Press Ctrl+C to stop tailing logs" -ForegroundColor Yellow
Write-Host ""
# Display the command being run
if ($Verbose) {
Write-Host "Executing: sf $($sfArgs -join ' ')" -ForegroundColor Gray
Write-Host ""
}
# Start the log tailing with timeout
try {
$job = Start-Job -ScriptBlock {
param($sfArgs)
& sf @sfArgs 2>$null
} -ArgumentList $sfArgs
$timeoutTime = (Get-Date).AddMinutes($Duration)
while ((Get-Date) -lt $timeoutTime -and $job.State -eq "Running") {
$output = Receive-Job $job
foreach ($line in $output) {
if (Test-ShowLogEntry $line $Filter $ApexOnly) {
Write-FormattedLogEntry $line $showColors $Verbose
}
}
Start-Sleep -Milliseconds 100
}
# Get any remaining output
$finalOutput = Receive-Job $job
foreach ($line in $finalOutput) {
if (Test-ShowLogEntry $line $Filter $ApexOnly) {
Write-FormattedLogEntry $line $showColors $Verbose
}
}
$exitCode = 0
if ($job.State -eq "Running") {
Stop-Job $job
$exitCode = 124 # Timeout exit code
} elseif ($job.State -eq "Failed") {
$exitCode = 1
}
Remove-Job $job
Write-Host ""
if ($exitCode -eq 124) {
Write-Host "⏰ Log tail timed out after $Duration minutes" -ForegroundColor Yellow
} elseif ($exitCode -eq 0) {
Write-Host "✅ Log tail completed successfully" -ForegroundColor Green
} else {
Write-Host "❌ Log tail failed with exit code: $exitCode" -ForegroundColor Red
Write-Host "💡 Check org connectivity and user permissions" -ForegroundColor Yellow
}
Write-Host "Tip: Use different filters to focus on specific log types" -ForegroundColor Gray
} catch {
Write-Host "Error during log tail execution: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}