From da498546a45b35c5fcde27d89db7d25390ca4e75 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Mon, 20 Oct 2025 15:36:19 +0200 Subject: [PATCH 1/3] chore: fix formatting --- README.md | 14 +- dependencies/download.ps1 | 62 ++--- modules/Sentry/assemblies-loader.ps1 | 14 +- modules/Sentry/private/DiagnosticLogger.ps1 | 38 +-- modules/Sentry/private/EventUpdater.ps1 | 9 +- modules/Sentry/private/Get-CurrentOptions.ps1 | 6 +- .../private/Get-SentryAssembliesDirectory.ps1 | 17 +- modules/Sentry/private/New-HttpTransport.ps1 | 3 +- modules/Sentry/private/ScopeIntegration.ps1 | 13 +- .../Sentry/private/SentryEventProcessor.ps1 | 16 +- .../Sentry/private/StackTraceProcessor.ps1 | 226 ++++++------------ .../Sentry/private/SynchronousTransport.ps1 | 27 +-- modules/Sentry/private/SynchronousWorker.ps1 | 21 +- .../Sentry/public/Add-SentryBreadcrumb.ps1 | 16 +- modules/Sentry/public/Edit-SentryScope.ps1 | 6 +- modules/Sentry/public/Invoke-WithSentry.ps1 | 10 +- modules/Sentry/public/Out-Sentry.ps1 | 49 ++-- modules/Sentry/public/Start-Sentry.ps1 | 64 ++--- .../Sentry/public/Start-SentryTransaction.ps1 | 28 +-- modules/Sentry/public/Stop-Sentry.ps1 | 3 +- samples/locate-city.ps1 | 16 +- scripts/bump-version.ps1 | 23 +- tests/integration-test-script.ps1 | 16 +- tests/integration.tests.ps1 | 3 +- tests/out-sentry.tests.ps1 | 7 +- tests/packages.tests.ps1 | 21 +- tests/publishing.tests.ps1 | 9 +- tests/stacktrace.tests.ps1 | 99 +++----- tests/throwing.ps1 | 19 +- tests/throwingshort.ps1 | 4 +- tests/traces.tests.ps1 | 14 +- tests/utils.ps1 | 31 +-- 32 files changed, 292 insertions(+), 612 deletions(-) diff --git a/README.md b/README.md index 7c222c6..f9fccd2 100644 --- a/README.md +++ b/README.md @@ -23,18 +23,18 @@ PowerShell Sentry SDK is a thin wrapper on top of [Sentry .NET SDK](https://gith The PowerShell Sentry SDK is tested to work with: -- Windows PowerShell 5.1 -- PowerShell 7.4+ on Windows, macOS, and Linux +* Windows PowerShell 5.1 +* PowerShell 7.4+ on Windows, macOS, and Linux ## Documentation Sentry has extensive documentation for its SDKs on docs.sentry.io: -- [PowerShell SDK](https://docs.sentry.io/platforms/powershell/) -- [.NET SDK](https://docs.sentry.io/platforms/dotnet/) +* [PowerShell SDK](https://docs.sentry.io/platforms/powershell/) +* [.NET SDK](https://docs.sentry.io/platforms/dotnet/) ## Resources -- [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) -- [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](http://stackoverflow.com/questions/tagged/sentry) -- [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) +* [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](http://stackoverflow.com/questions/tagged/sentry) +* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) diff --git a/dependencies/download.ps1 b/dependencies/download.ps1 index ab92dff..83ba8ff 100644 --- a/dependencies/download.ps1 +++ b/dependencies/download.ps1 @@ -6,24 +6,20 @@ $libDir = "$moduleDir/lib" New-Item $libDir -ItemType Directory -Force | Out-Null -function CheckAssemblyVersion([string] $libFile, [string] $assemblyVersion) -{ +function CheckAssemblyVersion([string] $libFile, [string] $assemblyVersion) { $assembly = [Reflection.Assembly]::LoadFile($libFile) - if ($assembly.GetName().Version.ToString() -ne $assemblyVersion) - { + if ($assembly.GetName().Version.ToString() -ne $assemblyVersion) { throw "Dependency $libFile has different assembly version ($($assembly.GetName().Version)) than expected ($assemblyVersion)" } } -function Download([string] $dependency, [string] $TFM, [string] $targetTFM = $null, [string] $assemblyVersion = $null) -{ +function Download([string] $dependency, [string] $TFM, [string] $targetTFM = $null, [string] $assemblyVersion = $null) { $targetTFM = "$targetTFM" -eq '' ? $TFM : $targetTFM New-Item "$libDir/$targetTFM" -ItemType Directory -Force | Out-Null $props = (Get-Content "$propsDir/$dependency.properties" -Raw | ConvertFrom-StringData) - if ("$assemblyVersion" -eq '') - { + if ("$assemblyVersion" -eq '') { $assemblyVersion = $props.ContainsKey('assemblyVersion') ? $props.assemblyVersion : "$($props.version).0" } @@ -32,42 +28,32 @@ function Download([string] $dependency, [string] $TFM, [string] $targetTFM = $nu $targetVersionFile = "$libDir/$targetTFM/$dependency.version" $targetLicenseFile = "$libDir/$targetTFM/$dependency.license" - if ((Test-Path $targetLibFile) -and ((Get-Content $targetVersionFile -Raw -ErrorAction SilentlyContinue) -eq $assemblyVersion)) - { - try - { + if ((Test-Path $targetLibFile) -and ((Get-Content $targetVersionFile -Raw -ErrorAction SilentlyContinue) -eq $assemblyVersion)) { + try { CheckAssemblyVersion $targetLibFile $assemblyVersion Write-Debug "Dependency $targetLibFile already exists and has the expected assembly version ($assemblyVersion), skipping." return - } - catch - { + } catch { Write-Warning "$_, downloading again" } } - if (Test-Path $targetLibFile) - { + if (Test-Path $targetLibFile) { Remove-Item $targetLibFile -Force } - if (Test-Path $targetVersionFile) - { + if (Test-Path $targetVersionFile) { Remove-Item $targetVersionFile -Force } - if (Test-Path $targetLicenseFile) - { + if (Test-Path $targetLicenseFile) { Remove-Item $targetLicenseFile -Force } $archiveName = "$($package.ToLower()).$($props.version).nupkg" $archiveFile = "$downloadDir/$archiveName" - if (Test-Path $archiveFile) - { + if (Test-Path $archiveFile) { Write-Debug "Archive $archiveFile already exists, skipping download" - } - else - { + } else { $sourceUrl = "https://globalcdn.nuget.org/packages/$archiveName" Write-Output "Downloading $sourceUrl" Invoke-WebRequest $sourceUrl -OutFile $archiveFile @@ -75,33 +61,23 @@ function Download([string] $dependency, [string] $TFM, [string] $targetTFM = $nu $archive = [IO.Compression.ZipFile]::OpenRead($archiveFile) - function extract([string] $fileToExtract, [string] $targetFile) - { - if ($file = $archive.Entries.Where(({ $_.FullName -eq $fileToExtract }))) - { + function extract([string] $fileToExtract, [string] $targetFile) { + if ($file = $archive.Entries.Where(({ $_.FullName -eq $fileToExtract }))) { Write-Output "Extracting $fileToExtract to $targetFile" [IO.Compression.ZipFileExtensions]::ExtractToFile($file[0], $targetFile) - } - else - { + } else { throw "File not found in ZIP: $fileToExtract" } } - try - { + try { extract "lib/$TFM/$package.dll" $targetLibFile - if ($props.ContainsKey('licenseFile')) - { + if ($props.ContainsKey('licenseFile')) { extract $props.licenseFile $targetLicenseFile - } - else - { + } else { $props.license | Out-File -NoNewline $targetLicenseFile } - } - finally - { + } finally { $archive.Dispose() } diff --git a/modules/Sentry/assemblies-loader.ps1 b/modules/Sentry/assemblies-loader.ps1 index 1190c2e..e09d2d0 100644 --- a/modules/Sentry/assemblies-loader.ps1 +++ b/modules/Sentry/assemblies-loader.ps1 @@ -4,24 +4,18 @@ $dir = Get-SentryAssembliesDirectory # Check if the assembly is already loaded. $type = 'Sentry.SentrySdk' -as [type] -if ($type) -{ +if ($type) { $loadedAsssembly = $type.Assembly $expectedAssembly = [Reflection.Assembly]::LoadFile((Join-Path $dir 'Sentry.dll')) - if ($loadedAsssembly.ToString() -ne $expectedAssembly.ToString()) - { + if ($loadedAsssembly.ToString() -ne $expectedAssembly.ToString()) { throw "Sentry assembly is already loaded but it's not the expected version. Found: ($loadedAsssembly), location: $($loadedAsssembly.Location) Expected: ($expectedAssembly), location: $($expectedAssembly.Location)" - } - else - { + } else { Write-Debug "Sentry assembly is already loaded and at the expected version ($($expectedAssembly.GetName().Version)" } -} -else -{ +} else { Write-Debug "Loading assemblies from $($dir):" Get-ChildItem -Path $dir -Filter '*.dll' | ForEach-Object { Write-Debug "Loading assembly: $($_.Name)" diff --git a/modules/Sentry/private/DiagnosticLogger.ps1 b/modules/Sentry/private/DiagnosticLogger.ps1 index a334c5e..fbfc410 100644 --- a/modules/Sentry/private/DiagnosticLogger.ps1 +++ b/modules/Sentry/private/DiagnosticLogger.ps1 @@ -1,23 +1,18 @@ -class DiagnosticLogger : Sentry.Extensibility.IDiagnosticLogger -{ +class DiagnosticLogger : Sentry.Extensibility.IDiagnosticLogger { hidden [Sentry.SentryLevel] $minimalLevel - DiagnosticLogger([Sentry.SentryLevel] $minimalLevel) - { + DiagnosticLogger([Sentry.SentryLevel] $minimalLevel) { $this.minimalLevel = $minimalLevel } - [bool] IsEnabled([Sentry.SentryLevel] $level) - { + [bool] IsEnabled([Sentry.SentryLevel] $level) { return $level -ge $this.minimalLevel } - Log([Sentry.SentryLevel] $level, [string] $message, [Exception] $exception = $null, [object[]] $params) - { + Log([Sentry.SentryLevel] $level, [string] $message, [Exception] $exception = $null, [object[]] $params) { # Important: Only format the string if there are args passed. # Otherwise, a pre-formatted string that contains braces can cause a FormatException. - if ($params.Count -gt 0) - { + if ($params.Count -gt 0) { $message = $message -f $params } @@ -25,37 +20,30 @@ class DiagnosticLogger : Sentry.Extensibility.IDiagnosticLogger $message = $message -replace '[\r\n]+', ' ' $message = "[Sentry] $message" - if ($null -ne $exception) - { + if ($null -ne $exception) { $message += [Environment]::NewLine $message += $exception | Out-String } - switch ($level) - { - ([Sentry.SentryLevel]::Info) - { + switch ($level) { + ([Sentry.SentryLevel]::Info) { Write-Verbose $message } - ([Sentry.SentryLevel]::Warning) - { + ([Sentry.SentryLevel]::Warning) { Write-Warning $message } - ([Sentry.SentryLevel]::Error) - { + ([Sentry.SentryLevel]::Error) { Write-Error $message } - ([Sentry.SentryLevel]::Fatal) - { + ([Sentry.SentryLevel]::Fatal) { Write-Error $message } - default - { + default { # Workaround for Windows Powershell issue of halting and asking for user confirmation. # see https://github.com/PowerShell/PowerShell/issues/5148 if ($global:PSVersionTable.PSEdition -eq 'Desktop') { $pref = Get-Variable DebugPreference - if (($null -ne $pref) -and ($pref.value -eq "Inquire")) { + if (($null -ne $pref) -and ($pref.value -eq 'Inquire')) { $DebugPreference = 'Continue' } } diff --git a/modules/Sentry/private/EventUpdater.ps1 b/modules/Sentry/private/EventUpdater.ps1 index 07f07f4..0c99fe7 100644 --- a/modules/Sentry/private/EventUpdater.ps1 +++ b/modules/Sentry/private/EventUpdater.ps1 @@ -1,13 +1,10 @@ -class EventUpdater : SentryEventProcessor -{ - [Sentry.SentryEvent]DoProcess([Sentry.SentryEvent] $event_) - { +class EventUpdater : SentryEventProcessor { + [Sentry.SentryEvent]DoProcess([Sentry.SentryEvent] $event_) { $event_.Platform = 'powershell' # Clear useless release set by the .NET SDK (referring to the PowerShell assembly version) # "pwsh@7.4.1 SHA: 6a98b28414948626f1b29a5e8b062e73b7ff165a+6a98b28414948626f1b29a5e8b062e73b7ff165a" - if ($event_.Release -match "pwsh@$($global:PSVersionTable.PSVersion) .*") - { + if ($event_.Release -match "pwsh@$($global:PSVersionTable.PSVersion) .*") { $event_.Release = $null } diff --git a/modules/Sentry/private/Get-CurrentOptions.ps1 b/modules/Sentry/private/Get-CurrentOptions.ps1 index 5024385..5a0e87f 100644 --- a/modules/Sentry/private/Get-CurrentOptions.ps1 +++ b/modules/Sentry/private/Get-CurrentOptions.ps1 @@ -1,9 +1,7 @@ -function Get-CurrentOptions -{ +function Get-CurrentOptions { $bindingFlags = [System.Reflection.BindingFlags]::Static + [System.Reflection.BindingFlags]::NonPublic + [System.Reflection.BindingFlags]::Public $currentOptionsProperty = [Sentry.SentrySdk].GetProperty('CurrentOptions', $bindingFlags) - if ($null -eq $currentOptionsProperty) - { + if ($null -eq $currentOptionsProperty) { return $null } diff --git a/modules/Sentry/private/Get-SentryAssembliesDirectory.ps1 b/modules/Sentry/private/Get-SentryAssembliesDirectory.ps1 index 327c935..e8fa049 100644 --- a/modules/Sentry/private/Get-SentryAssembliesDirectory.ps1 +++ b/modules/Sentry/private/Get-SentryAssembliesDirectory.ps1 @@ -1,5 +1,4 @@ -function GetTFM -{ +function GetTFM { # Source https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle?view=powershell-7.4#powershell-end-of-support-dates # PowerShell 7.5 - Built on .NET 9.0 # PowerShell 7.4 (LTS) - Built on .NET 8.0 @@ -10,22 +9,16 @@ function GetTFM # PowerShell 6.2 - Built on .NET Core 2.1 # PowerShell 6.1 - Built on .NET Core 2.1 # PowerShell 6.0 - Built on .NET Core 2.0 - if ($PSVersionTable.PSVersion -ge '7.5') - { + if ($PSVersionTable.PSVersion -ge '7.5') { return 'net9.0' - } - elseif ($PSVersionTable.PSVersion -ge '7.4') - { + } elseif ($PSVersionTable.PSVersion -ge '7.4') { return 'net8.0' - } - else - { + } else { return 'net462' } } -function Get-SentryAssembliesDirectory -{ +function Get-SentryAssembliesDirectory { $dir = Split-Path -Parent $PSScriptRoot $dir = Join-Path $dir 'lib' $dir = Join-Path $dir (GetTFM) diff --git a/modules/Sentry/private/New-HttpTransport.ps1 b/modules/Sentry/private/New-HttpTransport.ps1 index 98022ce..f3060c0 100644 --- a/modules/Sentry/private/New-HttpTransport.ps1 +++ b/modules/Sentry/private/New-HttpTransport.ps1 @@ -1,6 +1,5 @@ # Wrapper to expose Sentry.Internal.SdkComposer::CreateHttpTransport() -function New-HttpTransport -{ +function New-HttpTransport { [OutputType([Sentry.Extensibility.ITransport])] [CmdletBinding()] param( diff --git a/modules/Sentry/private/ScopeIntegration.ps1 b/modules/Sentry/private/ScopeIntegration.ps1 index e27566d..0275a44 100644 --- a/modules/Sentry/private/ScopeIntegration.ps1 +++ b/modules/Sentry/private/ScopeIntegration.ps1 @@ -1,7 +1,5 @@ -class ScopeIntegration : Sentry.Integrations.ISdkIntegration -{ - Register([Sentry.IHub] $hub, [Sentry.SentryOptions] $options) - { +class ScopeIntegration : Sentry.Integrations.ISdkIntegration { + Register([Sentry.IHub] $hub, [Sentry.SentryOptions] $options) { $hub.ConfigureScope([System.Action[Sentry.Scope]] { param([Sentry.Scope]$scope) @@ -9,12 +7,9 @@ class ScopeIntegration : Sentry.Integrations.ISdkIntegration $scope.Sdk.Version = $moduleInfo.ModuleVersion $scope.Sdk.AddPackage("ps:$($scope.Sdk.Name)", $scope.Sdk.Version) - if ($PSVersionTable.PSEdition -eq 'Core') - { + if ($PSVersionTable.PSEdition -eq 'Core') { $scope.Contexts.Runtime.Name = 'PowerShell' - } - else - { + } else { $scope.Contexts.Runtime.Name = 'Windows PowerShell' } $scope.Contexts.Runtime.Version = $PSVersionTable.PSVersion.ToString() diff --git a/modules/Sentry/private/SentryEventProcessor.ps1 b/modules/Sentry/private/SentryEventProcessor.ps1 index 6f85e32..0c7b31d 100644 --- a/modules/Sentry/private/SentryEventProcessor.ps1 +++ b/modules/Sentry/private/SentryEventProcessor.ps1 @@ -1,18 +1,12 @@ -class SentryEventProcessor : SentryEventProcessor_ -{ - [Sentry.SentryEvent]DoProcess([Sentry.SentryEvent] $event_) - { +class SentryEventProcessor : SentryEventProcessor_ { + [Sentry.SentryEvent]DoProcess([Sentry.SentryEvent] $event_) { throw [NotImplementedException]::new('You must override SentryEventProcessor::DoProcess()') } - [Sentry.SentryEvent]Process_([Sentry.SentryEvent] $event_) - { - try - { + [Sentry.SentryEvent]Process_([Sentry.SentryEvent] $event_) { + try { return $this.DoProcess($event_) - } - catch - { + } catch { $ErrorRecord = $_ "$($this.GetType()) failed to process event $($event_.EventId):" | Write-Warning $ErrorRecord | Format-List * -Force | Out-String | Write-Warning diff --git a/modules/Sentry/private/StackTraceProcessor.ps1 b/modules/Sentry/private/StackTraceProcessor.ps1 index 1bb13dd..a89e6e7 100644 --- a/modules/Sentry/private/StackTraceProcessor.ps1 +++ b/modules/Sentry/private/StackTraceProcessor.ps1 @@ -1,5 +1,4 @@ -class StackTraceProcessor : SentryEventProcessor -{ +class StackTraceProcessor : SentryEventProcessor { [Sentry.Protocol.SentryException]$SentryException [System.Management.Automation.InvocationInfo]$InvocationInfo [System.Management.Automation.CallStackFrame[]]$StackTraceFrames @@ -8,52 +7,40 @@ class StackTraceProcessor : SentryEventProcessor hidden [string[]] $modulePaths hidden [hashtable] $pwshModules = @{} - StackTraceProcessor([Sentry.SentryOptions] $options) - { + StackTraceProcessor([Sentry.SentryOptions] $options) { $this.logger = $options.DiagnosticLogger if ($null -eq $this.logger) { $this.logger = Get-Variable -Scope script -Name SentryPowerShellDiagnosticLogger -ValueOnly -ErrorAction SilentlyContinue } - if ($env:PSModulePath.Contains(';')) - { + if ($env:PSModulePath.Contains(';')) { # Windows $this.modulePaths = $env:PSModulePath -split ';' - } - else - { + } else { # Unix $this.modulePaths = $env:PSModulePath -split ':' } } - [Sentry.SentryEvent]DoProcess([Sentry.SentryEvent] $event_) - { - if ($null -ne $this.SentryException) - { + [Sentry.SentryEvent]DoProcess([Sentry.SentryEvent] $event_) { + if ($null -ne $this.SentryException) { $this.ProcessException($event_) - } - elseif ($null -ne $event_.Message) - { + } elseif ($null -ne $event_.Message) { $this.ProcessMessage($event_) } # Add modules present in PowerShell - foreach ($module in $this.pwshModules.GetEnumerator()) - { + foreach ($module in $this.pwshModules.GetEnumerator()) { $event_.Modules[$module.Name] = $module.Value } # Add .NET modules. Note: we don't let sentry-dotnet do it because it would just add all the loaded assemblies, # regardless of their presence in a stacktrace. So we set the option ReportAssembliesMode=None in [Start-Sentry]. - foreach ($thread in $event_.SentryThreads) - { - foreach ($frame in $thread.Stacktrace.Frames) - { + foreach ($thread in $event_.SentryThreads) { + foreach ($frame in $thread.Stacktrace.Frames) { # .NET SDK sets the assembly info to frame.Package, for example: # "System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" - if ($frame.Package -match '^(?[^,]+), Version=(?[^,]+), ') - { + if ($frame.Package -match '^(?[^,]+), Version=(?[^,]+), ') { $event_.Modules[$Matches.Assembly] = $Matches.Version } } @@ -62,28 +49,22 @@ class StackTraceProcessor : SentryEventProcessor return $event_ } - hidden ProcessMessage([Sentry.SentryEvent] $event_) - { + hidden ProcessMessage([Sentry.SentryEvent] $event_) { $this.PrependThread($event_, $this.GetStackTrace()) } - hidden ProcessException([Sentry.SentryEvent] $event_) - { + hidden ProcessException([Sentry.SentryEvent] $event_) { $this.SentryException.Stacktrace = $this.GetStackTrace() - if ($this.SentryException.Stacktrace.Frames.Count -gt 0) - { + if ($this.SentryException.Stacktrace.Frames.Count -gt 0) { $topFrame = $this.SentryException.Stacktrace.Frames | Select-Object -Last 1 $this.SentryException.Module = $topFrame.Module } # Add the c# exception to the front of the exception list, followed by whatever is already there. $newExceptions = New-Object System.Collections.Generic.List[Sentry.Protocol.SentryException] - if ($null -ne $event_.SentryExceptions) - { - foreach ($e in $event_.SentryExceptions) - { - if ($null -eq $e.Mechanism) - { + if ($null -ne $event_.SentryExceptions) { + foreach ($e in $event_.SentryExceptions) { + if ($null -eq $e.Mechanism) { $e.Mechanism = [Sentry.Protocol.Mechanism]::new() } $e.Mechanism.Synthetic = $true @@ -95,8 +76,7 @@ class StackTraceProcessor : SentryEventProcessor $this.PrependThread($event_, $this.SentryException.Stacktrace) } - hidden PrependThread([Sentry.SentryEvent] $event_, [Sentry.SentryStackTrace] $sentryStackTrace) - { + hidden PrependThread([Sentry.SentryEvent] $event_, [Sentry.SentryStackTrace] $sentryStackTrace) { $newThreads = New-Object System.Collections.Generic.List[Sentry.SentryThread] $thread = New-Object Sentry.SentryThread $thread.Id = 0 @@ -105,10 +85,8 @@ class StackTraceProcessor : SentryEventProcessor $thread.Current = $true $thread.Stacktrace = $sentryStackTrace $newThreads.Add($thread) - if ($null -ne $event_.SentryThreads) - { - foreach ($t in $event_.SentryThreads) - { + if ($null -ne $event_.SentryThreads) { + foreach ($t in $event_.SentryThreads) { $t.Crashed = $false $t.Current = $false $newThreads.Add($t) @@ -117,33 +95,25 @@ class StackTraceProcessor : SentryEventProcessor $event_.SentryThreads = $newThreads } - hidden [Sentry.SentryStackTrace]GetStackTrace() - { + hidden [Sentry.SentryStackTrace]GetStackTrace() { # We collect all frames and then reverse them to the order expected by Sentry (caller->callee). # Do not try to make this code go backwards because it relies on the InvocationInfo from the previous frame. $sentryFrames = New-Object System.Collections.Generic.List[Sentry.SentryStackFrame] - if ($null -ne $this.StackTraceString) - { + if ($null -ne $this.StackTraceString) { $sentryFrames.Capacity = $this.StackTraceString.Count + 1 # Note: if InvocationInfo is present, use it to update: # - the first frame (in case of `$_ | Out-Sentry` in a catch clause). # - the second frame (in case of `write-error` and `$_ | Out-Sentry` in a trap). - if ($null -ne $this.InvocationInfo) - { + if ($null -ne $this.InvocationInfo) { $sentryFrameInitial = $this.CreateFrame($this.InvocationInfo) - } - else - { + } else { $sentryFrameInitial = $null } - foreach ($frame in $this.StackTraceString) - { + foreach ($frame in $this.StackTraceString) { $sentryFrame = $this.CreateFrame($frame) - if ($null -ne $sentryFrameInitial -and $sentryFrames.Count -lt 2) - { - if ($sentryFrameInitial.AbsolutePath -eq $sentryFrame.AbsolutePath -and $sentryFrameInitial.LineNumber -eq $sentryFrame.LineNumber) - { + if ($null -ne $sentryFrameInitial -and $sentryFrames.Count -lt 2) { + if ($sentryFrameInitial.AbsolutePath -eq $sentryFrame.AbsolutePath -and $sentryFrameInitial.LineNumber -eq $sentryFrame.LineNumber) { $sentryFrame.ContextLine = $sentryFrameInitial.ContextLine $sentryFrame.ColumnNumber = $sentryFrameInitial.ColumnNumber $sentryFrameInitial = $null @@ -152,24 +122,19 @@ class StackTraceProcessor : SentryEventProcessor $sentryFrames.Add($sentryFrame) } - if ($null -ne $sentryFrameInitial) - { + if ($null -ne $sentryFrameInitial) { $sentryFrames.Insert(0, $sentryFrameInitial) } $this.EnhanceTailFrames($sentryFrames) - } - elseif ($null -ne $this.StackTraceFrames) - { + } elseif ($null -ne $this.StackTraceFrames) { $sentryFrames.Capacity = $this.StackTraceFrames.Count + 1 - foreach ($frame in $this.StackTraceFrames) - { + foreach ($frame in $this.StackTraceFrames) { $sentryFrames.Add($this.CreateFrame($frame)) } } - foreach ($sentryFrame in $sentryFrames) - { + foreach ($sentryFrame in $sentryFrames) { # Update module info $this.SetModule($sentryFrame) $sentryFrame.InApp = [string]::IsNullOrEmpty($sentryFrame.Module) @@ -182,8 +147,7 @@ class StackTraceProcessor : SentryEventProcessor return $stacktrace_ } - hidden [Sentry.SentryStackFrame] CreateFrame([System.Management.Automation.InvocationInfo] $info) - { + hidden [Sentry.SentryStackFrame] CreateFrame([System.Management.Automation.InvocationInfo] $info) { $sentryFrame = [Sentry.SentryStackFrame]::new() $sentryFrame.AbsolutePath = $info.ScriptName $sentryFrame.LineNumber = $info.ScriptLineNumber @@ -192,8 +156,7 @@ class StackTraceProcessor : SentryEventProcessor return $sentryFrame } - hidden [Sentry.SentryStackFrame] CreateFrame([System.Management.Automation.CallStackFrame] $frame) - { + hidden [Sentry.SentryStackFrame] CreateFrame([System.Management.Automation.CallStackFrame] $frame) { $sentryFrame = [Sentry.SentryStackFrame]::new() $this.SetScriptInfo($sentryFrame, $frame) $this.SetModule($sentryFrame) @@ -201,31 +164,24 @@ class StackTraceProcessor : SentryEventProcessor return $sentryFrame } - hidden [Sentry.SentryStackFrame] CreateFrame([string] $frame) - { + hidden [Sentry.SentryStackFrame] CreateFrame([string] $frame) { $sentryFrame = [Sentry.SentryStackFrame]::new() # at funcB, C:\dev\sentry-powershell\tests\capture.tests.ps1: line 363 $regex = 'at (?[^,]*), (?.*): line (?\d*)' - if ($frame -match $regex) - { - if ($Matches.AbsolutePath -ne '') - { + if ($frame -match $regex) { + if ($Matches.AbsolutePath -ne '') { $sentryFrame.AbsolutePath = $Matches.AbsolutePath } $sentryFrame.LineNumber = [int]$Matches.LineNumber $sentryFrame.Function = $Matches.Function - } - else - { + } else { Write-Warning "Failed to parse stack frame: $frame" } return $sentryFrame } - hidden EnhanceTailFrames([Sentry.SentryStackFrame[]] $sentryFrames) - { - if ($null -eq $this.StackTraceFrames) - { + hidden EnhanceTailFrames([Sentry.SentryStackFrame[]] $sentryFrames) { + if ($null -eq $this.StackTraceFrames) { return } @@ -234,21 +190,17 @@ class StackTraceProcessor : SentryEventProcessor # - for pwsh -c `& {..}` it would be the `& {..}` code block. And in this case, the next frame would also be # just a scriptblock without a filename so we need to get the source code from the StackTraceFrames too. $i = 0; - for ($j = $sentryFrames.Count - 1; $j -ge 0; $j--) - { + for ($j = $sentryFrames.Count - 1; $j -ge 0; $j--) { $sentryFrame = $sentryFrames[$j] $frame = $this.StackTraceFrames | Select-Object -Last 1 -Skip $i $i++ - if ($null -eq $frame) - { + if ($null -eq $frame) { break } - if ($null -eq $sentryFrame.AbsolutePath -and $null -eq $frame.ScriptName) - { - if ($frame.ScriptLineNumber -gt 0 -and $frame.ScriptLineNumber -eq $sentryFrame.LineNumber) - { + if ($null -eq $sentryFrame.AbsolutePath -and $null -eq $frame.ScriptName) { + if ($frame.ScriptLineNumber -gt 0 -and $frame.ScriptLineNumber -eq $sentryFrame.LineNumber) { $this.SetScriptInfo($sentryFrame, $frame) $this.SetModule($sentryFrame) $this.SetFunction($sentryFrame, $frame) @@ -256,11 +208,9 @@ class StackTraceProcessor : SentryEventProcessor $this.SetContextLines($sentryFrame, $frame) # Try to match following frames that are part of the same codeblock. - while ($j -gt 0) - { + while ($j -gt 0) { $nextSentryFrame = $sentryFrames[$j - 1] - if ($nextSentryFrame.AbsolutePath -ne $sentryFrame.AbsolutePath) - { + if ($nextSentryFrame.AbsolutePath -ne $sentryFrame.AbsolutePath) { break } $this.SetContextLines($nextSentryFrame, $frame) @@ -270,38 +220,27 @@ class StackTraceProcessor : SentryEventProcessor } } - hidden SetScriptInfo([Sentry.SentryStackFrame] $sentryFrame, [System.Management.Automation.CallStackFrame] $frame) - { - if (![string]::IsNullOrEmpty($frame.ScriptName)) - { + hidden SetScriptInfo([Sentry.SentryStackFrame] $sentryFrame, [System.Management.Automation.CallStackFrame] $frame) { + if (![string]::IsNullOrEmpty($frame.ScriptName)) { $sentryFrame.AbsolutePath = $frame.ScriptName $sentryFrame.LineNumber = $frame.ScriptLineNumber - } - elseif (![string]::IsNullOrEmpty($frame.Position) -and ![string]::IsNullOrEmpty($frame.Position.File)) - { + } elseif (![string]::IsNullOrEmpty($frame.Position) -and ![string]::IsNullOrEmpty($frame.Position.File)) { $sentryFrame.AbsolutePath = $frame.Position.File $sentryFrame.LineNumber = $frame.Position.StartLineNumber $sentryFrame.ColumnNumber = $frame.Position.StartColumnNumber } } - hidden SetModule([Sentry.SentryStackFrame] $sentryFrame) - { - if (![string]::IsNullOrEmpty($sentryFrame.AbsolutePath)) - { - if ($prefix = $this.modulePaths | Where-Object { $sentryFrame.AbsolutePath.StartsWith($_) }) - { + hidden SetModule([Sentry.SentryStackFrame] $sentryFrame) { + if (![string]::IsNullOrEmpty($sentryFrame.AbsolutePath)) { + if ($prefix = $this.modulePaths | Where-Object { $sentryFrame.AbsolutePath.StartsWith($_) }) { $relativePath = $sentryFrame.AbsolutePath.Substring($prefix.Length + 1) $parts = $relativePath -split '[\\/]' $sentryFrame.Module = $parts | Select-Object -First 1 - if ($parts.Length -ge 2) - { - if (-not $this.pwshModules.ContainsKey($parts[0])) - { + if ($parts.Length -ge 2) { + if (-not $this.pwshModules.ContainsKey($parts[0])) { $this.pwshModules[$parts[0]] = $parts[1] - } - elseif ($this.pwshModules[$parts[0]] -ne $parts[1]) - { + } elseif ($this.pwshModules[$parts[0]] -ne $parts[1]) { $this.pwshModules[$parts[0]] = $this.pwshModules[$parts[0]] + ", $($parts[1])" } } @@ -309,42 +248,31 @@ class StackTraceProcessor : SentryEventProcessor } } - hidden SetFunction([Sentry.SentryStackFrame] $sentryFrame, [System.Management.Automation.CallStackFrame] $frame) - { - if ([string]::IsNullOrEmpty($sentryFrame.AbsolutePath) -and $frame.FunctionName -eq '' -and ![string]::IsNullOrEmpty($frame.Position)) - { + hidden SetFunction([Sentry.SentryStackFrame] $sentryFrame, [System.Management.Automation.CallStackFrame] $frame) { + if ([string]::IsNullOrEmpty($sentryFrame.AbsolutePath) -and $frame.FunctionName -eq '' -and ![string]::IsNullOrEmpty($frame.Position)) { $sentryFrame.Function = $frame.Position.Text # $frame.Position.Text may be a multiline command (e.g. when executed with `pwsh -c '& { ... \n ... \n ... }`) # So we need to trim it to a single line. - if ($sentryFrame.Function.Contains("`n")) - { + if ($sentryFrame.Function.Contains("`n")) { $lines = $sentryFrame.Function -split "[`r`n]+" $sentryFrame.Function = $lines[0] + ' ' - if ($lines.Count -gt 2) - { + if ($lines.Count -gt 2) { $sentryFrame.Function += ' ...... ' } $sentryFrame.Function += $lines[$lines.Count - 1] } - } - else - { + } else { $sentryFrame.Function = $frame.FunctionName } } - hidden SetContextLines([Sentry.SentryStackFrame] $sentryFrame, [System.Management.Automation.CallStackFrame] $frame) - { - if ($sentryFrame.LineNumber -gt 0) - { - try - { + hidden SetContextLines([Sentry.SentryStackFrame] $sentryFrame, [System.Management.Automation.CallStackFrame] $frame) { + if ($sentryFrame.LineNumber -gt 0) { + try { $lines = $frame.InvocationInfo.MyCommand.ScriptBlock.ToString() -split "`n" $this.SetContextLines($sentryFrame, $lines) - } - catch - { + } catch { Write-Warning "Failed to read context lines for frame with function '$($sentryFrame.Function)': $_" if ($global:SentryPowershellRethrowErrors -eq $true) { throw @@ -353,22 +281,16 @@ class StackTraceProcessor : SentryEventProcessor } } - hidden SetContextLines([Sentry.SentryStackFrame] $sentryFrame) - { - if ([string]::IsNullOrEmpty($sentryFrame.AbsolutePath) -or $sentryFrame.LineNumber -lt 1) - { + hidden SetContextLines([Sentry.SentryStackFrame] $sentryFrame) { + if ([string]::IsNullOrEmpty($sentryFrame.AbsolutePath) -or $sentryFrame.LineNumber -lt 1) { return } - if ((Test-Path $sentryFrame.AbsolutePath -IsValid) -and (Test-Path $sentryFrame.AbsolutePath -PathType Leaf)) - { - try - { + if ((Test-Path $sentryFrame.AbsolutePath -IsValid) -and (Test-Path $sentryFrame.AbsolutePath -PathType Leaf)) { + try { $lines = Get-Content $sentryFrame.AbsolutePath -TotalCount ($sentryFrame.LineNumber + 5) $this.SetContextLines($sentryFrame, $lines) - } - catch - { + } catch { Write-Warning "Failed to read context lines for $($sentryFrame.AbsolutePath): $_" if ($global:SentryPowershellRethrowErrors -eq $true) { throw @@ -377,10 +299,8 @@ class StackTraceProcessor : SentryEventProcessor } } - hidden SetContextLines([Sentry.SentryStackFrame] $sentryFrame, [string[]] $lines) - { - if ($lines.Count -lt $sentryFrame.LineNumber) - { + hidden SetContextLines([Sentry.SentryStackFrame] $sentryFrame, [string[]] $lines) { + if ($lines.Count -lt $sentryFrame.LineNumber) { if ($null -ne $this.logger) { $this.logger.Log( [Sentry.SentryLevel]::Debug, @@ -393,16 +313,14 @@ class StackTraceProcessor : SentryEventProcessor $numContextLines = 5 - if ($null -eq $sentryFrame.ContextLine) - { + if ($null -eq $sentryFrame.ContextLine) { $sentryFrame.ContextLine = $lines[$sentryFrame.LineNumber - 1] } $preContextCount = [math]::Min($numContextLines, $sentryFrame.LineNumber - 1) $postContextCount = [math]::Min($numContextLines, $lines.Count - $sentryFrame.LineNumber) - if ($sentryFrame.LineNumber -gt $numContextLines + 1) - { + if ($sentryFrame.LineNumber -gt $numContextLines + 1) { $lines = $lines | Select-Object -Skip ($sentryFrame.LineNumber - $numContextLines - 1) } diff --git a/modules/Sentry/private/SynchronousTransport.ps1 b/modules/Sentry/private/SynchronousTransport.ps1 index c5f19c5..e722745 100644 --- a/modules/Sentry/private/SynchronousTransport.ps1 +++ b/modules/Sentry/private/SynchronousTransport.ps1 @@ -1,18 +1,15 @@ # Take Sentry's SerializableHttpContent, convert it to a string, and send via PowerShell's Invoke-WebRequest, # then translate the response back to a .NET HttpResponseMessage. # There are limited options to perform synchronous operations in Windows PowerShell 5.1 on .NET 4.6, so this is a workaround. -class SynchronousTransport : Sentry.Http.HttpTransportBase, Sentry.Extensibility.ITransport -{ +class SynchronousTransport : Sentry.Http.HttpTransportBase, Sentry.Extensibility.ITransport { hidden [Sentry.Extensibility.IDiagnosticLogger] $logger hidden [System.Reflection.MethodInfo] $ProcessEnvelope hidden [System.Reflection.MethodInfo] $CreateRequest hidden [System.Reflection.MethodInfo] $SerializeToStream - SynchronousTransport([Sentry.SentryOptions] $options) : base($options) - { + SynchronousTransport([Sentry.SentryOptions] $options) : base($options) { $this.logger = $options.DiagnosticLogger - if ($null -eq $this.logger) - { + if ($null -eq $this.logger) { $this.logger = Get-Variable -Scope script -Name SentryPowerShellDiagnosticLogger -ValueOnly -ErrorAction SilentlyContinue } @@ -24,16 +21,13 @@ class SynchronousTransport : Sentry.Http.HttpTransportBase, Sentry.Extensibility $this.SerializeToStream = $EnvelopeHttpContentType.GetMethod('SerializeToStream', $instanceMethod) } - [System.Threading.Tasks.Task] SendEnvelopeAsync([Sentry.Protocol.Envelopes.Envelope] $envelope, [System.Threading.CancellationToken]$cancellationToken = [System.Threading.CancellationToken]::None) - { + [System.Threading.Tasks.Task] SendEnvelopeAsync([Sentry.Protocol.Envelopes.Envelope] $envelope, [System.Threading.CancellationToken]$cancellationToken = [System.Threading.CancellationToken]::None) { $processedEnvelope = $this.ProcessEnvelope.Invoke($this, @($envelope)) - if ($processedEnvelope.Items.count -gt 0) - { + if ($processedEnvelope.Items.count -gt 0) { $request = $this.CreateRequest.Invoke($this, @($processedEnvelope)) $headers = @{} - foreach ($header in $request.Headers) - { + foreach ($header in $request.Headers) { $Key = $header.Key $Value = $header.Value.Trim() -join ', ' $headers[$Key] = $Value @@ -43,8 +37,7 @@ class SynchronousTransport : Sentry.Http.HttpTransportBase, Sentry.Extensibility $this.SerializeToStream.Invoke($request.Content, @($memoryStream, $null, $cancellationToken)) $memoryStream.Position = 0 - if ($null -ne $this.logger) - { + if ($null -ne $this.logger) { $this.logger.Log([Sentry.SentryLevel]::Debug, 'Sending content synchronously, Content-Length: {0}', $null, $memoryStream.Length) } @@ -53,14 +46,12 @@ class SynchronousTransport : Sentry.Http.HttpTransportBase, Sentry.Extensibility $response = [System.Net.Http.HttpResponseMessage]::new($psResponse.StatusCode) $contentType = $psResponse.Headers['Content-Type'] - if ($null -eq $contentType) - { + if ($null -eq $contentType) { $contentType = 'application/json' } $response.Content = [System.Net.Http.StringContent]::new($psResponse.Content, [System.Text.Encoding]::UTF8, $contentType) - foreach ($header in $psResponse.Headers.GetEnumerator()) - { + foreach ($header in $psResponse.Headers.GetEnumerator()) { $response.Headers.TryAddWithoutValidation($header.Key, $header.Value) } diff --git a/modules/Sentry/private/SynchronousWorker.ps1 b/modules/Sentry/private/SynchronousWorker.ps1 index 2938cf3..9a0a54f 100644 --- a/modules/Sentry/private/SynchronousWorker.ps1 +++ b/modules/Sentry/private/SynchronousWorker.ps1 @@ -1,42 +1,35 @@ . "$privateDir/New-HttpTransport.ps1" -class SynchronousWorker : Sentry.Extensibility.IBackgroundWorker -{ +class SynchronousWorker : Sentry.Extensibility.IBackgroundWorker { hidden [Sentry.Extensibility.ITransport] $transport hidden [Sentry.SentryOptions] $options hidden $unfinishedTasks = [System.Collections.Generic.List[System.Threading.Tasks.Task]]::new() - SynchronousWorker([Sentry.SentryOptions] $options) - { + SynchronousWorker([Sentry.SentryOptions] $options) { $this.options = $options # Start from either the transport given on options, or create a new HTTP transport. $this.transport = $options.Transport; - if ($null -eq $this.transport) - { + if ($null -eq $this.transport) { $this.transport = New-HttpTransport($options) } } - [bool] EnqueueEnvelope([Sentry.Protocol.Envelopes.Envelope] $envelope) - { + [bool] EnqueueEnvelope([Sentry.Protocol.Envelopes.Envelope] $envelope) { $task = $this.transport.SendEnvelopeAsync($envelope, [System.Threading.CancellationToken]::None) - if (-not $task.Wait($this.options.FlushTimeout)) - { + if (-not $task.Wait($this.options.FlushTimeout)) { $this.unfinishedTasks.Add($task) } return $true } - [System.Threading.Tasks.Task] FlushAsync([System.TimeSpan] $timeout) - { + [System.Threading.Tasks.Task] FlushAsync([System.TimeSpan] $timeout) { [System.Threading.Tasks.Task]::WhenAll($this.unfinishedTasks).Wait($timeout) $this.unfinishedTasks.Clear() return [System.Threading.Tasks.Task]::CompletedTask } - [int] get_QueuedItems() - { + [int] get_QueuedItems() { return $this.unfinishedTasks.Count } } diff --git a/modules/Sentry/public/Add-SentryBreadcrumb.ps1 b/modules/Sentry/public/Add-SentryBreadcrumb.ps1 index 02a70a1..9f5e608 100644 --- a/modules/Sentry/public/Add-SentryBreadcrumb.ps1 +++ b/modules/Sentry/public/Add-SentryBreadcrumb.ps1 @@ -1,5 +1,4 @@ -function Add-SentryBreadcrumb -{ +function Add-SentryBreadcrumb { param( [Parameter(Mandatory, ValueFromPipeline = $true)] [string] $Message, @@ -9,20 +8,15 @@ function Add-SentryBreadcrumb [hashtable] $Data = $null, [Sentry.BreadcrumbLevel] $Level = [Sentry.BreadcrumbLevel]::Info) - begin - { - if ($null -eq $Data) - { + begin { + if ($null -eq $Data) { $DataDict = $null - } - else - { + } else { $DataDict = [System.Collections.Generic.Dictionary[string, string]]::new() $Data.Keys | ForEach-Object { $DataDict.Add($_, $Data[$_]) } } } - process - { + process { [Sentry.SentrySdk]::AddBreadcrumb($Message, $Category, $Type, $DataDict, $Level) } } diff --git a/modules/Sentry/public/Edit-SentryScope.ps1 b/modules/Sentry/public/Edit-SentryScope.ps1 index 95da445..b495821 100644 --- a/modules/Sentry/public/Edit-SentryScope.ps1 +++ b/modules/Sentry/public/Edit-SentryScope.ps1 @@ -1,12 +1,10 @@ -function Edit-SentryScope -{ +function Edit-SentryScope { param( [Parameter(Mandatory)] [scriptblock] $ScopeSetup ) - process - { + process { [Sentry.SentrySdk]::ConfigureScope([System.Action[Sentry.Scope]] { param([Sentry.Scope]$scope) # Execute the script block in the caller's scope (nothing to do $scope) & set the automatic $_ variable to the $scope object. diff --git a/modules/Sentry/public/Invoke-WithSentry.ps1 b/modules/Sentry/public/Invoke-WithSentry.ps1 index 373a221..11915f2 100644 --- a/modules/Sentry/public/Invoke-WithSentry.ps1 +++ b/modules/Sentry/public/Invoke-WithSentry.ps1 @@ -1,18 +1,14 @@ . "$publicDir/Out-Sentry.ps1" -function Invoke-WithSentry -{ +function Invoke-WithSentry { param( [scriptblock] $ScriptBlock ) - try - { + try { & $ScriptBlock - } - catch - { + } catch { $_ | Out-Sentry throw } diff --git a/modules/Sentry/public/Out-Sentry.ps1 b/modules/Sentry/public/Out-Sentry.ps1 index 1b87a54..4c6167f 100644 --- a/modules/Sentry/public/Out-Sentry.ps1 +++ b/modules/Sentry/public/Out-Sentry.ps1 @@ -1,8 +1,7 @@ . "$privateDir/StackTraceProcessor.ps1" . "$privateDir/Get-CurrentOptions.ps1" -function Out-Sentry -{ +function Out-Sentry { [OutputType([Sentry.SentryId])] [CmdletBinding(DefaultParameterSetName = 'ErrorRecord')] param( @@ -25,15 +24,13 @@ function Out-Sentry ) begin {} - process - { - if (-not [Sentry.SentrySdk]::IsEnabled) - { + process { + if (-not [Sentry.SentrySdk]::IsEnabled) { # Workaround for: # NullReferenceException: Object reference not set to an instance of an object. # at Out-Sentry, D:\a\sentry-powershell\sentry-powershell\modules\Sentry\public\Out-Sentry.ps1:32 try { - Write-Debug "Sentry is not started: Out-Sentry invocation ignored." + Write-Debug 'Sentry is not started: Out-Sentry invocation ignored.' } catch {} return } @@ -42,66 +39,50 @@ function Out-Sentry [Sentry.SentryEvent]$event_ = $null $processor = [StackTraceProcessor]::new($options) - if ($ErrorRecord -ne $null) - { + if ($ErrorRecord -ne $null) { $event_ = [Sentry.SentryEvent]::new($ErrorRecord.Exception) $processor.SentryException = [Sentry.Protocol.SentryException]::new() - if ($($ErrorRecord.CategoryInfo.Activity) -eq 'Write-Error') - { + if ($($ErrorRecord.CategoryInfo.Activity) -eq 'Write-Error') { # FullyQualifiedErrorId would be "Microsoft.PowerShell.Commands.WriteErrorException,funcB" $processor.SentryException.Type = 'Write-Error' - } - else - { + } else { $processor.SentryException.Type = $ErrorRecord.FullyQualifiedErrorId } - if (($details = $ErrorRecord.ErrorDetails) -and $null -ne $details.Message) - { + if (($details = $ErrorRecord.ErrorDetails) -and $null -ne $details.Message) { $processor.SentryException.Value = $details.Message - } - else - { + } else { $processor.SentryException.Value = $ErrorRecord.Exception.Message } - if ($options.AttachStackTrace) - { + if ($options.AttachStackTrace) { # Note: we use ScriptStackTrace even though we need to parse it, becaause it contains actual stack trace # to the throw, not just the trace to the call to this function. $processor.StackTraceString = @($ErrorRecord.ScriptStackTrace -split "[`r`n]+") $processor.InvocationInfo = $ErrorRecord.InvocationInfo } - } - elseif ($Exception -ne $null) - { + } elseif ($Exception -ne $null) { $event_ = [Sentry.SentryEvent]::new($Exception) $processor.SentryException = [Sentry.Protocol.SentryException]::new() $processor.SentryException.Type = $Exception.GetType().FullName $processor.SentryException.Value = $Exception.Message - } - elseif ($Message -ne $null) - { + } elseif ($Message -ne $null) { $event_ = [Sentry.SentryEvent]::new() $event_.Message = $Message $event_.Level = [Sentry.SentryLevel]::Info - } - else - { + } else { Write-Warning 'Out-Sentry: No argument matched, nothing to do' return } - if ($null -eq $event_) - { + if ($null -eq $event_) { Write-Debug 'Out-Sentry: Nothing to capture' return } - if ($options.AttachStackTrace -and $null -eq $processor.StackTraceFrames) - { + if ($options.AttachStackTrace -and $null -eq $processor.StackTraceFrames) { $processor.StackTraceFrames = Get-PSCallStack | Select-Object -Skip 1 } diff --git a/modules/Sentry/public/Start-Sentry.ps1 b/modules/Sentry/public/Start-Sentry.ps1 index eaf7a98..741c141 100644 --- a/modules/Sentry/public/Start-Sentry.ps1 +++ b/modules/Sentry/public/Start-Sentry.ps1 @@ -4,8 +4,7 @@ . "$privateDir/SynchronousTransport.ps1" . "$privateDir/EventUpdater.ps1" -function Start-Sentry -{ +function Start-Sentry { [CmdletBinding(DefaultParameterSetName = 'Simple')] param( [Parameter(Mandatory, ParameterSetName = 'Simple', Position = 0)] @@ -15,8 +14,7 @@ function Start-Sentry [scriptblock] $EditOptions ) - begin - { + begin { $options = [Sentry.SentryOptions]::new() $options.FlushTimeout = [System.TimeSpan]::FromSeconds(10) $options.ShutDownTimeout = $options.FlushTimeout @@ -25,23 +23,17 @@ function Start-Sentry $options.AddIntegration([ScopeIntegration]::new()) $options.AddEventProcessor([EventUpdater]::new()) - if ($DebugPreference -eq 'SilentlyContinue') - { + if ($DebugPreference -eq 'SilentlyContinue') { $Options.Debug = $false $options.DiagnosticLevel = [Sentry.SentryLevel]::Info - } - else - { + } else { $Options.Debug = $true $options.DiagnosticLevel = [Sentry.SentryLevel]::Debug } - if ($EditOptions -eq $null) - { + if ($EditOptions -eq $null) { $options.Dsn = $Dsn - } - else - { + } else { # Execute the script block in the caller's scope & set the automatic $_ variable to the options object. $options | ForEach-Object $EditOptions } @@ -53,32 +45,27 @@ function Start-Sentry $options.DiagnosticLogger = $logger $script:SentryPowerShellDiagnosticLogger = $logger - if ($null -eq $options.Transport) - { - try - { - $options.Transport = [SynchronousTransport]::new($options) - } - catch - { - $logger.Log([Sentry.SentryLevel]::Warning, 'Failed to create a PowerShell-specific synchronous transport', $_.Exception, @()) - if ($global:SentryPowershellRethrowErrors -eq $true) { - throw + # We don't need synchronous workers with newer PowerShell versions. + if (($PSVersionTable.PSVersion.Major -lt 7) -or ($PSVersionTable.PSVersion.Minor -l 5)) { + if ($null -eq $options.Transport) { + try { + $options.Transport = [SynchronousTransport]::new($options) + } catch { + $logger.Log([Sentry.SentryLevel]::Warning, 'Failed to create a PowerShell-specific synchronous transport', $_.Exception, @()) + if ($global:SentryPowershellRethrowErrors -eq $true) { + throw + } } } - } - if ($null -eq $options.BackgroundWorker) - { - try - { - $options.BackgroundWorker = [SynchronousWorker]::new($options) - } - catch - { - $logger.Log([Sentry.SentryLevel]::Warning, 'Failed to create a PowerShell-specific synchronous worker', $_.Exception, @()) - if ($global:SentryPowershellRethrowErrors -eq $true) { - throw + if ($null -eq $options.BackgroundWorker) { + try { + $options.BackgroundWorker = [SynchronousWorker]::new($options) + } catch { + $logger.Log([Sentry.SentryLevel]::Warning, 'Failed to create a PowerShell-specific synchronous worker', $_.Exception, @()) + if ($global:SentryPowershellRethrowErrors -eq $true) { + throw + } } } } @@ -86,8 +73,7 @@ function Start-Sentry # Workaround for https://github.com/getsentry/sentry-dotnet/issues/3141 $options.DisableAppDomainProcessExitFlush() } - process - { + process { [Sentry.SentrySdk]::init($options) | Out-Null } } diff --git a/modules/Sentry/public/Start-SentryTransaction.ps1 b/modules/Sentry/public/Start-SentryTransaction.ps1 index 59a5b61..6672d9f 100644 --- a/modules/Sentry/public/Start-SentryTransaction.ps1 +++ b/modules/Sentry/public/Start-SentryTransaction.ps1 @@ -1,5 +1,4 @@ -function Start-SentryTransaction -{ +function Start-SentryTransaction { [OutputType([Sentry.ITransactionTracer])] [CmdletBinding(DefaultParameterSetName = 'Basic')] param( @@ -28,27 +27,20 @@ function Start-SentryTransaction [switch] $ForceSampled ) - begin - { - if ($null -eq $TransactionContext) - { + begin { + if ($null -eq $TransactionContext) { $IsSampled = $null - if ($ForceSampled) - { + if ($ForceSampled) { $IsSampled = $true } $TransactionContext = [Sentry.TransactionContext]::new($Name, $Operation, $null, $null, $null, $Description, $null, $IsSampled) } } - process - { - if ($CustomSamplingContext -eq $null) - { + process { + if ($CustomSamplingContext -eq $null) { return [Sentry.SentrySdk]::StartTransaction($TransactionContext) - } - else - { + } else { $samplingContext = HashTableToDictionary $CustomSamplingContext return [Sentry.SentrySdk]::StartTransaction($TransactionContext, $samplingContext) } @@ -56,11 +48,9 @@ function Start-SentryTransaction } # Converts [hashtable] to [System.Collections.generic.dictionary] -function HashTableToDictionary([hashtable] $hash) -{ +function HashTableToDictionary([hashtable] $hash) { $dict = [System.Collections.Generic.Dictionary[string, object]]::new() - foreach ($key in $hash.Keys) - { + foreach ($key in $hash.Keys) { $dict.Add($key, $hash[$key]) } return $dict diff --git a/modules/Sentry/public/Stop-Sentry.ps1 b/modules/Sentry/public/Stop-Sentry.ps1 index 32ba954..cee7c66 100644 --- a/modules/Sentry/public/Stop-Sentry.ps1 +++ b/modules/Sentry/public/Stop-Sentry.ps1 @@ -1,5 +1,4 @@ -function Stop-Sentry -{ +function Stop-Sentry { [Sentry.SentrySdk]::Close() Remove-Variable -Scope script -Name SentryPowerShellDiagnosticLogger -ErrorAction SilentlyContinue } diff --git a/samples/locate-city.ps1 b/samples/locate-city.ps1 index aef6506..ae6cab4 100644 --- a/samples/locate-city.ps1 +++ b/samples/locate-city.ps1 @@ -27,8 +27,7 @@ Start-Sentry -Debug { # Transaction can be started by providing, at minimum, the name and the operation $transaction = Start-SentryTransaction 'transaction-name' 'transaction-operation' -try -{ +try { $span = $transaction.StartChild('wait for input') if ($City -eq '' ) { $City = Read-Host 'Enter the city name' } $span.Finish() @@ -40,10 +39,8 @@ try $span = $transaction.StartChild('search') $FoundOne = 0 - foreach ($Row in $Table) - { - if ($Row.city -eq $City) - { + foreach ($Row in $Table) { + if ($Row.city -eq $City) { $FoundOne = 1 $Country = $Row.country $Region = $Row.admin_name @@ -55,15 +52,12 @@ try } $span.Finish() $transaction.Finish() - if ($FoundOne) - { + if ($FoundOne) { exit 0 # success } Write-Error "City $City not found" exit 1 -} -catch -{ +} catch { # Mark the transaction as finished (note: this needs to be done prior to calling Out-Sentry) $transaction.Finish($_.Exception) diff --git a/scripts/bump-version.ps1 b/scripts/bump-version.ps1 index fc1781d..b592e94 100644 --- a/scripts/bump-version.ps1 +++ b/scripts/bump-version.ps1 @@ -3,41 +3,32 @@ param([string] $newVersion) . "$PSScriptRoot/settings.ps1" $parts = $newVersion -split '-' -if ($parts.Length -eq 1) -{ +if ($parts.Length -eq 1) { $version = $parts[0] $prerelease = '' -} -elseif ($parts.Length -eq 2) -{ +} elseif ($parts.Length -eq 2) { <# Action when this condition is true #> $version = $parts[0] $prerelease = $parts[1] -} -else -{ +} else { throw "Invalid version format: $newVersion" } $moduleFile = "$PSScriptRoot/../modules/Sentry/Sentry.psd1" $content = Get-Content $moduleFile $changes = 0 -for ($i = 0; $i -lt $content.Length; $i++) -{ - if ($content[$i] -match "^(\s*ModuleVersion\s*=\s*)'[^']*'\s*$") - { +for ($i = 0; $i -lt $content.Length; $i++) { + if ($content[$i] -match "^(\s*ModuleVersion\s*=\s*)'[^']*'\s*$") { $content[$i] = $matches[1] + "'$version'" $changes++ } - if ($content[$i] -match "^(\s*Prerelease\s*=\s*)'[^']*'\s*$") - { + if ($content[$i] -match "^(\s*Prerelease\s*=\s*)'[^']*'\s*$") { $content[$i] = $matches[1] + "'$prerelease'" $changes++ } } -if ($changes -ne 2) -{ +if ($changes -ne 2) { throw "Failed to update version in $moduleFile" } diff --git a/tests/integration-test-script.ps1 b/tests/integration-test-script.ps1 index 5968095..7783e18 100644 --- a/tests/integration-test-script.ps1 +++ b/tests/integration-test-script.ps1 @@ -6,8 +6,7 @@ Import-Module ./modules/Sentry/Sentry.psd1 . ./tests/utils.ps1 . ./tests/throwingshort.ps1 -function funcA -{ +function funcA { # Call to another file funcC } @@ -16,12 +15,9 @@ $events = [System.Collections.Generic.List[Sentry.SentryEvent]]::new(); $transport = [RecordingTransport]::new() StartSentryForEventTests ([ref] $events) ([ref] $transport) -try -{ +try { funcA -} -catch -{ +} catch { $_ | Out-Sentry | Out-Null } @@ -30,11 +26,9 @@ $thread.Stacktrace.Frames | ForEach-Object { '----------------' | Out-String $frame = $_ $properties = $frame | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name - foreach ($prop in $properties) - { + foreach ($prop in $properties) { $value = $frame.$prop | Out-String -Width 500 - if ("$value" -ne '') - { + if ("$value" -ne '') { "$($prop): $value".TrimEnd() } } diff --git a/tests/integration.tests.ps1 b/tests/integration.tests.ps1 index 8353585..1e26a67 100644 --- a/tests/integration.tests.ps1 +++ b/tests/integration.tests.ps1 @@ -22,8 +22,7 @@ BeforeAll { Write-Host 'Testing output:' $output | Write-Host - for ($i = 0; $i -lt $expected.Count -and $i -lt $output.Count; $i++) - { + for ($i = 0; $i -lt $expected.Count -and $i -lt $output.Count; $i++) { $output[$i] | Should -Be $expected[$i] -Because "Output line $i" } $output.Count | Should -Be $expected.Count diff --git a/tests/out-sentry.tests.ps1 b/tests/out-sentry.tests.ps1 index 2b0b682..557529e 100644 --- a/tests/out-sentry.tests.ps1 +++ b/tests/out-sentry.tests.ps1 @@ -27,12 +27,9 @@ Describe 'Out-Sentry' { } It 'returns an event ID for an error record' { - try - { + try { throw 'error' - } - catch - { + } catch { $eventId = $_ | Out-Sentry } $eventId | Should -BeOfType [Sentry.SentryId] diff --git a/tests/packages.tests.ps1 b/tests/packages.tests.ps1 index dabf7ba..fade135 100644 --- a/tests/packages.tests.ps1 +++ b/tests/packages.tests.ps1 @@ -13,19 +13,13 @@ AfterAll { Describe 'Out-Sentry for <_>' -ForEach @('message', 'error') { BeforeEach { $param = $_ - if ($param -eq 'error') - { - try - { + if ($param -eq 'error') { + try { throw 'error' - } - catch - { + } catch { $_ | Out-Sentry } - } - else - { + } else { $param | Out-Sentry } $events.Count | Should -Be 1 @@ -65,12 +59,9 @@ Describe 'Out-Sentry for <_>' -ForEach @('message', 'error') { } It 'Sets PowerShell as runtime' { - if ($PSVersionTable.PSVersion.Major -eq 5) - { + if ($PSVersionTable.PSVersion.Major -eq 5) { $event.Contexts.Runtime.Name | Should -Be 'Windows PowerShell' - } - else - { + } else { $event.Contexts.Runtime.Name | Should -Be 'PowerShell' } $event.Contexts.Runtime.Version | Should -Be $PSVersionTable.PSVersion.ToString() diff --git a/tests/publishing.tests.ps1 b/tests/publishing.tests.ps1 index 9d7dc5d..5b0dea3 100644 --- a/tests/publishing.tests.ps1 +++ b/tests/publishing.tests.ps1 @@ -11,15 +11,12 @@ Describe 'Publishing' { # Update version in the module manifest $content = Get-Content "$tempModuleDir/Sentry.psd1" $changes = 0 - for ($i = 0; $i -lt $content.Length; $i++) - { - if ($content[$i] -match "^(\s*ModuleVersion\s*=\s*)'[^']*'\s*$") - { + for ($i = 0; $i -lt $content.Length; $i++) { + if ($content[$i] -match "^(\s*ModuleVersion\s*=\s*)'[^']*'\s*$") { $content[$i] = $matches[1] + "'9.9.9'" $changes++ } - if ($content[$i] -match "^(\s*Prerelease\s*=\s*)'[^']*'\s*$") - { + if ($content[$i] -match "^(\s*Prerelease\s*=\s*)'[^']*'\s*$") { $content[$i] = $matches[1] + "'test'" $changes++ } diff --git a/tests/stacktrace.tests.ps1 b/tests/stacktrace.tests.ps1 index 3887bda..55fa0d1 100644 --- a/tests/stacktrace.tests.ps1 +++ b/tests/stacktrace.tests.ps1 @@ -6,10 +6,8 @@ BeforeAll { $transport = [RecordingTransport]::new() StartSentryForEventTests ([ref] $events) ([ref] $transport) - function ContextLines($start, $lines, $path = $null) - { - if ($null -eq $path) - { + function ContextLines($start, $lines, $path = $null) { + if ($null -eq $path) { $path = "$PSScriptRoot/throwing.ps1" } @@ -38,21 +36,15 @@ BeforeAll { [Sentry.SentryStackFrame[]] $frames = $event.SentryExceptions[1].Stacktrace.Frames $frames.Count | Should -BeGreaterThan 0 - if ($event.SentryExceptions[1].Type -eq 'Write-Error') - { + if ($event.SentryExceptions[1].Type -eq 'Write-Error') { $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 18) $event.SentryExceptions[0].Type | Should -Be 'Microsoft.PowerShell.Commands.WriteErrorException' $event.SentryExceptions[0].Module | Should -Match 'Microsoft.PowerShell.Commands.Utility' - } - else - { - if ($event.SentryExceptions[1].Type -eq 'error') - { + } else { + if ($event.SentryExceptions[1].Type -eq 'error') { $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 17) $(GetListItem $frames -1).ColumnNumber | Should -BeGreaterThan 0 - } - else - { + } else { $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 24) } $event.SentryExceptions[0].Type | Should -Be 'System.Management.Automation.RuntimeException' @@ -62,13 +54,10 @@ BeforeAll { $checkFrame.Invoke((GetListItem $frames -2), 'funcA', 7) $event.SentryExceptions[0].Value | Should -Be 'error' - if ($event.SentryExceptions[1].Type -eq 'error,funcB') - { + if ($event.SentryExceptions[1].Type -eq 'error,funcB') { $event.SentryExceptions[0].Stacktrace.Frames[0].Function | Should -Be 'void MshCommandRuntime.ThrowTerminatingError(ErrorRecord errorRecord)' $event.SentryThreads.Count | Should -Be 1 - } - else - { + } else { $event.SentryExceptions[0].Stacktrace | Should -BeNullOrEmpty $event.SentryThreads.Count | Should -Be 2 } @@ -135,12 +124,9 @@ Describe 'Out-Sentry' { } It 'captures error record' { - try - { + try { funcA 'throw' 'error' - } - catch - { + } catch { $_ | Out-Sentry } @@ -148,12 +134,9 @@ Describe 'Out-Sentry' { } It 'captures short context' { - try - { + try { funcC - } - catch - { + } catch { $_ | Out-Sentry } @@ -161,12 +144,9 @@ Describe 'Out-Sentry' { } It 'captures exception' { - try - { + try { funcA 'throw' 'exception' - } - catch - { + } catch { $_.Exception | Out-Sentry } $events.Count | Should -Be 1 @@ -201,15 +181,13 @@ Describe 'Out-Sentry' { It 'does not add stack trace to message when AttachStacktrace=false' { $bindingFlags = [System.Reflection.BindingFlags]::Static + [System.Reflection.BindingFlags]::NonPublic + [System.Reflection.BindingFlags]::Public $currentOptionsProperty = [Sentry.SentrySdk].GetProperty('CurrentOptions', $bindingFlags) - if ($null -eq $currentOptionsProperty) - { + if ($null -eq $currentOptionsProperty) { return $null } [Sentry.SentryOptions] $options = $currentOptionsProperty.GetValue($null) $options.AttachStacktrace = $false - try - { + try { FuncA 'pass' 'message' $events.Count | Should -Be 1 [Sentry.SentryEvent]$event = $events.ToArray()[0] @@ -217,9 +195,7 @@ Describe 'Out-Sentry' { $event.Message.Message | Should -Be 'message' $event.SentryThreads.Count | Should -Be 1 $event.SentryThreads[0].Stacktrace.Frames.Count | Should -Be 0 - } - finally - { + } finally { $options.AttachStacktrace = $true } } @@ -227,22 +203,17 @@ Describe 'Out-Sentry' { It 'does not add stack trace to error when AttachStacktrace=false' { $bindingFlags = [System.Reflection.BindingFlags]::Static + [System.Reflection.BindingFlags]::NonPublic + [System.Reflection.BindingFlags]::Public $currentOptionsProperty = [Sentry.SentrySdk].GetProperty('CurrentOptions', $bindingFlags) - if ($null -eq $currentOptionsProperty) - { + if ($null -eq $currentOptionsProperty) { return $null } [Sentry.SentryOptions] $options = $currentOptionsProperty.GetValue($null) $options.AttachStacktrace = $false - try - { + try { - try - { + try { funcA 'throw' 'error' - } - catch - { + } catch { $_ | Out-Sentry } $events.Count | Should -Be 1 @@ -260,9 +231,7 @@ Describe 'Out-Sentry' { $event.SentryThreads.Count | Should -Be 1 $event.SentryThreads[0].Stacktrace.Frames.Count | Should -Be 0 - } - finally - { + } finally { $options.AttachStacktrace = $true } } @@ -274,11 +243,9 @@ Describe 'Invoke-WithSentry' { } It 'captures error record' { - try - { + try { Invoke-WithSentry { funcA 'throw' 'error' } - } - catch {} + } catch {} $events.Count | Should -Be 1 [Sentry.SentryEvent]$event = $events.ToArray()[0] @@ -304,10 +271,8 @@ Describe 'trap' { # We need to have Trap inside another function because it lets the function continue and as such, it would also # override any test failures so the test would show up as passed. # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_trap?view=powershell-7.4#trapping-errors-and-scope - function TestFunction - { - trap - { + function TestFunction { + trap { $_ | Out-Sentry $info['triggers'] = $info['triggers'] + 1 } @@ -332,10 +297,8 @@ Describe 'trap' { # We need to have Trap inside another function because it lets the function continue and as such, it would also # override any test failures so the test would show up as passed. # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_trap?view=powershell-7.4#trapping-errors-and-scope - function TestFunction - { - trap - { + function TestFunction { + trap { $_ | Out-Sentry $info['triggers'] = $info['triggers'] + 1 } @@ -360,10 +323,8 @@ Describe 'trap' { # We need to have Trap inside another function because it lets the function continue and as such, it would also # override any test failures so the test would show up as passed. # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_trap?view=powershell-7.4#trapping-errors-and-scope - function TestFunction - { - trap - { + function TestFunction { + trap { $_ | Out-Sentry $info['triggers'] = $info['triggers'] + 1 } diff --git a/tests/throwing.ps1 b/tests/throwing.ps1 index ac210aa..4ef239c 100644 --- a/tests/throwing.ps1 +++ b/tests/throwing.ps1 @@ -2,29 +2,22 @@ # Changes here may require changes in tests/stacktrace.test.ps1 # Especially in the contexts-lines checks. -function funcA($action, $param) -{ +function funcA($action, $param) { funcB $action $param } -function funcB -{ +function funcB { [CmdletBinding()] param([string]$action, [string] $value) - switch ($action) - { + switch ($action) { 'throw' { throw $value } 'write' { Write-Error $value -ErrorAction Stop } 'pass' { $value | Out-Sentry } - 'pipeline' - { - try - { + 'pipeline' { + try { throw $value - } - catch - { + } catch { [System.Management.Automation.ErrorRecord]$ErrorRecord = $_ $PSCmdlet.ThrowTerminatingError($ErrorRecord) } diff --git a/tests/throwingshort.ps1 b/tests/throwingshort.ps1 index c8848a7..51551f8 100644 --- a/tests/throwingshort.ps1 +++ b/tests/throwingshort.ps1 @@ -1,3 +1,3 @@ function funcC { - throw "Short context test" -} \ No newline at end of file + throw 'Short context test' +} diff --git a/tests/traces.tests.ps1 b/tests/traces.tests.ps1 index bf0fc0a..721f6bf 100644 --- a/tests/traces.tests.ps1 +++ b/tests/traces.tests.ps1 @@ -105,13 +105,10 @@ Describe 'Start-SentryTransaction' { $_.Dsn = 'https://key@127.0.0.1/1' } - if ($ForceSampled) - { + if ($ForceSampled) { $transaction = Start-SentryTransaction 'foo' 'bar' -ForceSampled $transaction.IsSampled | Should -Be $true - } - else - { + } else { $transaction = Start-SentryTransaction 'foo' 'bar' $transaction.IsSampled | Should -Be $false } @@ -125,13 +122,10 @@ Describe 'Start-SentryTransaction' { $_.TracesSampleRate = 1.0 } - if ($ForceSampled) - { + if ($ForceSampled) { $transaction = Start-SentryTransaction 'foo' 'bar' -ForceSampled $transaction.IsSampled | Should -Be $true - } - else - { + } else { $transaction = Start-SentryTransaction 'foo' 'bar' $transaction.IsSampled | Should -Be $true } diff --git a/tests/utils.ps1 b/tests/utils.ps1 index 96afc6e..da0da42 100644 --- a/tests/utils.ps1 +++ b/tests/utils.ps1 @@ -1,21 +1,17 @@ -class RecordingTransport:Sentry.Extensibility.ITransport -{ +class RecordingTransport:Sentry.Extensibility.ITransport { $envelopes = [System.Collections.Concurrent.ConcurrentQueue[Sentry.Protocol.Envelopes.Envelope]]::new() - [System.Threading.Tasks.Task]SendEnvelopeAsync([Sentry.Protocol.Envelopes.Envelope] $envelope, [System.Threading.CancellationToken] $cancellationToken) - { + [System.Threading.Tasks.Task]SendEnvelopeAsync([Sentry.Protocol.Envelopes.Envelope] $envelope, [System.Threading.CancellationToken] $cancellationToken) { $this.envelopes.Enqueue($envelope) return [System.Threading.Tasks.Task]::CompletedTask } - [void] Clear() - { + [void] Clear() { $this.envelopes = [System.Collections.Concurrent.ConcurrentQueue[Sentry.Protocol.Envelopes.Envelope]]::new() } } -class TestLogger:Sentry.Infrastructure.DiagnosticLogger -{ +class TestLogger:Sentry.Infrastructure.DiagnosticLogger { TestLogger([Sentry.SentryLevel]$level) : base($level) {} $entries = [System.Collections.Concurrent.ConcurrentQueue[string]]::new() @@ -23,20 +19,17 @@ class TestLogger:Sentry.Infrastructure.DiagnosticLogger [void]LogMessage([string] $message) { $this.entries.Enqueue($message) } } -class TestIntegration : Sentry.Integrations.ISdkIntegration -{ +class TestIntegration : Sentry.Integrations.ISdkIntegration { [Sentry.SentryOptions] $Options [Sentry.IHub] $Hub - Register([Sentry.IHub] $hub, [Sentry.SentryOptions] $options) - { + Register([Sentry.IHub] $hub, [Sentry.SentryOptions] $options) { $this.Hub = $hub $this.Options = $options } } -function StartSentryForEventTests([ref] $events, [ref] $transport) -{ +function StartSentryForEventTests([ref] $events, [ref] $transport) { Start-Sentry { $_.Dsn = 'https://key@127.0.0.1/1' @@ -53,14 +46,10 @@ function StartSentryForEventTests([ref] $events, [ref] $transport) } } -function GetListItem($list, $index) -{ - if ($index -ge 0) - { +function GetListItem($list, $index) { + if ($index -ge 0) { return $list[$index] - } - else - { + } else { return $list[$list.Count + $index] } } From 0a1b257d2c59ae2a1c795412092c342bdd3a89da Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Mon, 20 Oct 2025 16:06:25 +0200 Subject: [PATCH 2/3] fixup --- modules/Sentry/public/Start-Sentry.ps1 | 33 ++++++++++++-------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/modules/Sentry/public/Start-Sentry.ps1 b/modules/Sentry/public/Start-Sentry.ps1 index 741c141..9ff4ac1 100644 --- a/modules/Sentry/public/Start-Sentry.ps1 +++ b/modules/Sentry/public/Start-Sentry.ps1 @@ -45,27 +45,24 @@ function Start-Sentry { $options.DiagnosticLogger = $logger $script:SentryPowerShellDiagnosticLogger = $logger - # We don't need synchronous workers with newer PowerShell versions. - if (($PSVersionTable.PSVersion.Major -lt 7) -or ($PSVersionTable.PSVersion.Minor -l 5)) { - if ($null -eq $options.Transport) { - try { - $options.Transport = [SynchronousTransport]::new($options) - } catch { - $logger.Log([Sentry.SentryLevel]::Warning, 'Failed to create a PowerShell-specific synchronous transport', $_.Exception, @()) - if ($global:SentryPowershellRethrowErrors -eq $true) { - throw - } + if ($null -eq $options.Transport) { + try { + $options.Transport = [SynchronousTransport]::new($options) + } catch { + $logger.Log([Sentry.SentryLevel]::Warning, 'Failed to create a PowerShell-specific synchronous transport', $_.Exception, @()) + if ($global:SentryPowershellRethrowErrors -eq $true) { + throw } } + } - if ($null -eq $options.BackgroundWorker) { - try { - $options.BackgroundWorker = [SynchronousWorker]::new($options) - } catch { - $logger.Log([Sentry.SentryLevel]::Warning, 'Failed to create a PowerShell-specific synchronous worker', $_.Exception, @()) - if ($global:SentryPowershellRethrowErrors -eq $true) { - throw - } + if ($null -eq $options.BackgroundWorker) { + try { + $options.BackgroundWorker = [SynchronousWorker]::new($options) + } catch { + $logger.Log([Sentry.SentryLevel]::Warning, 'Failed to create a PowerShell-specific synchronous worker', $_.Exception, @()) + if ($global:SentryPowershellRethrowErrors -eq $true) { + throw } } } From bceda96b2c98a298fc521004e93950847edb8fdf Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Mon, 20 Oct 2025 16:36:12 +0200 Subject: [PATCH 3/3] test: Update test expectations for formatting changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The formatting PR changed code style (moving opening braces to the same line as function/control structure declarations), which shifted line numbers in stack traces. This updates test expectations to match the new line numbers: - integration.tests.ps1: Updated line numbers for funcA (21→19), funcC (12→11), and piped command tests (3→2, 4→3) - stacktrace.tests.ps1: Updated line numbers for funcB calls (19→16, 18→15, 17→14, 24→19) and funcA (7→6) - Updated PreContext expectations to reflect compressed formatting - Changed quote style from double to single quotes in throwingshort.ps1 references 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- tests/integration.tests.ps1 | 91 +++++++++++++++++-------------------- tests/stacktrace.tests.ps1 | 16 +++---- 2 files changed, 49 insertions(+), 58 deletions(-) diff --git a/tests/integration.tests.ps1 b/tests/integration.tests.ps1 index 1e26a67..c92d319 100644 --- a/tests/integration.tests.ps1 +++ b/tests/integration.tests.ps1 @@ -63,33 +63,32 @@ Describe 'Out-Sentry captures expected stack traces for command argument' -Skip: 'ContextLine: funcA' 'Function: ' 'InApp: True' - 'LineNumber: 21' - 'PostContext: }' - 'catch' - '{' + 'LineNumber: 19' + 'PostContext: } catch {' ' $_ | Out-Sentry | Out-Null' '}' - 'PreContext: $transport = [RecordingTransport]::new()' + '$thread = $events[0].SentryThreads | Where-Object { $_.Id -eq 0 }' + 'PreContext: $events = [System.Collections.Generic.List[Sentry.SentryEvent]]::new();' + '$transport = [RecordingTransport]::new()' 'StartSentryForEventTests ([ref] $events) ([ref] $transport)' - 'try' - '{' + 'try {' '----------------' 'ContextLine: funcC' 'Function: funcA' 'InApp: True' - 'LineNumber: 12' + 'LineNumber: 11' 'PostContext: }' '$events = [System.Collections.Generic.List[Sentry.SentryEvent]]::new();' '$transport = [RecordingTransport]::new()' 'StartSentryForEventTests ([ref] $events) ([ref] $transport)' - 'PreContext: . ./tests/throwingshort.ps1' - 'function funcA' - '{' + 'PreContext: . ./tests/utils.ps1' + '. ./tests/throwingshort.ps1' + 'function funcA {' ' # Call to another file' '----------------' "AbsolutePath: $integrationTestThrowingScript" 'ColumnNumber: 5' - 'ContextLine: throw "Short context test"' + "ContextLine: throw 'Short context test'" 'Function: funcC' 'InApp: True' 'LineNumber: 2' @@ -123,30 +122,24 @@ Describe 'Out-Sentry captures expected stack traces for piped command' { 'ContextLine: funcA' 'Function: ' 'InApp: True' - 'LineNumber: 3' - 'PostContext: }' - 'catch' - '{' + 'LineNumber: 2' + 'PostContext: } catch {' ' $_ | Out-Sentry | Out-Null' '}' - 'PreContext: try' - '{' + 'PreContext: try {' '----------------' - 'ContextLine: }' + 'ContextLine: } catch {' 'Function: funcA' 'InApp: True' - 'LineNumber: 4' - 'PostContext: catch' - '{' - ' $_ | Out-Sentry | Out-Null' + 'LineNumber: 3' + 'PostContext: $_ | Out-Sentry | Out-Null' '}' - 'PreContext: try' - '{' + "PreContext: try {" ' funcA' '----------------' "AbsolutePath: $integrationTestThrowingScript" 'ColumnNumber: 5' - 'ContextLine: throw "Short context test"' + "ContextLine: throw 'Short context test'" 'Function: funcC' 'InApp: True' 'LineNumber: 2' @@ -184,34 +177,33 @@ Describe 'Out-Sentry captures expected stack traces for file input' { 'ContextLine: funcA' 'Function: ' 'InApp: True' - 'LineNumber: 21' - 'PostContext: }' - 'catch' - '{' + 'LineNumber: 19' + 'PostContext: } catch {' ' $_ | Out-Sentry | Out-Null' '}' - 'PreContext: $transport = [RecordingTransport]::new()' + '$thread = $events[0].SentryThreads | Where-Object { $_.Id -eq 0 }' + 'PreContext: $events = [System.Collections.Generic.List[Sentry.SentryEvent]]::new();' + '$transport = [RecordingTransport]::new()' 'StartSentryForEventTests ([ref] $events) ([ref] $transport)' - 'try' - '{' + 'try {' '----------------' "AbsolutePath: $integrationTestScript" 'ContextLine: funcC' 'Function: funcA' 'InApp: True' - 'LineNumber: 12' + 'LineNumber: 11' 'PostContext: }' '$events = [System.Collections.Generic.List[Sentry.SentryEvent]]::new();' '$transport = [RecordingTransport]::new()' 'StartSentryForEventTests ([ref] $events) ([ref] $transport)' - 'PreContext: . ./tests/throwingshort.ps1' - 'function funcA' - '{' + 'PreContext: . ./tests/utils.ps1' + '. ./tests/throwingshort.ps1' + 'function funcA {' ' # Call to another file' '----------------' "AbsolutePath: $integrationTestThrowingScript" 'ColumnNumber: 5' - 'ContextLine: throw "Short context test"' + "ContextLine: throw 'Short context test'" 'Function: funcC' 'InApp: True' 'LineNumber: 2' @@ -245,33 +237,32 @@ Describe 'Out-Sentry captures expected stack traces for PowerShell.Create()' { 'ContextLine: funcA' 'Function: ' 'InApp: True' - 'LineNumber: 21' - 'PostContext: }' - 'catch' - '{' + 'LineNumber: 19' + 'PostContext: } catch {' ' $_ | Out-Sentry | Out-Null' '}' - 'PreContext: $transport = [RecordingTransport]::new()' + '$thread = $events[0].SentryThreads | Where-Object { $_.Id -eq 0 }' + 'PreContext: $events = [System.Collections.Generic.List[Sentry.SentryEvent]]::new();' + '$transport = [RecordingTransport]::new()' 'StartSentryForEventTests ([ref] $events) ([ref] $transport)' - 'try' - '{' + 'try {' '----------------' 'ContextLine: funcC' 'Function: funcA' 'InApp: True' - 'LineNumber: 12' + 'LineNumber: 11' 'PostContext: }' '$events = [System.Collections.Generic.List[Sentry.SentryEvent]]::new();' '$transport = [RecordingTransport]::new()' 'StartSentryForEventTests ([ref] $events) ([ref] $transport)' - 'PreContext: . ./tests/throwingshort.ps1' - 'function funcA' - '{' + 'PreContext: . ./tests/utils.ps1' + '. ./tests/throwingshort.ps1' + 'function funcA {' ' # Call to another file' '----------------' "AbsolutePath: $integrationTestThrowingScript" 'ColumnNumber: 5' - 'ContextLine: throw "Short context test"' + "ContextLine: throw 'Short context test'" 'Function: funcC' 'InApp: True' 'LineNumber: 2' diff --git a/tests/stacktrace.tests.ps1 b/tests/stacktrace.tests.ps1 index 55fa0d1..fddab07 100644 --- a/tests/stacktrace.tests.ps1 +++ b/tests/stacktrace.tests.ps1 @@ -37,21 +37,21 @@ BeforeAll { $frames.Count | Should -BeGreaterThan 0 if ($event.SentryExceptions[1].Type -eq 'Write-Error') { - $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 18) + $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 15) $event.SentryExceptions[0].Type | Should -Be 'Microsoft.PowerShell.Commands.WriteErrorException' $event.SentryExceptions[0].Module | Should -Match 'Microsoft.PowerShell.Commands.Utility' } else { if ($event.SentryExceptions[1].Type -eq 'error') { - $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 17) + $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 14) $(GetListItem $frames -1).ColumnNumber | Should -BeGreaterThan 0 } else { - $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 24) + $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 19) } $event.SentryExceptions[0].Type | Should -Be 'System.Management.Automation.RuntimeException' $event.SentryExceptions[0].Module | Should -Match 'System.Management.Automation' } - $checkFrame.Invoke((GetListItem $frames -2), 'funcA', 7) + $checkFrame.Invoke((GetListItem $frames -2), 'funcA', 6) $event.SentryExceptions[0].Value | Should -Be 'error' if ($event.SentryExceptions[1].Type -eq 'error,funcB') { @@ -88,7 +88,7 @@ BeforeAll { $frame.PreContext | Should -Be @('function funcC {') $frame.PreContext.Count | Should -Be 1 - $frame.ContextLine | Should -Be ' throw "Short context test"' + $frame.ContextLine | Should -Be " throw 'Short context test'" $frame.PostContext | Should -Be @('}') $frame.PostContext.Count | Should -Be 1 } @@ -116,8 +116,8 @@ Describe 'Out-Sentry' { $event.SentryThreads.Count | Should -Be 2 [Sentry.SentryStackFrame[]] $frames = $event.SentryThreads[0].Stacktrace.Frames $frames.Count | Should -BeGreaterThan 0 - $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 19) - $checkFrame.Invoke((GetListItem $frames -2), 'funcA', 7) + $checkFrame.Invoke((GetListItem $frames -1), 'funcB', 16) + $checkFrame.Invoke((GetListItem $frames -2), 'funcA', 6) # A module-based frame should be in-app=false $frames | Where-Object -Property Module | Select-Object -First 1 -ExpandProperty 'InApp' | Should -Be $false @@ -162,7 +162,7 @@ Describe 'Out-Sentry' { (GetListItem $frames -1).AbsolutePath | Should -Be $PSCommandPath (GetListItem $frames -1).LineNumber | Should -BeGreaterThan 0 (GetListItem $frames -1).InApp | Should -Be $true - (GetListItem $frames -1).PreContext | Should -Be @(' {', " funcA 'throw' 'exception'", ' }', ' catch', ' {') + (GetListItem $frames -1).PreContext | Should -Be @('', " It 'captures exception' {", ' try {', " funcA 'throw' 'exception'", ' } catch {') (GetListItem $frames -1).ContextLine | Should -Be ' $_.Exception | Out-Sentry' (GetListItem $frames -1).PostContext | Should -Be @(' }', ' $events.Count | Should -Be 1', ' [Sentry.SentryEvent]$event = $events.ToArray()[0]', ' $event.SentryExceptions.Count | Should -Be 2', '')