Files
sf-cli-wrapper/sf-logs-tail.ps1
reynold 1b553c9d2d fix: update sf-logs-tail PowerShell examples to require target org
- Updated all example commands to include -to MYORG parameter
- Aligns with environment where no default org is configured
- Ensures consistency between script examples and actual requirements
2025-08-28 22:53:02 +08:00

322 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 to
Target org username or alias
.PARAMETER ui
Specific user ID to monitor (default: current user)
.PARAMETER lv
Log level: ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST
.PARAMETER dr
How long to tail logs in minutes (default: 30)
.PARAMETER ft
Filter log entries containing pattern
.PARAMETER ax
Show only Apex-related log entries
.PARAMETER nc
Disable colored output
.PARAMETER ve
Enable verbose output with timestamps
.PARAMETER hp
Show this help message
.EXAMPLE
.\sf-logs-tail.ps1 -to MYORG
.\sf-logs-tail.ps1 -to MYORG -lv DEBUG -dr 60
.\sf-logs-tail.ps1 -to MYORG -ft "MyClass" -ax
.\sf-logs-tail.ps1 -to sandbox -ui 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]$to,
[string]$ui,
[ValidateSet("ERROR", "WARN", "INFO", "DEBUG", "FINE", "FINER", "FINEST")]
[string]$lv,
[int]$dr = 30,
[string]$ft,
[switch]$ax,
[switch]$nc,
[switch]$ve,
[switch]$hp
)
# Show help if no parameters provided
if (-not ($to -or $ui -or $lv -or $dr -ne 30 -or $ft -or $ax -or $nc -or $ve -or $hp)) {
Get-Help $MyInvocation.MyCommand.Path -Detailed
exit 0
}
# Show help if requested
if ($hp) {
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 ($dr -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 ($to) {
$sfArgs += "--target-org"
$sfArgs += $to
}
if ($ui) {
$sfArgs += "--user-id"
$sfArgs += $ui
}
if ($lv) {
$sfArgs += "--debug-level"
$sfArgs += $lv
}
# Set up signal handlers
Set-SignalHandlers
# Display log tail information
Write-Host "📡 Starting Debug Log Tail" -ForegroundColor Blue
Write-Host "===========================" -ForegroundColor Blue
if ($to) {
Write-Host "Target org: $to" -ForegroundColor Cyan
}
if ($ui) {
Write-Host "User ID: $ui" -ForegroundColor Cyan
} else {
Write-Host "User: Current user" -ForegroundColor Cyan
}
if ($lv) {
Write-Host "Log level: " -ForegroundColor Cyan -NoNewline
Write-ColorizedLogLevel $lv
Write-Host ""
}
Write-Host "Duration: $dr minutes" -ForegroundColor Cyan
if ($ft) {
Write-Host "Filter: $ft" -ForegroundColor Cyan
}
if ($ax) {
Write-Host "Mode: Apex-only logs" -ForegroundColor Yellow
}
if ($ve) {
Write-Host "Verbose: Enabled (with timestamps)" -ForegroundColor Yellow
}
# Color settings
$showColors = -not $nc
if ($nc) {
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 ($ve) {
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($dr)
while ((Get-Date) -lt $timeoutTime -and $job.State -eq "Running") {
$output = Receive-Job $job
foreach ($line in $output) {
if (Test-ShowLogEntry $line $ft $ax) {
Write-FormattedLogEntry $line $showColors $ve
}
}
Start-Sleep -Milliseconds 100
}
# Get any remaining output
$finalOutput = Receive-Job $job
foreach ($line in $finalOutput) {
if (Test-ShowLogEntry $line $ft $ax) {
Write-FormattedLogEntry $line $showColors $ve
}
}
$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 $dr 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
}