From 836c6f6d39f536f8a492362ad938eaa18ffa60a8 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 12:04:20 +0100 Subject: [PATCH 01/14] feat: add TrySentry module for graceful Sentry telemetry integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add wrapper module that provides graceful degradation when Sentry PowerShell SDK is unavailable. This enables operational visibility into test infrastructure failures without creating hard dependencies or breaking functionality when Sentry is not installed. Key features: - Auto-loads Sentry module if available, fails silently if not - Checks [Sentry.SentrySdk]::IsEnabled before initialization - Respects $env:SENTRY_DSN for override/disable (empty = disabled) - Caches initialization state to avoid repeated module import attempts - Exports wrapper functions: TryStart-Sentry, TryOut-Sentry, TryAdd-SentryBreadcrumb, TryEdit-SentryScope This is Phase 1 of implementation per issue #18. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- utils/TrySentry.psm1 | 413 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 413 insertions(+) create mode 100644 utils/TrySentry.psm1 diff --git a/utils/TrySentry.psm1 b/utils/TrySentry.psm1 new file mode 100644 index 0000000..32fc69e --- /dev/null +++ b/utils/TrySentry.psm1 @@ -0,0 +1,413 @@ +# Sentry PowerShell SDK wrapper module +# Provides graceful degradation when Sentry module is unavailable + +# Default DSN for app-runner telemetry +# Override with $env:SENTRY_DSN or disable with $env:SENTRY_DSN = $null +$script:DefaultDsn = 'https://8e7867b699467018c4f8a64a5a0b5b43@o447951.ingest.us.sentry.io/4510317734854656' + +# Track initialization state to avoid repeated attempts +$script:InitializationAttempted = $false +$script:SentryAvailable = $false + +<# +.SYNOPSIS +Internal function to ensure Sentry SDK is ready for use. + +.DESCRIPTION +Checks if Sentry is disabled, loads the module if needed, and initializes the SDK. +All failures are silent (Write-Debug only) to avoid breaking functionality. + +.OUTPUTS +[bool] True if Sentry is ready to use, false otherwise. +#> +function Ensure-SentryReady { + [CmdletBinding()] + [OutputType([bool])] + param() + + # Check if disabled via environment variable + if ([string]::IsNullOrEmpty($env:SENTRY_DSN) -and $env:SENTRY_DSN -ne $null) { + Write-Debug "Sentry disabled: SENTRY_DSN environment variable is explicitly set to empty" + return $false + } + + # Return cached result if we already attempted initialization + if ($script:InitializationAttempted) { + return $script:SentryAvailable + } + + $script:InitializationAttempted = $true + + # Check if Sentry SDK type is available (module loaded) + $sentryTypeAvailable = $false + try { + $null = [Sentry.SentrySdk] + $sentryTypeAvailable = $true + Write-Debug "Sentry SDK type already available" + } + catch { + Write-Debug "Sentry SDK type not available, attempting to load module" + } + + # Try to import Sentry module if type not available + if (-not $sentryTypeAvailable) { + try { + Import-Module Sentry -ErrorAction Stop + $null = [Sentry.SentrySdk] # Verify type is now available + Write-Debug "Sentry module imported successfully" + $sentryTypeAvailable = $true + } + catch { + Write-Debug "Failed to import Sentry module: $_" + $script:SentryAvailable = $false + return $false + } + } + + # Check if already initialized + if ([Sentry.SentrySdk]::IsEnabled) { + Write-Debug "Sentry SDK already initialized" + $script:SentryAvailable = $true + return $true + } + + # Initialize Sentry SDK + try { + $dsn = if ($env:SENTRY_DSN) { $env:SENTRY_DSN } else { $script:DefaultDsn } + + if ([string]::IsNullOrEmpty($dsn) -or $dsn -eq 'https://TODO@TODO.ingest.sentry.io/TODO') { + Write-Debug "Sentry DSN not configured, telemetry disabled" + $script:SentryAvailable = $false + return $false + } + + Write-Debug "Initializing Sentry with DSN: $($dsn -replace '(?<=https://)([^@]+)(?=@)', '***')" + + Start-Sentry -Dsn $dsn + + if ([Sentry.SentrySdk]::IsEnabled) { + Write-Debug "Sentry SDK initialized successfully" + $script:SentryAvailable = $true + return $true + } + else { + Write-Debug "Sentry SDK initialization completed but IsEnabled is false" + $script:SentryAvailable = $false + return $false + } + } + catch { + Write-Debug "Failed to initialize Sentry SDK: $_" + $script:SentryAvailable = $false + return $false + } +} + +<# +.SYNOPSIS +Optionally initialize Sentry with module context and tags. + +.DESCRIPTION +Ensures Sentry is ready and sets contextual tags like module name, version, +PowerShell version, and OS. This is optional - Sentry will auto-initialize +on first use of any Try* function if not already started. + +.PARAMETER ModuleName +Name of the module using Sentry (e.g., 'SentryAppRunner'). + +.PARAMETER ModuleVersion +Version of the module. + +.PARAMETER Tags +Additional custom tags to set on all events. + +.EXAMPLE +TryStart-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion '1.0.0' + +.EXAMPLE +TryStart-Sentry -ModuleName 'MyModule' -ModuleVersion '2.1.0' -Tags @{ + environment = 'ci' + build_id = '12345' +} + +.OUTPUTS +[bool] True if Sentry was initialized successfully, false otherwise. +#> +function TryStart-Sentry { + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory = $false)] + [string]$ModuleName, + + [Parameter(Mandatory = $false)] + [string]$ModuleVersion, + + [Parameter(Mandatory = $false)] + [hashtable]$Tags = @{} + ) + + if (-not (Ensure-SentryReady)) { + return $false + } + + try { + # Set contextual tags + Edit-SentryScope { + if ($ModuleName) { + $_.SetTag('module_name', $ModuleName) + } + + if ($ModuleVersion) { + $_.SetTag('module_version', $ModuleVersion) + } + + # PowerShell version + $_.SetTag('powershell_version', $PSVersionTable.PSVersion.ToString()) + + # Operating system + $_.SetTag('os', $PSVersionTable.OS ?? $PSVersionTable.Platform ?? 'Windows') + + # CI environment detection + if ($env:CI) { + $_.SetTag('ci', 'true') + } + + # Custom tags + foreach ($key in $Tags.Keys) { + $_.SetTag($key, $Tags[$key]) + } + } + + Write-Debug "Sentry context initialized with module: $ModuleName, version: $ModuleVersion" + return $true + } + catch { + Write-Debug "Failed to set Sentry context: $_" + return $false + } +} + +<# +.SYNOPSIS +Wrapper for Out-Sentry that fails silently if Sentry is unavailable. + +.DESCRIPTION +Sends an error, exception, or message to Sentry. Automatically ensures Sentry +is ready before sending. Fails silently if Sentry is not available. + +.PARAMETER InputObject +The object to send to Sentry. Can be an ErrorRecord, Exception, or string message. + +.PARAMETER Tag +Optional hashtable of tags to attach to the event. + +.PARAMETER Level +Optional severity level (Debug, Info, Warning, Error, Fatal). + +.EXAMPLE +try { + Get-Item "nonexistent.txt" +} +catch { + $_ | TryOut-Sentry +} + +.EXAMPLE +"Something important happened" | TryOut-Sentry -Level Info + +.EXAMPLE +$error[0] | TryOut-Sentry -Tag @{operation = "device_connect"; platform = "Xbox"} + +.OUTPUTS +[Guid] Event ID if sent successfully, $null otherwise. +#> +function TryOut-Sentry { + [CmdletBinding()] + [OutputType([System.Nullable[Guid]])] + param( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [object]$InputObject, + + [Parameter(Mandatory = $false)] + [hashtable]$Tag = @{}, + + [Parameter(Mandatory = $false)] + [ValidateSet('Debug', 'Info', 'Warning', 'Error', 'Fatal')] + [string]$Level + ) + + process { + if (-not (Ensure-SentryReady)) { + return $null + } + + try { + # Build Out-Sentry parameters + $outSentryParams = @{} + + if ($Tag.Count -gt 0) { + $outSentryParams['EditScope'] = { + foreach ($key in $Tag.Keys) { + $_.SetTag($key, $Tag[$key]) + } + }.GetNewClosure() + } + + # Send to Sentry based on input type + if ($InputObject -is [System.Management.Automation.ErrorRecord]) { + $eventId = $InputObject | Out-Sentry @outSentryParams + } + elseif ($InputObject -is [System.Exception]) { + $eventId = Out-Sentry -Exception $InputObject @outSentryParams + } + else { + # Treat as message + $eventId = Out-Sentry -Message $InputObject.ToString() @outSentryParams + } + + if ($eventId) { + Write-Debug "Event sent to Sentry: $eventId" + } + + return $eventId + } + catch { + Write-Debug "Failed to send event to Sentry: $_" + return $null + } + } +} + +<# +.SYNOPSIS +Wrapper for Add-SentryBreadcrumb that fails silently if Sentry is unavailable. + +.DESCRIPTION +Adds a breadcrumb to the current Sentry scope. Breadcrumbs provide context +for subsequent events. Automatically ensures Sentry is ready before adding. + +.PARAMETER Message +The breadcrumb message. + +.PARAMETER Category +Optional category for the breadcrumb (e.g., "device", "network", "app"). + +.PARAMETER Data +Optional hashtable of additional data to attach to the breadcrumb. + +.PARAMETER Level +Optional breadcrumb level (Debug, Info, Warning, Error, Critical). + +.EXAMPLE +TryAdd-SentryBreadcrumb -Message "Acquiring device lock" -Category "device" + +.EXAMPLE +TryAdd-SentryBreadcrumb -Message "HTTP request completed" -Category "network" -Data @{ + status_code = 200 + duration_ms = 150 +} + +.EXAMPLE +"Starting application installation" | TryAdd-SentryBreadcrumb -Category "app" +#> +function TryAdd-SentryBreadcrumb { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [string]$Message, + + [Parameter(Mandatory = $false)] + [string]$Category, + + [Parameter(Mandatory = $false)] + [hashtable]$Data = @{}, + + [Parameter(Mandatory = $false)] + [ValidateSet('Debug', 'Info', 'Warning', 'Error', 'Critical')] + [string]$Level + ) + + process { + if (-not (Ensure-SentryReady)) { + return + } + + try { + $breadcrumbParams = @{ + Message = $Message + } + + if ($Category) { + $breadcrumbParams['Category'] = $Category + } + + if ($Data.Count -gt 0) { + $breadcrumbParams['Data'] = $Data + } + + if ($Level) { + $breadcrumbParams['Level'] = $Level + } + + Add-SentryBreadcrumb @breadcrumbParams + Write-Debug "Breadcrumb added: $Message" + } + catch { + Write-Debug "Failed to add Sentry breadcrumb: $_" + } + } +} + +<# +.SYNOPSIS +Wrapper for Edit-SentryScope that fails silently if Sentry is unavailable. + +.DESCRIPTION +Modifies the current Sentry scope to add tags, extra data, or change context. +Automatically ensures Sentry is ready before editing. + +.PARAMETER ScopeSetup +Scriptblock that receives the scope object and modifies it. + +.EXAMPLE +TryEdit-SentryScope { + $_.SetTag('operation', 'device_connect') + $_.SetExtra('target', '192.168.1.100') +} + +.EXAMPLE +TryEdit-SentryScope { + $_.User = @{ + id = $env:USERNAME + username = $env:USERNAME + } +} +#> +function TryEdit-SentryScope { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [scriptblock]$ScopeSetup + ) + + if (-not (Ensure-SentryReady)) { + return + } + + try { + Edit-SentryScope -ScopeSetup $ScopeSetup + Write-Debug "Sentry scope edited" + } + catch { + Write-Debug "Failed to edit Sentry scope: $_" + } +} + +# Export public functions +Export-ModuleMember -Function @( + 'TryStart-Sentry', + 'TryOut-Sentry', + 'TryAdd-SentryBreadcrumb', + 'TryEdit-SentryScope' +) From 8c7d34bd2499c9927cef0a9221baa8c6cc910831 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 12:07:50 +0100 Subject: [PATCH 02/14] feat: add performance monitoring support to TrySentry module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TryStart-SentryTransaction wrapper to enable performance tracking of critical operations like device connections, app deployments, and builds. The transaction object supports creating child spans using the null-conditional operator (?.) pattern, ensuring graceful degradation when Sentry is unavailable: $transaction = TryStart-SentryTransaction -Name "Connect" -Operation "device.connect" $span = $transaction?.StartChild("lock.acquire") $span?.Finish() $transaction?.Finish() This enables identifying performance bottlenecks in test automation workflows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- utils/TrySentry.psm1 | 92 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/utils/TrySentry.psm1 b/utils/TrySentry.psm1 index 32fc69e..f5ab95b 100644 --- a/utils/TrySentry.psm1 +++ b/utils/TrySentry.psm1 @@ -404,10 +404,100 @@ function TryEdit-SentryScope { } } +<# +.SYNOPSIS +Wrapper for Start-SentryTransaction that fails silently if Sentry is unavailable. + +.DESCRIPTION +Starts a performance monitoring transaction to track operation duration and create spans. +Returns a transaction object that can be used to create child spans and finish the transaction. +Automatically ensures Sentry is ready before starting. + +.PARAMETER Name +The name of the transaction (e.g., "Connect-Device", "Deploy-App"). + +.PARAMETER Operation +The operation type (e.g., "device.connect", "app.deploy", "http.request"). + +.PARAMETER CustomSamplingContext +Optional hashtable with additional context for sampling decisions. + +.EXAMPLE +$transaction = TryStart-SentryTransaction -Name "Connect-Device" -Operation "device.connect" +try { + # Create a span for a sub-operation + $span = $transaction?.StartChild("device.lock.acquire") + # ... perform lock acquisition ... + $span?.Finish() + + # Create another span + $span = $transaction?.StartChild("device.connection.establish") + # ... establish connection ... + $span?.Finish() +} +finally { + # Always finish the transaction + $transaction?.Finish() +} + +.EXAMPLE +$transaction = TryStart-SentryTransaction -Name "Build-App" -Operation "build" -CustomSamplingContext @{ + target = "Xbox" + preset = "Debug" +} +try { + # ... build operations ... +} +finally { + $transaction?.Finish() +} + +.OUTPUTS +[Sentry.ITransaction] Transaction object if successful, $null otherwise. +#> +function TryStart-SentryTransaction { + [CmdletBinding()] + [OutputType([object])] + param( + [Parameter(Mandatory = $true)] + [string]$Name, + + [Parameter(Mandatory = $true)] + [string]$Operation, + + [Parameter(Mandatory = $false)] + [hashtable]$CustomSamplingContext = @{} + ) + + if (-not (Ensure-SentryReady)) { + return $null + } + + try { + $transactionParams = @{ + Name = $Name + Operation = $Operation + } + + if ($CustomSamplingContext.Count -gt 0) { + $transactionParams['CustomSamplingContext'] = $CustomSamplingContext + } + + $transaction = Start-SentryTransaction @transactionParams + Write-Debug "Sentry transaction started: $Name ($Operation)" + return $transaction + } + catch { + Write-Debug "Failed to start Sentry transaction: $_" + return $null + } +} + # Export public functions Export-ModuleMember -Function @( 'TryStart-Sentry', 'TryOut-Sentry', 'TryAdd-SentryBreadcrumb', - 'TryEdit-SentryScope' + 'TryEdit-SentryScope', + 'TryStart-SentryTransaction' ) From 2b89e5202211c98e579a6fb205f030538d8251c6 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 12:09:07 +0100 Subject: [PATCH 03/14] feat: integrate TrySentry telemetry into app-runner and sentry-api-client modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Auto-initialize Sentry telemetry on module import with module name and version context. The initialization is fully optional and fails silently if: - Sentry PowerShell SDK is not installed - SENTRY_DSN environment variable is empty/null - TrySentry module import fails Both modules now automatically track operational errors and performance metrics without requiring any code changes by consumers. Telemetry can be disabled by setting $env:SENTRY_DSN to empty string or null. This completes Phase 2 of implementation per issue #18. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app-runner/SentryAppRunner.psm1 | 12 ++++++++++++ sentry-api-client/SentryApiClient.psm1 | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/app-runner/SentryAppRunner.psm1 b/app-runner/SentryAppRunner.psm1 index c1ec76e..b21b4e7 100644 --- a/app-runner/SentryAppRunner.psm1 +++ b/app-runner/SentryAppRunner.psm1 @@ -1,6 +1,18 @@ $ErrorActionPreference = 'Stop' $PSNativeCommandUseErrorActionPreference = $true +# Initialize Sentry telemetry (optional, graceful degradation if unavailable) +try { + Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction SilentlyContinue + if (Get-Module -Name TrySentry) { + $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryAppRunner.psd1') + TryStart-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion $moduleManifest.ModuleVersion + } +} +catch { + Write-Debug "Sentry telemetry initialization skipped: $_" +} + # Import device providers in the correct order (base provider first, then implementations, then factory) $ProviderFiles = @( "$PSScriptRoot\Private\DeviceProviders\DeviceProvider.ps1", diff --git a/sentry-api-client/SentryApiClient.psm1 b/sentry-api-client/SentryApiClient.psm1 index 0b969e1..4f4738a 100644 --- a/sentry-api-client/SentryApiClient.psm1 +++ b/sentry-api-client/SentryApiClient.psm1 @@ -1,3 +1,15 @@ +# Initialize Sentry telemetry (optional, graceful degradation if unavailable) +try { + Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction SilentlyContinue + if (Get-Module -Name TrySentry) { + $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryApiClient.psd1') + TryStart-Sentry -ModuleName 'SentryApiClient' -ModuleVersion $moduleManifest.ModuleVersion + } +} +catch { + Write-Debug "Sentry telemetry initialization skipped: $_" +} + $Script:SentryApiConfig = @{ BaseUrl = 'https://sentry.io/api/0' ApiToken = $null From 11657e4914b3776102a7051bead47c77f3edfb87 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 12:16:41 +0100 Subject: [PATCH 04/14] feat: integrate Sentry telemetry into error handling and critical operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhanced error handling and added diagnostic breadcrumbs throughout the codebase: **Error Handling:** - Modified ErrorHandler::LogError() to send all errors to Sentry with: - Error ID, category, platform, session ID as tags - Exception context as extra data - Full detailed message as event content **Breadcrumb Integration:** Connect-Device: - Starting device connection - Acquiring/acquired device lock - Creating device provider - Establishing/established connection Invoke-DeviceApp: - Starting application deployment - Invoking application on device - Application execution completed (with exit code) Integration.TestUtils: - EVENT_CAPTURED lines mismatch (with expected/found counts) - Starting Sentry event polling (by ID or tag) - Sentry event polling timed out (with last error) All breadcrumbs include relevant context data (platform, executable, counts, etc.) to provide diagnostic trail when errors occur. All integrations fail gracefully when Sentry is unavailable. This completes Phase 3 of implementation per issue #18. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app-runner/Private/ErrorHandling.ps1 | 28 ++++++++++++++++++++++ app-runner/Public/Connect-Device.ps1 | 28 ++++++++++++++++++++++ app-runner/Public/Invoke-DeviceApp.ps1 | 17 +++++++++++++ utils/Integration.TestUtils.psm1 | 33 ++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) diff --git a/app-runner/Private/ErrorHandling.ps1 b/app-runner/Private/ErrorHandling.ps1 index f90f963..39120f6 100644 --- a/app-runner/Private/ErrorHandling.ps1 +++ b/app-runner/Private/ErrorHandling.ps1 @@ -122,6 +122,34 @@ class ErrorHandler { # Log to debug stream for troubleshooting Write-Debug "Error logged with ID: $errorId" + + # Send to Sentry for operational visibility + if (Get-Command -Name TryOut-Sentry -ErrorAction SilentlyContinue) { + $sentryTags = @{ + error_id = $errorId + category = $exception.Category.ToString() + } + + if ($exception.Platform) { + $sentryTags['platform'] = $exception.Platform + } + + if ($exception.SessionId) { + $sentryTags['session_id'] = $exception.SessionId + } + + # Add context as extra data in scope + $message = $exception.GetDetailedMessage() + if ($exception.Context.Count -gt 0) { + TryEdit-SentryScope { + foreach ($key in $exception.Context.Keys) { + $_.SetExtra($key, $exception.Context[$key]) + } + } + } + + TryOut-Sentry -InputObject $message -Tag $sentryTags -Level Error + } } static [void]LogError([string]$message, [ConsoleErrorCategory]$category) { diff --git a/app-runner/Public/Connect-Device.ps1 b/app-runner/Public/Connect-Device.ps1 index 0a732d5..9cbe428 100644 --- a/app-runner/Public/Connect-Device.ps1 +++ b/app-runner/Public/Connect-Device.ps1 @@ -49,6 +49,11 @@ function Connect-Device { Write-Debug "Connecting to device platform: $Platform" + TryAdd-SentryBreadcrumb -Message "Starting device connection" -Category "device" -Data @{ + platform = $Platform + target = $Target + } + # Validate platform is supported if (-not [DeviceProviderFactory]::IsPlatformSupported($Platform)) { throw "Unsupported platform: $Platform. Supported platforms: $([DeviceProviderFactory]::GetSupportedPlatforms() -join ', ')" @@ -68,6 +73,11 @@ function Connect-Device { $resourceName = New-DeviceResourceName -Platform $Platform -Target $mutexTarget Write-Debug "Device resource name: $resourceName" + TryAdd-SentryBreadcrumb -Message "Acquiring device lock" -Category "device" -Data @{ + resource_name = $resourceName + timeout_seconds = $TimeoutSeconds + } + # Acquire exclusive access to the device resource # Default 60-minute timeout with progress messages every minute $mutex = $null @@ -75,10 +85,23 @@ function Connect-Device { $mutex = Request-DeviceAccess -ResourceName $resourceName -TimeoutSeconds $TimeoutSeconds -ProgressIntervalSeconds 60 Write-Output "Acquired exclusive access to device: $resourceName" + TryAdd-SentryBreadcrumb -Message "Device lock acquired" -Category "device" -Data @{ + resource_name = $resourceName + } + # Create provider for the specified platform + TryAdd-SentryBreadcrumb -Message "Creating device provider" -Category "device" -Data @{ + platform = $Platform + } + $provider = [DeviceProviderFactory]::CreateProvider($Platform) # Connect using the provider + TryAdd-SentryBreadcrumb -Message "Establishing device connection" -Category "device" -Data @{ + platform = $Platform + target = $Target + } + $sessionInfo = $provider.Connect($Target) # Store the provider instance and mutex with the session @@ -87,6 +110,11 @@ function Connect-Device { $script:CurrentSession.Mutex = $mutex $script:CurrentSession.ResourceName = $resourceName + TryAdd-SentryBreadcrumb -Message "Device connection established" -Category "device" -Data @{ + platform = $Platform + device_id = $script:CurrentSession.Identifier + } + Write-Debug "Successfully connected to $Platform device (Device: $($script:CurrentSession.Identifier))" return $script:CurrentSession diff --git a/app-runner/Public/Invoke-DeviceApp.ps1 b/app-runner/Public/Invoke-DeviceApp.ps1 index 23b568a..d0da0aa 100644 --- a/app-runner/Public/Invoke-DeviceApp.ps1 +++ b/app-runner/Public/Invoke-DeviceApp.ps1 @@ -31,9 +31,26 @@ function Invoke-DeviceApp { Write-Debug "Running application: $ExecutablePath with arguments: $Arguments" Write-Debug "Target platform: $($script:CurrentSession.Platform)" + TryAdd-SentryBreadcrumb -Message "Starting application deployment" -Category "app" -Data @{ + executable = (Split-Path -Leaf $ExecutablePath) + platform = $script:CurrentSession.Platform + has_arguments = ($Arguments.Length -gt 0) + } + # Use the provider to run the application $provider = $script:CurrentSession.Provider + + TryAdd-SentryBreadcrumb -Message "Invoking application on device" -Category "app" -Data @{ + executable = (Split-Path -Leaf $ExecutablePath) + platform = $script:CurrentSession.Platform + } + $result = $provider.RunApplication($ExecutablePath, $Arguments) + TryAdd-SentryBreadcrumb -Message "Application execution completed" -Category "app" -Data @{ + executable = (Split-Path -Leaf $ExecutablePath) + exit_code = $result.ExitCode + } + return $result } \ No newline at end of file diff --git a/utils/Integration.TestUtils.psm1 b/utils/Integration.TestUtils.psm1 index 6a1d719..d53d74d 100644 --- a/utils/Integration.TestUtils.psm1 +++ b/utils/Integration.TestUtils.psm1 @@ -56,6 +56,15 @@ function Get-EventIds { # Provide detailed error message if count doesn't match if ($eventCapturedLines.Count -ne $ExpectedCount) { + # Add breadcrumb for diagnostic purposes + if (Get-Command -Name TryAdd-SentryBreadcrumb -ErrorAction SilentlyContinue) { + TryAdd-SentryBreadcrumb -Message "EVENT_CAPTURED lines mismatch" -Category "test" -Level Error -Data @{ + expected_count = $ExpectedCount + found_count = $eventCapturedLines.Count + output_line_count = @($AppOutput).Count + } + } + $errorMsg = "Expected $ExpectedCount EVENT_CAPTURED line(s) but found $($eventCapturedLines.Count).`n" $errorMsg += "`nSearched for lines matching: 'EVENT_CAPTURED:'`n" @@ -121,9 +130,22 @@ function Get-SentryTestEvent { if ($EventId) { Write-Host "Fetching Sentry event by ID: $EventId" -ForegroundColor Yellow $progressActivity = "Waiting for Sentry event $EventId" + if (Get-Command -Name TryAdd-SentryBreadcrumb -ErrorAction SilentlyContinue) { + TryAdd-SentryBreadcrumb -Message "Starting Sentry event polling" -Category "test" -Data @{ + event_id = $EventId + timeout_seconds = $TimeoutSeconds + } + } } elseif ($TagName -and $TagValue) { Write-Host "Fetching Sentry event by tag: $TagName=$TagValue" -ForegroundColor Yellow $progressActivity = "Waiting for Sentry event with tag $TagName=$TagValue" + if (Get-Command -Name TryAdd-SentryBreadcrumb -ErrorAction SilentlyContinue) { + TryAdd-SentryBreadcrumb -Message "Starting Sentry event polling by tag" -Category "test" -Data @{ + tag_name = $TagName + tag_value = $TagValue + timeout_seconds = $TimeoutSeconds + } + } } else { throw 'Must specify either EventId or both TagName and TagValue' } @@ -179,6 +201,17 @@ function Get-SentryTestEvent { Write-Progress -Activity $progressActivity -Completed } + # Add breadcrumb for timeout + if (Get-Command -Name TryAdd-SentryBreadcrumb -ErrorAction SilentlyContinue) { + TryAdd-SentryBreadcrumb -Message "Sentry event polling timed out" -Category "test" -Level Error -Data @{ + event_id = $EventId + tag_name = $TagName + tag_value = $TagValue + timeout_seconds = $TimeoutSeconds + last_error = $lastError + } + } + if ($EventId) { throw "Event $EventId not found in Sentry within $TimeoutSeconds seconds: $lastError" } else { From 54d21bce8f8b1ffb0956e08925e1c26b2d8717dd Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 12:17:18 +0100 Subject: [PATCH 05/14] docs: add telemetry documentation to root README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive Telemetry section documenting: - What data is collected (errors, breadcrumbs, performance metrics) - How to disable telemetry ($env:SENTRY_DSN = $null) - How to use custom Sentry project - DSN security explanation (public keys, safe to expose) - Optional Sentry module dependency Positioned before Requirements section for visibility. Emphasizes user control and privacy while explaining operational benefits. This completes Phase 4 of implementation per issue #18. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index c2d1c94..fe96096 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,46 @@ Future support planned: - Mobile platforms (iOS, Android) - Desktop platforms (Windows, macOS, Linux) +## Telemetry + +This toolkit automatically collects operational telemetry using [Sentry](https://sentry.io) to improve reliability and diagnose issues. Telemetry helps identify test infrastructure failures, device connection problems, and automation bottlenecks. + +### What's Collected + +- Module errors and exceptions with context (platform, session ID, error category) +- Device connection failures and lock acquisition issues +- Test infrastructure problems (missing event captures, polling timeouts) +- Diagnostic operation breadcrumbs showing the sequence of operations leading to failures +- Performance metrics for critical operations (device connections, app deployments) + +### Privacy & Control + +**Telemetry is optional and controlled by environment variables:** + +**To disable telemetry completely:** +```powershell +$env:SENTRY_DSN = $null # or empty string +``` + +**To use your own Sentry project:** +```powershell +$env:SENTRY_DSN = 'https://your-key@o123.ingest.sentry.io/your-project' +``` + +**Note:** DSNs are public client keys that are safe to expose in code or configuration. They cannot be used to access your Sentry account or data. See [Sentry DSN documentation](https://docs.sentry.io/product/sentry-basics/dsn-explainer/) for details. + +### Dependencies + +Telemetry requires the optional `Sentry` PowerShell module: + +```powershell +Install-Module -Name Sentry +``` + +If the module is not installed, telemetry is automatically disabled and all functionality works normally. The toolkit has no hard dependency on Sentry. + +**Learn more:** [sentry-powershell on GitHub](https://github.com/getsentry/sentry-powershell) + ## Requirements ### Platform-Specific Prerequisites From f0b520e483e117ec0a2202d5b3f17a28d7a0c322 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 13:53:54 +0100 Subject: [PATCH 06/14] docs: enhance telemetry section in README for clarity and detail --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fe96096..f767f70 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ This toolkit automatically collects operational telemetry using [Sentry](https:/ ### What's Collected +Examples of the types of telemetry data collected: + - Module errors and exceptions with context (platform, session ID, error category) - Device connection failures and lock acquisition issues - Test infrastructure problems (missing event captures, polling timeouts) @@ -34,7 +36,7 @@ This toolkit automatically collects operational telemetry using [Sentry](https:/ ### Privacy & Control -**Telemetry is optional and controlled by environment variables:** +**Telemetry is optional, enabled by default, and controllably by environment variable:** **To disable telemetry completely:** ```powershell @@ -46,14 +48,16 @@ $env:SENTRY_DSN = $null # or empty string $env:SENTRY_DSN = 'https://your-key@o123.ingest.sentry.io/your-project' ``` -**Note:** DSNs are public client keys that are safe to expose in code or configuration. They cannot be used to access your Sentry account or data. See [Sentry DSN documentation](https://docs.sentry.io/product/sentry-basics/dsn-explainer/) for details. +**Note:** DSNs are public client keys that are safe to expose in code or configuration. +They cannot be used to access your Sentry account or data. +See [Sentry DSN documentation](https://docs.sentry.io/product/sentry-basics/dsn-explainer/) for details. ### Dependencies Telemetry requires the optional `Sentry` PowerShell module: ```powershell -Install-Module -Name Sentry +Install-Module -Name Sentry -Repository PSGallery -Force ``` If the module is not installed, telemetry is automatically disabled and all functionality works normally. The toolkit has no hard dependency on Sentry. From ee60c3829722c3a6477456f0f1d07a3ed3b12efb Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 13:59:09 +0100 Subject: [PATCH 07/14] refactor: use module-qualified names to eliminate unapproved verb warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renamed TrySentry wrapper functions to use standard approved PowerShell verbs and updated all call sites to use module-qualified names (TrySentry\*): **Function renames:** - TryStart-Sentry → Start-Sentry - TryOut-Sentry → Out-Sentry - TryAdd-SentryBreadcrumb → Add-SentryBreadcrumb - TryEdit-SentryScope → Edit-SentryScope - TryStart-SentryTransaction → Start-SentryTransaction **Call site updates:** - app-runner/SentryAppRunner.psm1: TrySentry\Start-Sentry - sentry-api-client/SentryApiClient.psm1: TrySentry\Start-Sentry - app-runner/Private/ErrorHandling.ps1: TrySentry\Out-Sentry, TrySentry\Edit-SentryScope - app-runner/Public/Connect-Device.ps1: TrySentry\Add-SentryBreadcrumb (5 calls) - app-runner/Public/Invoke-DeviceApp.ps1: TrySentry\Add-SentryBreadcrumb (3 calls) - utils/Integration.TestUtils.psm1: TrySentry\Add-SentryBreadcrumb (3 calls) Module-qualified names make it clear these are safe wrappers (TrySentry namespace) while eliminating PowerShell warnings about unapproved verbs. Modules now load silently without any warnings. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app-runner/Private/ErrorHandling.ps1 | 6 ++-- app-runner/Public/Connect-Device.ps1 | 12 +++---- app-runner/Public/Invoke-DeviceApp.ps1 | 6 ++-- app-runner/SentryAppRunner.psm1 | 2 +- sentry-api-client/SentryApiClient.psm1 | 2 +- utils/Integration.TestUtils.psm1 | 16 +++++----- utils/TrySentry.psm1 | 44 +++++++++++++------------- 7 files changed, 44 insertions(+), 44 deletions(-) diff --git a/app-runner/Private/ErrorHandling.ps1 b/app-runner/Private/ErrorHandling.ps1 index 39120f6..1b8e23c 100644 --- a/app-runner/Private/ErrorHandling.ps1 +++ b/app-runner/Private/ErrorHandling.ps1 @@ -124,7 +124,7 @@ class ErrorHandler { Write-Debug "Error logged with ID: $errorId" # Send to Sentry for operational visibility - if (Get-Command -Name TryOut-Sentry -ErrorAction SilentlyContinue) { + if (Get-Command -Name TrySentry\Out-Sentry -ErrorAction SilentlyContinue) { $sentryTags = @{ error_id = $errorId category = $exception.Category.ToString() @@ -141,14 +141,14 @@ class ErrorHandler { # Add context as extra data in scope $message = $exception.GetDetailedMessage() if ($exception.Context.Count -gt 0) { - TryEdit-SentryScope { + TrySentry\Edit-SentryScope { foreach ($key in $exception.Context.Keys) { $_.SetExtra($key, $exception.Context[$key]) } } } - TryOut-Sentry -InputObject $message -Tag $sentryTags -Level Error + TrySentry\Out-Sentry -InputObject $message -Tag $sentryTags -Level Error } } diff --git a/app-runner/Public/Connect-Device.ps1 b/app-runner/Public/Connect-Device.ps1 index 9cbe428..2b39511 100644 --- a/app-runner/Public/Connect-Device.ps1 +++ b/app-runner/Public/Connect-Device.ps1 @@ -49,7 +49,7 @@ function Connect-Device { Write-Debug "Connecting to device platform: $Platform" - TryAdd-SentryBreadcrumb -Message "Starting device connection" -Category "device" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Starting device connection" -Category "device" -Data @{ platform = $Platform target = $Target } @@ -73,7 +73,7 @@ function Connect-Device { $resourceName = New-DeviceResourceName -Platform $Platform -Target $mutexTarget Write-Debug "Device resource name: $resourceName" - TryAdd-SentryBreadcrumb -Message "Acquiring device lock" -Category "device" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Acquiring device lock" -Category "device" -Data @{ resource_name = $resourceName timeout_seconds = $TimeoutSeconds } @@ -85,19 +85,19 @@ function Connect-Device { $mutex = Request-DeviceAccess -ResourceName $resourceName -TimeoutSeconds $TimeoutSeconds -ProgressIntervalSeconds 60 Write-Output "Acquired exclusive access to device: $resourceName" - TryAdd-SentryBreadcrumb -Message "Device lock acquired" -Category "device" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Device lock acquired" -Category "device" -Data @{ resource_name = $resourceName } # Create provider for the specified platform - TryAdd-SentryBreadcrumb -Message "Creating device provider" -Category "device" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Creating device provider" -Category "device" -Data @{ platform = $Platform } $provider = [DeviceProviderFactory]::CreateProvider($Platform) # Connect using the provider - TryAdd-SentryBreadcrumb -Message "Establishing device connection" -Category "device" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Establishing device connection" -Category "device" -Data @{ platform = $Platform target = $Target } @@ -110,7 +110,7 @@ function Connect-Device { $script:CurrentSession.Mutex = $mutex $script:CurrentSession.ResourceName = $resourceName - TryAdd-SentryBreadcrumb -Message "Device connection established" -Category "device" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Device connection established" -Category "device" -Data @{ platform = $Platform device_id = $script:CurrentSession.Identifier } diff --git a/app-runner/Public/Invoke-DeviceApp.ps1 b/app-runner/Public/Invoke-DeviceApp.ps1 index d0da0aa..28723ba 100644 --- a/app-runner/Public/Invoke-DeviceApp.ps1 +++ b/app-runner/Public/Invoke-DeviceApp.ps1 @@ -31,7 +31,7 @@ function Invoke-DeviceApp { Write-Debug "Running application: $ExecutablePath with arguments: $Arguments" Write-Debug "Target platform: $($script:CurrentSession.Platform)" - TryAdd-SentryBreadcrumb -Message "Starting application deployment" -Category "app" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Starting application deployment" -Category "app" -Data @{ executable = (Split-Path -Leaf $ExecutablePath) platform = $script:CurrentSession.Platform has_arguments = ($Arguments.Length -gt 0) @@ -40,14 +40,14 @@ function Invoke-DeviceApp { # Use the provider to run the application $provider = $script:CurrentSession.Provider - TryAdd-SentryBreadcrumb -Message "Invoking application on device" -Category "app" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Invoking application on device" -Category "app" -Data @{ executable = (Split-Path -Leaf $ExecutablePath) platform = $script:CurrentSession.Platform } $result = $provider.RunApplication($ExecutablePath, $Arguments) - TryAdd-SentryBreadcrumb -Message "Application execution completed" -Category "app" -Data @{ + TrySentry\Add-SentryBreadcrumb -Message "Application execution completed" -Category "app" -Data @{ executable = (Split-Path -Leaf $ExecutablePath) exit_code = $result.ExitCode } diff --git a/app-runner/SentryAppRunner.psm1 b/app-runner/SentryAppRunner.psm1 index b21b4e7..a2d8366 100644 --- a/app-runner/SentryAppRunner.psm1 +++ b/app-runner/SentryAppRunner.psm1 @@ -6,7 +6,7 @@ try { Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction SilentlyContinue if (Get-Module -Name TrySentry) { $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryAppRunner.psd1') - TryStart-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion $moduleManifest.ModuleVersion + TrySentry\Start-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion $moduleManifest.ModuleVersion } } catch { diff --git a/sentry-api-client/SentryApiClient.psm1 b/sentry-api-client/SentryApiClient.psm1 index 4f4738a..ba2bf88 100644 --- a/sentry-api-client/SentryApiClient.psm1 +++ b/sentry-api-client/SentryApiClient.psm1 @@ -3,7 +3,7 @@ try { Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction SilentlyContinue if (Get-Module -Name TrySentry) { $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryApiClient.psd1') - TryStart-Sentry -ModuleName 'SentryApiClient' -ModuleVersion $moduleManifest.ModuleVersion + TrySentry\Start-Sentry -ModuleName 'SentryApiClient' -ModuleVersion $moduleManifest.ModuleVersion } } catch { diff --git a/utils/Integration.TestUtils.psm1 b/utils/Integration.TestUtils.psm1 index d53d74d..69537df 100644 --- a/utils/Integration.TestUtils.psm1 +++ b/utils/Integration.TestUtils.psm1 @@ -57,8 +57,8 @@ function Get-EventIds { # Provide detailed error message if count doesn't match if ($eventCapturedLines.Count -ne $ExpectedCount) { # Add breadcrumb for diagnostic purposes - if (Get-Command -Name TryAdd-SentryBreadcrumb -ErrorAction SilentlyContinue) { - TryAdd-SentryBreadcrumb -Message "EVENT_CAPTURED lines mismatch" -Category "test" -Level Error -Data @{ + if (Get-Command -Name TrySentry\Add-SentryBreadcrumb -ErrorAction SilentlyContinue) { + TrySentry\Add-SentryBreadcrumb -Message "EVENT_CAPTURED lines mismatch" -Category "test" -Level Error -Data @{ expected_count = $ExpectedCount found_count = $eventCapturedLines.Count output_line_count = @($AppOutput).Count @@ -130,8 +130,8 @@ function Get-SentryTestEvent { if ($EventId) { Write-Host "Fetching Sentry event by ID: $EventId" -ForegroundColor Yellow $progressActivity = "Waiting for Sentry event $EventId" - if (Get-Command -Name TryAdd-SentryBreadcrumb -ErrorAction SilentlyContinue) { - TryAdd-SentryBreadcrumb -Message "Starting Sentry event polling" -Category "test" -Data @{ + if (Get-Command -Name TrySentry\Add-SentryBreadcrumb -ErrorAction SilentlyContinue) { + TrySentry\Add-SentryBreadcrumb -Message "Starting Sentry event polling" -Category "test" -Data @{ event_id = $EventId timeout_seconds = $TimeoutSeconds } @@ -139,8 +139,8 @@ function Get-SentryTestEvent { } elseif ($TagName -and $TagValue) { Write-Host "Fetching Sentry event by tag: $TagName=$TagValue" -ForegroundColor Yellow $progressActivity = "Waiting for Sentry event with tag $TagName=$TagValue" - if (Get-Command -Name TryAdd-SentryBreadcrumb -ErrorAction SilentlyContinue) { - TryAdd-SentryBreadcrumb -Message "Starting Sentry event polling by tag" -Category "test" -Data @{ + if (Get-Command -Name TrySentry\Add-SentryBreadcrumb -ErrorAction SilentlyContinue) { + TrySentry\Add-SentryBreadcrumb -Message "Starting Sentry event polling by tag" -Category "test" -Data @{ tag_name = $TagName tag_value = $TagValue timeout_seconds = $TimeoutSeconds @@ -202,8 +202,8 @@ function Get-SentryTestEvent { } # Add breadcrumb for timeout - if (Get-Command -Name TryAdd-SentryBreadcrumb -ErrorAction SilentlyContinue) { - TryAdd-SentryBreadcrumb -Message "Sentry event polling timed out" -Category "test" -Level Error -Data @{ + if (Get-Command -Name TrySentry\Add-SentryBreadcrumb -ErrorAction SilentlyContinue) { + TrySentry\Add-SentryBreadcrumb -Message "Sentry event polling timed out" -Category "test" -Level Error -Data @{ event_id = $EventId tag_name = $TagName tag_value = $TagValue diff --git a/utils/TrySentry.psm1 b/utils/TrySentry.psm1 index f5ab95b..625c383 100644 --- a/utils/TrySentry.psm1 +++ b/utils/TrySentry.psm1 @@ -122,10 +122,10 @@ Version of the module. Additional custom tags to set on all events. .EXAMPLE -TryStart-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion '1.0.0' +Start-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion '1.0.0' .EXAMPLE -TryStart-Sentry -ModuleName 'MyModule' -ModuleVersion '2.1.0' -Tags @{ +Start-Sentry -ModuleName 'MyModule' -ModuleVersion '2.1.0' -Tags @{ environment = 'ci' build_id = '12345' } @@ -133,7 +133,7 @@ TryStart-Sentry -ModuleName 'MyModule' -ModuleVersion '2.1.0' -Tags @{ .OUTPUTS [bool] True if Sentry was initialized successfully, false otherwise. #> -function TryStart-Sentry { +function Start-Sentry { [CmdletBinding()] [OutputType([bool])] param( @@ -210,19 +210,19 @@ try { Get-Item "nonexistent.txt" } catch { - $_ | TryOut-Sentry + $_ | Out-Sentry } .EXAMPLE -"Something important happened" | TryOut-Sentry -Level Info +"Something important happened" | Out-Sentry -Level Info .EXAMPLE -$error[0] | TryOut-Sentry -Tag @{operation = "device_connect"; platform = "Xbox"} +$error[0] | Out-Sentry -Tag @{operation = "device_connect"; platform = "Xbox"} .OUTPUTS [Guid] Event ID if sent successfully, $null otherwise. #> -function TryOut-Sentry { +function Out-Sentry { [CmdletBinding()] [OutputType([System.Nullable[Guid]])] param( @@ -300,18 +300,18 @@ Optional hashtable of additional data to attach to the breadcrumb. Optional breadcrumb level (Debug, Info, Warning, Error, Critical). .EXAMPLE -TryAdd-SentryBreadcrumb -Message "Acquiring device lock" -Category "device" +Add-SentryBreadcrumb -Message "Acquiring device lock" -Category "device" .EXAMPLE -TryAdd-SentryBreadcrumb -Message "HTTP request completed" -Category "network" -Data @{ +Add-SentryBreadcrumb -Message "HTTP request completed" -Category "network" -Data @{ status_code = 200 duration_ms = 150 } .EXAMPLE -"Starting application installation" | TryAdd-SentryBreadcrumb -Category "app" +"Starting application installation" | Add-SentryBreadcrumb -Category "app" #> -function TryAdd-SentryBreadcrumb { +function Add-SentryBreadcrumb { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] @@ -371,20 +371,20 @@ Automatically ensures Sentry is ready before editing. Scriptblock that receives the scope object and modifies it. .EXAMPLE -TryEdit-SentryScope { +Edit-SentryScope { $_.SetTag('operation', 'device_connect') $_.SetExtra('target', '192.168.1.100') } .EXAMPLE -TryEdit-SentryScope { +Edit-SentryScope { $_.User = @{ id = $env:USERNAME username = $env:USERNAME } } #> -function TryEdit-SentryScope { +function Edit-SentryScope { [CmdletBinding()] param( [Parameter(Mandatory = $true)] @@ -423,7 +423,7 @@ The operation type (e.g., "device.connect", "app.deploy", "http.request"). Optional hashtable with additional context for sampling decisions. .EXAMPLE -$transaction = TryStart-SentryTransaction -Name "Connect-Device" -Operation "device.connect" +$transaction = Start-SentryTransaction -Name "Connect-Device" -Operation "device.connect" try { # Create a span for a sub-operation $span = $transaction?.StartChild("device.lock.acquire") @@ -441,7 +441,7 @@ finally { } .EXAMPLE -$transaction = TryStart-SentryTransaction -Name "Build-App" -Operation "build" -CustomSamplingContext @{ +$transaction = Start-SentryTransaction -Name "Build-App" -Operation "build" -CustomSamplingContext @{ target = "Xbox" preset = "Debug" } @@ -455,7 +455,7 @@ finally { .OUTPUTS [Sentry.ITransaction] Transaction object if successful, $null otherwise. #> -function TryStart-SentryTransaction { +function Start-SentryTransaction { [CmdletBinding()] [OutputType([object])] param( @@ -495,9 +495,9 @@ function TryStart-SentryTransaction { # Export public functions Export-ModuleMember -Function @( - 'TryStart-Sentry', - 'TryOut-Sentry', - 'TryAdd-SentryBreadcrumb', - 'TryEdit-SentryScope', - 'TryStart-SentryTransaction' + 'Start-Sentry', + 'Out-Sentry', + 'Add-SentryBreadcrumb', + 'Edit-SentryScope', + 'Start-SentryTransaction' ) From 4395b6cd6ce49a7cff7ce5f7f17b9295a682d6bf Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 16:15:59 +0100 Subject: [PATCH 08/14] refactor: simplify telemetry by removing breadcrumbs and context data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove breadcrumb tracking from device operations and test utilities in favor of future structured logging implementation. Also fix SENTRY_DSN disable check to properly distinguish between unset (uses default) and explicitly disabled (empty string), and remove exception context data that could leak sensitive information. Changes: - Fix null-checking logic in TrySentry to use Test-Path for proper disable detection - Remove all Add-SentryBreadcrumb calls from Connect-Device, Invoke-DeviceApp, and Integration.TestUtils - Remove Edit-SentryScope block that added exception context as extra data - Simplify error reporting to only include message and basic tags 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app-runner/Private/ErrorHandling.ps1 | 9 ---- app-runner/Public/Connect-Device.ps1 | 28 ----------- app-runner/Public/Invoke-DeviceApp.ps1 | 17 ------- utils/Integration.TestUtils.psm1 | 33 ------------ utils/TrySentry.psm1 | 70 +++++++++++--------------- 5 files changed, 30 insertions(+), 127 deletions(-) diff --git a/app-runner/Private/ErrorHandling.ps1 b/app-runner/Private/ErrorHandling.ps1 index 1b8e23c..c139d20 100644 --- a/app-runner/Private/ErrorHandling.ps1 +++ b/app-runner/Private/ErrorHandling.ps1 @@ -138,16 +138,7 @@ class ErrorHandler { $sentryTags['session_id'] = $exception.SessionId } - # Add context as extra data in scope $message = $exception.GetDetailedMessage() - if ($exception.Context.Count -gt 0) { - TrySentry\Edit-SentryScope { - foreach ($key in $exception.Context.Keys) { - $_.SetExtra($key, $exception.Context[$key]) - } - } - } - TrySentry\Out-Sentry -InputObject $message -Tag $sentryTags -Level Error } } diff --git a/app-runner/Public/Connect-Device.ps1 b/app-runner/Public/Connect-Device.ps1 index 2b39511..0a732d5 100644 --- a/app-runner/Public/Connect-Device.ps1 +++ b/app-runner/Public/Connect-Device.ps1 @@ -49,11 +49,6 @@ function Connect-Device { Write-Debug "Connecting to device platform: $Platform" - TrySentry\Add-SentryBreadcrumb -Message "Starting device connection" -Category "device" -Data @{ - platform = $Platform - target = $Target - } - # Validate platform is supported if (-not [DeviceProviderFactory]::IsPlatformSupported($Platform)) { throw "Unsupported platform: $Platform. Supported platforms: $([DeviceProviderFactory]::GetSupportedPlatforms() -join ', ')" @@ -73,11 +68,6 @@ function Connect-Device { $resourceName = New-DeviceResourceName -Platform $Platform -Target $mutexTarget Write-Debug "Device resource name: $resourceName" - TrySentry\Add-SentryBreadcrumb -Message "Acquiring device lock" -Category "device" -Data @{ - resource_name = $resourceName - timeout_seconds = $TimeoutSeconds - } - # Acquire exclusive access to the device resource # Default 60-minute timeout with progress messages every minute $mutex = $null @@ -85,23 +75,10 @@ function Connect-Device { $mutex = Request-DeviceAccess -ResourceName $resourceName -TimeoutSeconds $TimeoutSeconds -ProgressIntervalSeconds 60 Write-Output "Acquired exclusive access to device: $resourceName" - TrySentry\Add-SentryBreadcrumb -Message "Device lock acquired" -Category "device" -Data @{ - resource_name = $resourceName - } - # Create provider for the specified platform - TrySentry\Add-SentryBreadcrumb -Message "Creating device provider" -Category "device" -Data @{ - platform = $Platform - } - $provider = [DeviceProviderFactory]::CreateProvider($Platform) # Connect using the provider - TrySentry\Add-SentryBreadcrumb -Message "Establishing device connection" -Category "device" -Data @{ - platform = $Platform - target = $Target - } - $sessionInfo = $provider.Connect($Target) # Store the provider instance and mutex with the session @@ -110,11 +87,6 @@ function Connect-Device { $script:CurrentSession.Mutex = $mutex $script:CurrentSession.ResourceName = $resourceName - TrySentry\Add-SentryBreadcrumb -Message "Device connection established" -Category "device" -Data @{ - platform = $Platform - device_id = $script:CurrentSession.Identifier - } - Write-Debug "Successfully connected to $Platform device (Device: $($script:CurrentSession.Identifier))" return $script:CurrentSession diff --git a/app-runner/Public/Invoke-DeviceApp.ps1 b/app-runner/Public/Invoke-DeviceApp.ps1 index 28723ba..23b568a 100644 --- a/app-runner/Public/Invoke-DeviceApp.ps1 +++ b/app-runner/Public/Invoke-DeviceApp.ps1 @@ -31,26 +31,9 @@ function Invoke-DeviceApp { Write-Debug "Running application: $ExecutablePath with arguments: $Arguments" Write-Debug "Target platform: $($script:CurrentSession.Platform)" - TrySentry\Add-SentryBreadcrumb -Message "Starting application deployment" -Category "app" -Data @{ - executable = (Split-Path -Leaf $ExecutablePath) - platform = $script:CurrentSession.Platform - has_arguments = ($Arguments.Length -gt 0) - } - # Use the provider to run the application $provider = $script:CurrentSession.Provider - - TrySentry\Add-SentryBreadcrumb -Message "Invoking application on device" -Category "app" -Data @{ - executable = (Split-Path -Leaf $ExecutablePath) - platform = $script:CurrentSession.Platform - } - $result = $provider.RunApplication($ExecutablePath, $Arguments) - TrySentry\Add-SentryBreadcrumb -Message "Application execution completed" -Category "app" -Data @{ - executable = (Split-Path -Leaf $ExecutablePath) - exit_code = $result.ExitCode - } - return $result } \ No newline at end of file diff --git a/utils/Integration.TestUtils.psm1 b/utils/Integration.TestUtils.psm1 index 69537df..6a1d719 100644 --- a/utils/Integration.TestUtils.psm1 +++ b/utils/Integration.TestUtils.psm1 @@ -56,15 +56,6 @@ function Get-EventIds { # Provide detailed error message if count doesn't match if ($eventCapturedLines.Count -ne $ExpectedCount) { - # Add breadcrumb for diagnostic purposes - if (Get-Command -Name TrySentry\Add-SentryBreadcrumb -ErrorAction SilentlyContinue) { - TrySentry\Add-SentryBreadcrumb -Message "EVENT_CAPTURED lines mismatch" -Category "test" -Level Error -Data @{ - expected_count = $ExpectedCount - found_count = $eventCapturedLines.Count - output_line_count = @($AppOutput).Count - } - } - $errorMsg = "Expected $ExpectedCount EVENT_CAPTURED line(s) but found $($eventCapturedLines.Count).`n" $errorMsg += "`nSearched for lines matching: 'EVENT_CAPTURED:'`n" @@ -130,22 +121,9 @@ function Get-SentryTestEvent { if ($EventId) { Write-Host "Fetching Sentry event by ID: $EventId" -ForegroundColor Yellow $progressActivity = "Waiting for Sentry event $EventId" - if (Get-Command -Name TrySentry\Add-SentryBreadcrumb -ErrorAction SilentlyContinue) { - TrySentry\Add-SentryBreadcrumb -Message "Starting Sentry event polling" -Category "test" -Data @{ - event_id = $EventId - timeout_seconds = $TimeoutSeconds - } - } } elseif ($TagName -and $TagValue) { Write-Host "Fetching Sentry event by tag: $TagName=$TagValue" -ForegroundColor Yellow $progressActivity = "Waiting for Sentry event with tag $TagName=$TagValue" - if (Get-Command -Name TrySentry\Add-SentryBreadcrumb -ErrorAction SilentlyContinue) { - TrySentry\Add-SentryBreadcrumb -Message "Starting Sentry event polling by tag" -Category "test" -Data @{ - tag_name = $TagName - tag_value = $TagValue - timeout_seconds = $TimeoutSeconds - } - } } else { throw 'Must specify either EventId or both TagName and TagValue' } @@ -201,17 +179,6 @@ function Get-SentryTestEvent { Write-Progress -Activity $progressActivity -Completed } - # Add breadcrumb for timeout - if (Get-Command -Name TrySentry\Add-SentryBreadcrumb -ErrorAction SilentlyContinue) { - TrySentry\Add-SentryBreadcrumb -Message "Sentry event polling timed out" -Category "test" -Level Error -Data @{ - event_id = $EventId - tag_name = $TagName - tag_value = $TagValue - timeout_seconds = $TimeoutSeconds - last_error = $lastError - } - } - if ($EventId) { throw "Event $EventId not found in Sentry within $TimeoutSeconds seconds: $lastError" } else { diff --git a/utils/TrySentry.psm1 b/utils/TrySentry.psm1 index 625c383..57ec403 100644 --- a/utils/TrySentry.psm1 +++ b/utils/TrySentry.psm1 @@ -25,9 +25,10 @@ function Ensure-SentryReady { [OutputType([bool])] param() - # Check if disabled via environment variable - if ([string]::IsNullOrEmpty($env:SENTRY_DSN) -and $env:SENTRY_DSN -ne $null) { - Write-Debug "Sentry disabled: SENTRY_DSN environment variable is explicitly set to empty" + # Check if explicitly disabled via environment variable (set to empty string) + # If not set at all, we'll use the default DSN + if ((Test-Path env:SENTRY_DSN) -and [string]::IsNullOrEmpty($env:SENTRY_DSN)) { + Write-Debug 'Sentry disabled: SENTRY_DSN environment variable is explicitly set to empty' return $false } @@ -43,10 +44,9 @@ function Ensure-SentryReady { try { $null = [Sentry.SentrySdk] $sentryTypeAvailable = $true - Write-Debug "Sentry SDK type already available" - } - catch { - Write-Debug "Sentry SDK type not available, attempting to load module" + Write-Debug 'Sentry SDK type already available' + } catch { + Write-Debug 'Sentry SDK type not available, attempting to load module' } # Try to import Sentry module if type not available @@ -54,10 +54,9 @@ function Ensure-SentryReady { try { Import-Module Sentry -ErrorAction Stop $null = [Sentry.SentrySdk] # Verify type is now available - Write-Debug "Sentry module imported successfully" + Write-Debug 'Sentry module imported successfully' $sentryTypeAvailable = $true - } - catch { + } catch { Write-Debug "Failed to import Sentry module: $_" $script:SentryAvailable = $false return $false @@ -66,7 +65,7 @@ function Ensure-SentryReady { # Check if already initialized if ([Sentry.SentrySdk]::IsEnabled) { - Write-Debug "Sentry SDK already initialized" + Write-Debug 'Sentry SDK already initialized' $script:SentryAvailable = $true return $true } @@ -76,27 +75,25 @@ function Ensure-SentryReady { $dsn = if ($env:SENTRY_DSN) { $env:SENTRY_DSN } else { $script:DefaultDsn } if ([string]::IsNullOrEmpty($dsn) -or $dsn -eq 'https://TODO@TODO.ingest.sentry.io/TODO') { - Write-Debug "Sentry DSN not configured, telemetry disabled" + Write-Debug 'Sentry DSN not configured, telemetry disabled' $script:SentryAvailable = $false return $false } Write-Debug "Initializing Sentry with DSN: $($dsn -replace '(?<=https://)([^@]+)(?=@)', '***')" - Start-Sentry -Dsn $dsn + Sentry\Start-Sentry -Dsn $dsn if ([Sentry.SentrySdk]::IsEnabled) { - Write-Debug "Sentry SDK initialized successfully" + Write-Debug 'Sentry SDK initialized successfully' $script:SentryAvailable = $true return $true - } - else { - Write-Debug "Sentry SDK initialization completed but IsEnabled is false" + } else { + Write-Debug 'Sentry SDK initialization completed but IsEnabled is false' $script:SentryAvailable = $false return $false } - } - catch { + } catch { Write-Debug "Failed to initialize Sentry SDK: $_" $script:SentryAvailable = $false return $false @@ -181,8 +178,7 @@ function Start-Sentry { Write-Debug "Sentry context initialized with module: $ModuleName, version: $ModuleVersion" return $true - } - catch { + } catch { Write-Debug "Failed to set Sentry context: $_" return $false } @@ -256,14 +252,12 @@ function Out-Sentry { # Send to Sentry based on input type if ($InputObject -is [System.Management.Automation.ErrorRecord]) { - $eventId = $InputObject | Out-Sentry @outSentryParams - } - elseif ($InputObject -is [System.Exception]) { - $eventId = Out-Sentry -Exception $InputObject @outSentryParams - } - else { + $eventId = $InputObject | Sentry\Out-Sentry @outSentryParams + } elseif ($InputObject -is [System.Exception]) { + $eventId = Sentry\Out-Sentry -Exception $InputObject @outSentryParams + } else { # Treat as message - $eventId = Out-Sentry -Message $InputObject.ToString() @outSentryParams + $eventId = Sentry\Out-Sentry -Message $InputObject.ToString() @outSentryParams } if ($eventId) { @@ -271,8 +265,7 @@ function Out-Sentry { } return $eventId - } - catch { + } catch { Write-Debug "Failed to send event to Sentry: $_" return $null } @@ -350,10 +343,9 @@ function Add-SentryBreadcrumb { $breadcrumbParams['Level'] = $Level } - Add-SentryBreadcrumb @breadcrumbParams + Sentry\Add-SentryBreadcrumb @breadcrumbParams Write-Debug "Breadcrumb added: $Message" - } - catch { + } catch { Write-Debug "Failed to add Sentry breadcrumb: $_" } } @@ -396,10 +388,9 @@ function Edit-SentryScope { } try { - Edit-SentryScope -ScopeSetup $ScopeSetup - Write-Debug "Sentry scope edited" - } - catch { + Sentry\Edit-SentryScope -ScopeSetup $ScopeSetup + Write-Debug 'Sentry scope edited' + } catch { Write-Debug "Failed to edit Sentry scope: $_" } } @@ -483,11 +474,10 @@ function Start-SentryTransaction { $transactionParams['CustomSamplingContext'] = $CustomSamplingContext } - $transaction = Start-SentryTransaction @transactionParams + $transaction = Sentry\Start-SentryTransaction @transactionParams Write-Debug "Sentry transaction started: $Name ($Operation)" return $transaction - } - catch { + } catch { Write-Debug "Failed to start Sentry transaction: $_" return $null } From b7ae9649bb9e16c59e09ce9f42641b2bd8c7e941 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 16:34:18 +0100 Subject: [PATCH 09/14] feat: bundle Sentry PowerShell module to eliminate external dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bundle sentry-powershell v0.4.0 directly in the repository at vendor/Sentry to provide out-of-the-box telemetry without requiring manual installation from PSGallery. This ensures consistent behavior across all environments (CI, dev, offline) and eliminates potential installation failures. Changes: - Add bundled Sentry module v0.4.0 from GitHub release to vendor/Sentry - Update TrySentry.psm1 to load bundled module instead of system-installed - Update README to reflect that Sentry is now bundled and ready to use - Remove PSGallery installation instructions The bundled module includes .NET assemblies for net462, net8.0, and net9.0 frameworks (~4.2MB total). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- README.md | 8 +- utils/TrySentry.psm1 | 18 +- vendor/Sentry/Sentry.psd1 | 85 +++++ vendor/Sentry/Sentry.psm1 | 13 + vendor/Sentry/assemblies-loader.ps1 | 24 ++ .../Microsoft.Bcl.AsyncInterfaces.license | 23 ++ .../Microsoft.Bcl.AsyncInterfaces.version | 1 + vendor/Sentry/lib/net462/Sentry.license | 1 + vendor/Sentry/lib/net462/Sentry.version | 1 + .../Sentry/lib/net462/System.Buffers.license | 23 ++ .../Sentry/lib/net462/System.Buffers.version | 1 + .../System.Collections.Immutable.license | 23 ++ .../System.Collections.Immutable.version | 1 + .../Sentry/lib/net462/System.Memory.license | 23 ++ .../Sentry/lib/net462/System.Memory.version | 1 + .../Sentry/lib/net462/System.Net.Http.license | 128 +++++++ .../Sentry/lib/net462/System.Net.Http.version | 1 + .../net462/System.Numerics.Vectors.license | 23 ++ .../net462/System.Numerics.Vectors.version | 1 + .../net462/System.Reflection.Metadata.license | 23 ++ .../net462/System.Reflection.Metadata.version | 1 + ....Runtime.CompilerServices.Unsafe.4.license | 23 ++ ....Runtime.CompilerServices.Unsafe.4.version | 1 + ....Runtime.CompilerServices.Unsafe.6.license | 23 ++ ....Runtime.CompilerServices.Unsafe.6.version | 1 + .../net462/System.Text.Encodings.Web.license | 23 ++ .../net462/System.Text.Encodings.Web.version | 1 + .../lib/net462/System.Text.Json.license | 23 ++ .../lib/net462/System.Text.Json.version | 1 + .../System.Threading.Tasks.Extensions.license | 23 ++ .../System.Threading.Tasks.Extensions.version | 1 + .../lib/net462/System.ValueTuple.license | 23 ++ .../lib/net462/System.ValueTuple.version | 1 + vendor/Sentry/lib/net8.0/Sentry.license | 1 + vendor/Sentry/lib/net8.0/Sentry.version | 1 + vendor/Sentry/lib/net9.0/Sentry.license | 1 + vendor/Sentry/lib/net9.0/Sentry.version | 1 + vendor/Sentry/private/DiagnosticLogger.ps1 | 55 +++ vendor/Sentry/private/EventUpdater.ps1 | 13 + vendor/Sentry/private/Get-CurrentOptions.ps1 | 10 + .../private/Get-SentryAssembliesDirectory.ps1 | 26 ++ vendor/Sentry/private/New-HttpTransport.ps1 | 16 + vendor/Sentry/private/ScopeIntegration.ps1 | 23 ++ vendor/Sentry/private/SentryEventProcessor.cs | 13 + .../Sentry/private/SentryEventProcessor.ps1 | 18 + vendor/Sentry/private/StackTraceProcessor.ps1 | 333 ++++++++++++++++++ .../Sentry/private/SynchronousTransport.ps1 | 79 +++++ vendor/Sentry/private/SynchronousWorker.ps1 | 35 ++ vendor/Sentry/public/Add-SentryBreadcrumb.ps1 | 22 ++ vendor/Sentry/public/Edit-SentryScope.ps1 | 14 + vendor/Sentry/public/Invoke-WithSentry.ps1 | 15 + vendor/Sentry/public/Out-Sentry.ps1 | 97 +++++ vendor/Sentry/public/Start-Sentry.ps1 | 73 ++++ .../Sentry/public/Start-SentryTransaction.ps1 | 57 +++ vendor/Sentry/public/Stop-Sentry.ps1 | 4 + 55 files changed, 1462 insertions(+), 12 deletions(-) create mode 100644 vendor/Sentry/Sentry.psd1 create mode 100644 vendor/Sentry/Sentry.psm1 create mode 100644 vendor/Sentry/assemblies-loader.ps1 create mode 100644 vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.license create mode 100644 vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.version create mode 100644 vendor/Sentry/lib/net462/Sentry.license create mode 100644 vendor/Sentry/lib/net462/Sentry.version create mode 100644 vendor/Sentry/lib/net462/System.Buffers.license create mode 100644 vendor/Sentry/lib/net462/System.Buffers.version create mode 100644 vendor/Sentry/lib/net462/System.Collections.Immutable.license create mode 100644 vendor/Sentry/lib/net462/System.Collections.Immutable.version create mode 100644 vendor/Sentry/lib/net462/System.Memory.license create mode 100644 vendor/Sentry/lib/net462/System.Memory.version create mode 100644 vendor/Sentry/lib/net462/System.Net.Http.license create mode 100644 vendor/Sentry/lib/net462/System.Net.Http.version create mode 100644 vendor/Sentry/lib/net462/System.Numerics.Vectors.license create mode 100644 vendor/Sentry/lib/net462/System.Numerics.Vectors.version create mode 100644 vendor/Sentry/lib/net462/System.Reflection.Metadata.license create mode 100644 vendor/Sentry/lib/net462/System.Reflection.Metadata.version create mode 100644 vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.license create mode 100644 vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.version create mode 100644 vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.license create mode 100644 vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.version create mode 100644 vendor/Sentry/lib/net462/System.Text.Encodings.Web.license create mode 100644 vendor/Sentry/lib/net462/System.Text.Encodings.Web.version create mode 100644 vendor/Sentry/lib/net462/System.Text.Json.license create mode 100644 vendor/Sentry/lib/net462/System.Text.Json.version create mode 100644 vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.license create mode 100644 vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.version create mode 100644 vendor/Sentry/lib/net462/System.ValueTuple.license create mode 100644 vendor/Sentry/lib/net462/System.ValueTuple.version create mode 100644 vendor/Sentry/lib/net8.0/Sentry.license create mode 100644 vendor/Sentry/lib/net8.0/Sentry.version create mode 100644 vendor/Sentry/lib/net9.0/Sentry.license create mode 100644 vendor/Sentry/lib/net9.0/Sentry.version create mode 100644 vendor/Sentry/private/DiagnosticLogger.ps1 create mode 100644 vendor/Sentry/private/EventUpdater.ps1 create mode 100644 vendor/Sentry/private/Get-CurrentOptions.ps1 create mode 100644 vendor/Sentry/private/Get-SentryAssembliesDirectory.ps1 create mode 100644 vendor/Sentry/private/New-HttpTransport.ps1 create mode 100644 vendor/Sentry/private/ScopeIntegration.ps1 create mode 100644 vendor/Sentry/private/SentryEventProcessor.cs create mode 100644 vendor/Sentry/private/SentryEventProcessor.ps1 create mode 100644 vendor/Sentry/private/StackTraceProcessor.ps1 create mode 100644 vendor/Sentry/private/SynchronousTransport.ps1 create mode 100644 vendor/Sentry/private/SynchronousWorker.ps1 create mode 100644 vendor/Sentry/public/Add-SentryBreadcrumb.ps1 create mode 100644 vendor/Sentry/public/Edit-SentryScope.ps1 create mode 100644 vendor/Sentry/public/Invoke-WithSentry.ps1 create mode 100644 vendor/Sentry/public/Out-Sentry.ps1 create mode 100644 vendor/Sentry/public/Start-Sentry.ps1 create mode 100644 vendor/Sentry/public/Start-SentryTransaction.ps1 create mode 100644 vendor/Sentry/public/Stop-Sentry.ps1 diff --git a/README.md b/README.md index f767f70..6b81887 100644 --- a/README.md +++ b/README.md @@ -54,13 +54,7 @@ See [Sentry DSN documentation](https://docs.sentry.io/product/sentry-basics/dsn- ### Dependencies -Telemetry requires the optional `Sentry` PowerShell module: - -```powershell -Install-Module -Name Sentry -Repository PSGallery -Force -``` - -If the module is not installed, telemetry is automatically disabled and all functionality works normally. The toolkit has no hard dependency on Sentry. +The `Sentry` PowerShell module (v0.4.0) is bundled in the `vendor/Sentry` directory, so no installation is required. Telemetry works out of the box. **Learn more:** [sentry-powershell on GitHub](https://github.com/getsentry/sentry-powershell) diff --git a/utils/TrySentry.psm1 b/utils/TrySentry.psm1 index 57ec403..49d5e9d 100644 --- a/utils/TrySentry.psm1 +++ b/utils/TrySentry.psm1 @@ -52,12 +52,20 @@ function Ensure-SentryReady { # Try to import Sentry module if type not available if (-not $sentryTypeAvailable) { try { - Import-Module Sentry -ErrorAction Stop - $null = [Sentry.SentrySdk] # Verify type is now available - Write-Debug 'Sentry module imported successfully' - $sentryTypeAvailable = $true + # Load bundled Sentry module from vendor directory + $bundledSentryPath = Join-Path $PSScriptRoot '..\vendor\Sentry\Sentry.psd1' + if (Test-Path $bundledSentryPath) { + Import-Module $bundledSentryPath -ErrorAction Stop + $null = [Sentry.SentrySdk] # Verify type is now available + Write-Debug 'Bundled Sentry module imported successfully' + $sentryTypeAvailable = $true + } else { + Write-Debug "Bundled Sentry module not found at: $bundledSentryPath" + $script:SentryAvailable = $false + return $false + } } catch { - Write-Debug "Failed to import Sentry module: $_" + Write-Debug "Failed to import bundled Sentry module: $_" $script:SentryAvailable = $false return $false } diff --git a/vendor/Sentry/Sentry.psd1 b/vendor/Sentry/Sentry.psd1 new file mode 100644 index 0000000..2e9abe4 --- /dev/null +++ b/vendor/Sentry/Sentry.psd1 @@ -0,0 +1,85 @@ +# https://learn.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest +@{ + # Script module or binary module file associated with this manifest. + RootModule = 'Sentry.psm1' + + # Version number of this module. + ModuleVersion = '0.4.0' + + # Supported PSEditions + CompatiblePSEditions = @('Desktop', 'Core') + + # ID used to uniquely identify this module + GUID = '4062b4a0-74d3-4aee-a3ec-9889342d4025' + + # Author of this module + Author = 'Sentry' + + # Company or vendor of this module + CompanyName = 'Sentry' + + # Copyright statement for this module + Copyright = '(c) Sentry. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'An error reporting module that sends reports to Sentry.io' + + # Minimum version of the PowerShell engine required by this module + PowerShellVersion = '5.1' + + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + ScriptsToProcess = @('assemblies-loader.ps1') + + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + FunctionsToExport = @( + 'Add-SentryBreadcrumb', + 'Edit-SentryScope', + 'Invoke-WithSentry', + 'Out-Sentry', + 'Start-Sentry', + 'Start-SentryTransaction', + 'Stop-Sentry' + ) + + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + CmdletsToExport = @() + + # Variables to export from this module + VariablesToExport = @() + + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + AliasesToExport = @() + + # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + PSData = @{ + # Tags applied to this module. These help with module discovery in online galleries. + Tags = @('Sentry', 'PSEdition_Core', 'PSEdition_Desktop', 'Windows', 'Linux', 'macOS') + + + # A URL to the license for this module. + LicenseUri = 'https://raw.githubusercontent.com/getsentry/sentry-powershell/main/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/getsentry/sentry-powershell' + + # A URL to an icon representing this module. + IconUri = 'https://raw.githubusercontent.com/getsentry/platformicons/4e407e832f1a2a95d77ca8ca0ea2a195a38eec24/svg/sentry.svg' + + # ReleaseNotes of this module + ReleaseNotes = 'https://raw.githubusercontent.com/getsentry/sentry-powershell/main/CHANGELOG.md' + + # Prerelease string of this module + Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + } # End of PSData hashtable + } # End of PrivateData hashtable + + # HelpInfo URI of this module + HelpInfoURI = 'https://docs.sentry.io/platforms/powershell' +} diff --git a/vendor/Sentry/Sentry.psm1 b/vendor/Sentry/Sentry.psm1 new file mode 100644 index 0000000..810abdd --- /dev/null +++ b/vendor/Sentry/Sentry.psm1 @@ -0,0 +1,13 @@ +$publicDir = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) 'public' +$privateDir = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) 'private' +$moduleInfo = Import-PowerShellDataFile (Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) 'Sentry.psd1') + +. "$privateDir/Get-SentryAssembliesDirectory.ps1" +$sentryDllPath = (Join-Path (Get-SentryAssembliesDirectory) 'Sentry.dll') + +Add-Type -TypeDefinition (Get-Content "$privateDir/SentryEventProcessor.cs" -Raw) -ReferencedAssemblies $sentryDllPath -Debug:$false +. "$privateDir/SentryEventProcessor.ps1" + +Get-ChildItem $publicDir -Filter '*.ps1' | ForEach-Object { + . $_.FullName +} diff --git a/vendor/Sentry/assemblies-loader.ps1 b/vendor/Sentry/assemblies-loader.ps1 new file mode 100644 index 0000000..e09d2d0 --- /dev/null +++ b/vendor/Sentry/assemblies-loader.ps1 @@ -0,0 +1,24 @@ +. (Join-Path (Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) 'private') 'Get-SentryAssembliesDirectory.ps1') + +$dir = Get-SentryAssembliesDirectory + +# Check if the assembly is already loaded. +$type = 'Sentry.SentrySdk' -as [type] +if ($type) { + $loadedAsssembly = $type.Assembly + $expectedAssembly = [Reflection.Assembly]::LoadFile((Join-Path $dir 'Sentry.dll')) + + 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 { + Write-Debug "Sentry assembly is already loaded and at the expected version ($($expectedAssembly.GetName().Version)" + } +} else { + Write-Debug "Loading assemblies from $($dir):" + Get-ChildItem -Path $dir -Filter '*.dll' | ForEach-Object { + Write-Debug "Loading assembly: $($_.Name)" + [Reflection.Assembly]::LoadFrom($_.FullName) | Write-Debug + } +} diff --git a/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.license b/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.version b/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.version new file mode 100644 index 0000000..8c26f0d --- /dev/null +++ b/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.version @@ -0,0 +1 @@ +6.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/Sentry.license b/vendor/Sentry/lib/net462/Sentry.license new file mode 100644 index 0000000..8ab70c0 --- /dev/null +++ b/vendor/Sentry/lib/net462/Sentry.license @@ -0,0 +1 @@ +MIT \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/Sentry.version b/vendor/Sentry/lib/net462/Sentry.version new file mode 100644 index 0000000..c21f961 --- /dev/null +++ b/vendor/Sentry/lib/net462/Sentry.version @@ -0,0 +1 @@ +5.16.1.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Buffers.license b/vendor/Sentry/lib/net462/System.Buffers.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Buffers.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Buffers.version b/vendor/Sentry/lib/net462/System.Buffers.version new file mode 100644 index 0000000..dd17671 --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Buffers.version @@ -0,0 +1 @@ +4.0.3.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Collections.Immutable.license b/vendor/Sentry/lib/net462/System.Collections.Immutable.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Collections.Immutable.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Collections.Immutable.version b/vendor/Sentry/lib/net462/System.Collections.Immutable.version new file mode 100644 index 0000000..47f017f --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Collections.Immutable.version @@ -0,0 +1 @@ +5.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Memory.license b/vendor/Sentry/lib/net462/System.Memory.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Memory.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Memory.version b/vendor/Sentry/lib/net462/System.Memory.version new file mode 100644 index 0000000..df80b37 --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Memory.version @@ -0,0 +1 @@ +4.0.1.1 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Net.Http.license b/vendor/Sentry/lib/net462/System.Net.Http.license new file mode 100644 index 0000000..92b6c44 --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Net.Http.license @@ -0,0 +1,128 @@ + +MICROSOFT SOFTWARE LICENSE TERMS + + +MICROSOFT .NET LIBRARY + +These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft + +· updates, + +· supplements, + +· Internet-based services, and + +· support services + +for this software, unless other terms accompany those items. If so, those terms apply. + +BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE. + + +IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE PERPETUAL RIGHTS BELOW. + +1. INSTALLATION AND USE RIGHTS. + +a. Installation and Use. You may install and use any number of copies of the software to design, develop and test your programs. + +b. Third Party Programs. The software may include third party programs that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party program are included for your information only. + +2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. + +a. DISTRIBUTABLE CODE. The software is comprised of Distributable Code. “Distributable Code” is code that you are permitted to distribute in programs you develop if you comply with the terms below. + +i. Right to Use and Distribute. + +· You may copy and distribute the object code form of the software. + +· Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs. + +ii. Distribution Requirements. For any Distributable Code you distribute, you must + +· add significant primary functionality to it in your programs; + +· require distributors and external end users to agree to terms that protect it at least as much as this agreement; + +· display your valid copyright notice on your programs; and + +· indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your programs. + +iii. Distribution Restrictions. You may not + +· alter any copyright, trademark or patent notice in the Distributable Code; + +· use Microsoft’s trademarks in your programs’ names or in a way that suggests your programs come from or are endorsed by Microsoft; + +· include Distributable Code in malicious, deceptive or unlawful programs; or + +· modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that + +· the code be disclosed or distributed in source code form; or + +· others have the right to modify it. + +3. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not + +· work around any technical limitations in the software; + +· reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation; + +· publish the software for others to copy; + +· rent, lease or lend the software; + +· transfer the software or this agreement to any third party; or + +· use the software for commercial software hosting services. + +4. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the software. + +5. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes. + +6. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see www.microsoft.com/exporting. + +7. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. + +8. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. + +9. APPLICABLE LAW. + +a. United States. If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort. + +b. Outside the United States. If you acquired the software in any other country, the laws of that country apply. + +10. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so. + +11. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS OR STATUTORY GUARANTEES UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + +FOR AUSTRALIA – YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS. + +12. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES. + +This limitation applies to + +· anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and + +· claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. + +It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages. + +Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French. + +Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français. + +EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues. + +LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. + +Cette limitation concerne : + +· tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et + +· les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur. + +Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre égard. + +EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas. + + diff --git a/vendor/Sentry/lib/net462/System.Net.Http.version b/vendor/Sentry/lib/net462/System.Net.Http.version new file mode 100644 index 0000000..47d6c59 --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Net.Http.version @@ -0,0 +1 @@ +4.1.1.3 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Numerics.Vectors.license b/vendor/Sentry/lib/net462/System.Numerics.Vectors.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Numerics.Vectors.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Numerics.Vectors.version b/vendor/Sentry/lib/net462/System.Numerics.Vectors.version new file mode 100644 index 0000000..fc931ed --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Numerics.Vectors.version @@ -0,0 +1 @@ +4.1.4.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Reflection.Metadata.license b/vendor/Sentry/lib/net462/System.Reflection.Metadata.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Reflection.Metadata.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Reflection.Metadata.version b/vendor/Sentry/lib/net462/System.Reflection.Metadata.version new file mode 100644 index 0000000..47f017f --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Reflection.Metadata.version @@ -0,0 +1 @@ +5.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.license b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.version b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.version new file mode 100644 index 0000000..23a3694 --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.version @@ -0,0 +1 @@ +4.0.4.1 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.license b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.version b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.version new file mode 100644 index 0000000..8c26f0d --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.version @@ -0,0 +1 @@ +6.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Text.Encodings.Web.license b/vendor/Sentry/lib/net462/System.Text.Encodings.Web.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Text.Encodings.Web.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Text.Encodings.Web.version b/vendor/Sentry/lib/net462/System.Text.Encodings.Web.version new file mode 100644 index 0000000..8c26f0d --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Text.Encodings.Web.version @@ -0,0 +1 @@ +6.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Text.Json.license b/vendor/Sentry/lib/net462/System.Text.Json.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Text.Json.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Text.Json.version b/vendor/Sentry/lib/net462/System.Text.Json.version new file mode 100644 index 0000000..e842b65 --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Text.Json.version @@ -0,0 +1 @@ +6.0.0.10 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.license b/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.version b/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.version new file mode 100644 index 0000000..137b831 --- /dev/null +++ b/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.version @@ -0,0 +1 @@ +4.2.0.1 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.ValueTuple.license b/vendor/Sentry/lib/net462/System.ValueTuple.license new file mode 100644 index 0000000..984713a --- /dev/null +++ b/vendor/Sentry/lib/net462/System.ValueTuple.license @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.ValueTuple.version b/vendor/Sentry/lib/net462/System.ValueTuple.version new file mode 100644 index 0000000..dd17671 --- /dev/null +++ b/vendor/Sentry/lib/net462/System.ValueTuple.version @@ -0,0 +1 @@ +4.0.3.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net8.0/Sentry.license b/vendor/Sentry/lib/net8.0/Sentry.license new file mode 100644 index 0000000..8ab70c0 --- /dev/null +++ b/vendor/Sentry/lib/net8.0/Sentry.license @@ -0,0 +1 @@ +MIT \ No newline at end of file diff --git a/vendor/Sentry/lib/net8.0/Sentry.version b/vendor/Sentry/lib/net8.0/Sentry.version new file mode 100644 index 0000000..c21f961 --- /dev/null +++ b/vendor/Sentry/lib/net8.0/Sentry.version @@ -0,0 +1 @@ +5.16.1.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net9.0/Sentry.license b/vendor/Sentry/lib/net9.0/Sentry.license new file mode 100644 index 0000000..8ab70c0 --- /dev/null +++ b/vendor/Sentry/lib/net9.0/Sentry.license @@ -0,0 +1 @@ +MIT \ No newline at end of file diff --git a/vendor/Sentry/lib/net9.0/Sentry.version b/vendor/Sentry/lib/net9.0/Sentry.version new file mode 100644 index 0000000..c21f961 --- /dev/null +++ b/vendor/Sentry/lib/net9.0/Sentry.version @@ -0,0 +1 @@ +5.16.1.0 \ No newline at end of file diff --git a/vendor/Sentry/private/DiagnosticLogger.ps1 b/vendor/Sentry/private/DiagnosticLogger.ps1 new file mode 100644 index 0000000..fbfc410 --- /dev/null +++ b/vendor/Sentry/private/DiagnosticLogger.ps1 @@ -0,0 +1,55 @@ +class DiagnosticLogger : Sentry.Extensibility.IDiagnosticLogger { + hidden [Sentry.SentryLevel] $minimalLevel + + DiagnosticLogger([Sentry.SentryLevel] $minimalLevel) { + $this.minimalLevel = $minimalLevel + } + + [bool] IsEnabled([Sentry.SentryLevel] $level) { + return $level -ge $this.minimalLevel + } + + 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) { + $message = $message -f $params + } + + # Note, linefeed and newline chars are removed to guard against log injection attacks. + $message = $message -replace '[\r\n]+', ' ' + + $message = "[Sentry] $message" + if ($null -ne $exception) { + $message += [Environment]::NewLine + $message += $exception | Out-String + } + + switch ($level) { + ([Sentry.SentryLevel]::Info) { + Write-Verbose $message + } + ([Sentry.SentryLevel]::Warning) { + Write-Warning $message + } + ([Sentry.SentryLevel]::Error) { + Write-Error $message + } + ([Sentry.SentryLevel]::Fatal) { + Write-Error $message + } + 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')) { + $DebugPreference = 'Continue' + } + } + + Write-Debug $message + } + } + } +} diff --git a/vendor/Sentry/private/EventUpdater.ps1 b/vendor/Sentry/private/EventUpdater.ps1 new file mode 100644 index 0000000..0c99fe7 --- /dev/null +++ b/vendor/Sentry/private/EventUpdater.ps1 @@ -0,0 +1,13 @@ +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) .*") { + $event_.Release = $null + } + + return $event_ + } +} diff --git a/vendor/Sentry/private/Get-CurrentOptions.ps1 b/vendor/Sentry/private/Get-CurrentOptions.ps1 new file mode 100644 index 0000000..5a0e87f --- /dev/null +++ b/vendor/Sentry/private/Get-CurrentOptions.ps1 @@ -0,0 +1,10 @@ +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) { + return $null + } + + [Sentry.SentryOptions] $options = $currentOptionsProperty.GetValue($null) + return $options +} diff --git a/vendor/Sentry/private/Get-SentryAssembliesDirectory.ps1 b/vendor/Sentry/private/Get-SentryAssembliesDirectory.ps1 new file mode 100644 index 0000000..e8fa049 --- /dev/null +++ b/vendor/Sentry/private/Get-SentryAssembliesDirectory.ps1 @@ -0,0 +1,26 @@ +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 + # PowerShell 7.3 - Built on .NET 7.0 + # PowerShell 7.2 (LTS) - Built on .NET 6.0 + # PowerShell 7.1 - Built on .NET 5.0 + # PowerShell 7.0 (LTS) - Built on .NET Core 3.1 + # 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') { + return 'net9.0' + } elseif ($PSVersionTable.PSVersion -ge '7.4') { + return 'net8.0' + } else { + return 'net462' + } +} + +function Get-SentryAssembliesDirectory { + $dir = Split-Path -Parent $PSScriptRoot + $dir = Join-Path $dir 'lib' + $dir = Join-Path $dir (GetTFM) + return $dir +} diff --git a/vendor/Sentry/private/New-HttpTransport.ps1 b/vendor/Sentry/private/New-HttpTransport.ps1 new file mode 100644 index 0000000..f3060c0 --- /dev/null +++ b/vendor/Sentry/private/New-HttpTransport.ps1 @@ -0,0 +1,16 @@ +# Wrapper to expose Sentry.Internal.SdkComposer::CreateHttpTransport() +function New-HttpTransport { + [OutputType([Sentry.Extensibility.ITransport])] + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [Sentry.SentryOptions] $options + ) + + $assembly = [Sentry.SentrySdk].Assembly + $type = $assembly.GetType('Sentry.Internal.SdkComposer') + $composer = [Activator]::CreateInstance($type, @($options)) + + $method = $type.GetMethod('CreateHttpTransport', [System.Reflection.BindingFlags]::Instance + [System.Reflection.BindingFlags]::NonPublic + [System.Reflection.BindingFlags]::Public) + return $method.Invoke($composer, @()) +} diff --git a/vendor/Sentry/private/ScopeIntegration.ps1 b/vendor/Sentry/private/ScopeIntegration.ps1 new file mode 100644 index 0000000..0275a44 --- /dev/null +++ b/vendor/Sentry/private/ScopeIntegration.ps1 @@ -0,0 +1,23 @@ +class ScopeIntegration : Sentry.Integrations.ISdkIntegration { + Register([Sentry.IHub] $hub, [Sentry.SentryOptions] $options) { + $hub.ConfigureScope([System.Action[Sentry.Scope]] { + param([Sentry.Scope]$scope) + + $scope.Sdk.Name = 'sentry.dotnet.powershell' + $scope.Sdk.Version = $moduleInfo.ModuleVersion + $scope.Sdk.AddPackage("ps:$($scope.Sdk.Name)", $scope.Sdk.Version) + + if ($PSVersionTable.PSEdition -eq 'Core') { + $scope.Contexts.Runtime.Name = 'PowerShell' + } else { + $scope.Contexts.Runtime.Name = 'Windows PowerShell' + } + $scope.Contexts.Runtime.Version = $PSVersionTable.PSVersion.ToString() + + $netRuntime = [Sentry.PlatformAbstractions.SentryRuntime]::Current + $scope.Contexts['runtime.net'] = [Sentry.Protocol.Runtime]::new() + $scope.Contexts['runtime.net'].Name = $netRuntime.Name + $scope.Contexts['runtime.net'].Version = $netRuntime.Version + }); + } +} diff --git a/vendor/Sentry/private/SentryEventProcessor.cs b/vendor/Sentry/private/SentryEventProcessor.cs new file mode 100644 index 0000000..de25a2f --- /dev/null +++ b/vendor/Sentry/private/SentryEventProcessor.cs @@ -0,0 +1,13 @@ +// This is an abstract class for any PowerShell event processors. It gets around an issue with Windows PowerShell +// failing to compile scripts that have a method name `Process`, which is a reserved word. +// https://stackoverflow.com/questions/78001695/windows-powershell-implement-c-sharp-interface-with-reserved-words-as-method-n/78001981 +// This way, we can keep the PowerShell implementation of the event processor, with access to System.Management.Automation, etc. +public abstract class SentryEventProcessor_ : Sentry.Extensibility.ISentryEventProcessor +{ + public Sentry.SentryEvent Process(Sentry.SentryEvent event_) + { + return Process_(event_); + } + + protected abstract Sentry.SentryEvent Process_(Sentry.SentryEvent event_); +} diff --git a/vendor/Sentry/private/SentryEventProcessor.ps1 b/vendor/Sentry/private/SentryEventProcessor.ps1 new file mode 100644 index 0000000..0c7b31d --- /dev/null +++ b/vendor/Sentry/private/SentryEventProcessor.ps1 @@ -0,0 +1,18 @@ +class SentryEventProcessor : SentryEventProcessor_ { + [Sentry.SentryEvent]DoProcess([Sentry.SentryEvent] $event_) { + throw [NotImplementedException]::new('You must override SentryEventProcessor::DoProcess()') + } + + [Sentry.SentryEvent]Process_([Sentry.SentryEvent] $event_) { + try { + return $this.DoProcess($event_) + } catch { + $ErrorRecord = $_ + "$($this.GetType()) failed to process event $($event_.EventId):" | Write-Warning + $ErrorRecord | Format-List * -Force | Out-String | Write-Warning + $ErrorRecord.InvocationInfo | Format-List * | Out-String | Write-Warning + $ErrorRecord.Exception | Format-List * -Force | Out-String | Write-Warning + return $event_ + } + } +} diff --git a/vendor/Sentry/private/StackTraceProcessor.ps1 b/vendor/Sentry/private/StackTraceProcessor.ps1 new file mode 100644 index 0000000..a89e6e7 --- /dev/null +++ b/vendor/Sentry/private/StackTraceProcessor.ps1 @@ -0,0 +1,333 @@ +class StackTraceProcessor : SentryEventProcessor { + [Sentry.Protocol.SentryException]$SentryException + [System.Management.Automation.InvocationInfo]$InvocationInfo + [System.Management.Automation.CallStackFrame[]]$StackTraceFrames + [string[]]$StackTraceString + hidden [Sentry.Extensibility.IDiagnosticLogger] $logger + hidden [string[]] $modulePaths + hidden [hashtable] $pwshModules = @{} + + 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(';')) { + # Windows + $this.modulePaths = $env:PSModulePath -split ';' + } else { + # Unix + $this.modulePaths = $env:PSModulePath -split ':' + } + } + + [Sentry.SentryEvent]DoProcess([Sentry.SentryEvent] $event_) { + if ($null -ne $this.SentryException) { + $this.ProcessException($event_) + } elseif ($null -ne $event_.Message) { + $this.ProcessMessage($event_) + } + + # Add modules present in PowerShell + 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) { + # .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=(?[^,]+), ') { + $event_.Modules[$Matches.Assembly] = $Matches.Version + } + } + } + + return $event_ + } + + hidden ProcessMessage([Sentry.SentryEvent] $event_) { + $this.PrependThread($event_, $this.GetStackTrace()) + } + + hidden ProcessException([Sentry.SentryEvent] $event_) { + $this.SentryException.Stacktrace = $this.GetStackTrace() + 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) { + $e.Mechanism = [Sentry.Protocol.Mechanism]::new() + } + $e.Mechanism.Synthetic = $true + $newExceptions.Add($e) + } + } + $newExceptions.Add($this.SentryException) + $event_.SentryExceptions = $newExceptions + $this.PrependThread($event_, $this.SentryException.Stacktrace) + } + + 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 + $thread.Name = 'PowerShell Script' + $thread.Crashed = $true + $thread.Current = $true + $thread.Stacktrace = $sentryStackTrace + $newThreads.Add($thread) + if ($null -ne $event_.SentryThreads) { + foreach ($t in $event_.SentryThreads) { + $t.Crashed = $false + $t.Current = $false + $newThreads.Add($t) + } + } + $event_.SentryThreads = $newThreads + } + + 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) { + $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) { + $sentryFrameInitial = $this.CreateFrame($this.InvocationInfo) + } else { + $sentryFrameInitial = $null + } + + 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) { + $sentryFrame.ContextLine = $sentryFrameInitial.ContextLine + $sentryFrame.ColumnNumber = $sentryFrameInitial.ColumnNumber + $sentryFrameInitial = $null + } + } + $sentryFrames.Add($sentryFrame) + } + + if ($null -ne $sentryFrameInitial) { + $sentryFrames.Insert(0, $sentryFrameInitial) + } + + $this.EnhanceTailFrames($sentryFrames) + } elseif ($null -ne $this.StackTraceFrames) { + $sentryFrames.Capacity = $this.StackTraceFrames.Count + 1 + foreach ($frame in $this.StackTraceFrames) { + $sentryFrames.Add($this.CreateFrame($frame)) + } + } + + foreach ($sentryFrame in $sentryFrames) { + # Update module info + $this.SetModule($sentryFrame) + $sentryFrame.InApp = [string]::IsNullOrEmpty($sentryFrame.Module) + $this.SetContextLines($sentryFrame) + } + + $sentryFrames.Reverse() + $stacktrace_ = [Sentry.SentryStackTrace]::new() + $stacktrace_.Frames = $sentryFrames + return $stacktrace_ + } + + hidden [Sentry.SentryStackFrame] CreateFrame([System.Management.Automation.InvocationInfo] $info) { + $sentryFrame = [Sentry.SentryStackFrame]::new() + $sentryFrame.AbsolutePath = $info.ScriptName + $sentryFrame.LineNumber = $info.ScriptLineNumber + $sentryFrame.ColumnNumber = $info.OffsetInLine + $sentryFrame.ContextLine = $info.Line.TrimEnd() + return $sentryFrame + } + + hidden [Sentry.SentryStackFrame] CreateFrame([System.Management.Automation.CallStackFrame] $frame) { + $sentryFrame = [Sentry.SentryStackFrame]::new() + $this.SetScriptInfo($sentryFrame, $frame) + $this.SetModule($sentryFrame) + $this.SetFunction($sentryFrame, $frame) + return $sentryFrame + } + + 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 '') { + $sentryFrame.AbsolutePath = $Matches.AbsolutePath + } + $sentryFrame.LineNumber = [int]$Matches.LineNumber + $sentryFrame.Function = $Matches.Function + } else { + Write-Warning "Failed to parse stack frame: $frame" + } + return $sentryFrame + } + + hidden EnhanceTailFrames([Sentry.SentryStackFrame[]] $sentryFrames) { + if ($null -eq $this.StackTraceFrames) { + return + } + + # The last frame is usually how the PowerShell was invoked. We need to get this info from $this.StackTraceFrames + # - for pwsh scriptname.ps1 it would be something like `. scriptname.ps1` + # - 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--) { + $sentryFrame = $sentryFrames[$j] + $frame = $this.StackTraceFrames | Select-Object -Last 1 -Skip $i + $i++ + + 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) { + $this.SetScriptInfo($sentryFrame, $frame) + $this.SetModule($sentryFrame) + $this.SetFunction($sentryFrame, $frame) + } + $this.SetContextLines($sentryFrame, $frame) + + # Try to match following frames that are part of the same codeblock. + while ($j -gt 0) { + $nextSentryFrame = $sentryFrames[$j - 1] + if ($nextSentryFrame.AbsolutePath -ne $sentryFrame.AbsolutePath) { + break + } + $this.SetContextLines($nextSentryFrame, $frame) + $j-- + } + } + } + } + + 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)) { + $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($_) }) { + $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])) { + $this.pwshModules[$parts[0]] = $parts[1] + } elseif ($this.pwshModules[$parts[0]] -ne $parts[1]) { + $this.pwshModules[$parts[0]] = $this.pwshModules[$parts[0]] + ", $($parts[1])" + } + } + } + } + } + + 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")) { + $lines = $sentryFrame.Function -split "[`r`n]+" + $sentryFrame.Function = $lines[0] + ' ' + if ($lines.Count -gt 2) { + $sentryFrame.Function += ' ...... ' + } + $sentryFrame.Function += $lines[$lines.Count - 1] + } + } else { + $sentryFrame.Function = $frame.FunctionName + } + } + + 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 { + Write-Warning "Failed to read context lines for frame with function '$($sentryFrame.Function)': $_" + if ($global:SentryPowershellRethrowErrors -eq $true) { + throw + } + } + } + } + + 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 { + $lines = Get-Content $sentryFrame.AbsolutePath -TotalCount ($sentryFrame.LineNumber + 5) + $this.SetContextLines($sentryFrame, $lines) + } catch { + Write-Warning "Failed to read context lines for $($sentryFrame.AbsolutePath): $_" + if ($global:SentryPowershellRethrowErrors -eq $true) { + throw + } + } + } + } + + hidden SetContextLines([Sentry.SentryStackFrame] $sentryFrame, [string[]] $lines) { + if ($lines.Count -lt $sentryFrame.LineNumber) { + if ($null -ne $this.logger) { + $this.logger.Log( + [Sentry.SentryLevel]::Debug, + "Couldn't set frame context because the line number ($($sentryFrame.LineNumber)) " + + "is lower than the available number of source code lines ($($lines.Count))." + ) + } + return + } + + $numContextLines = 5 + + 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) { + $lines = $lines | Select-Object -Skip ($sentryFrame.LineNumber - $numContextLines - 1) + } + + # Note: these are read-only in sentry-dotnet so we just update the underlying lists instead of replacing. + $sentryFrame.PreContext.Clear() + $lines | Select-Object -First $preContextCount | ForEach-Object { $sentryFrame.PreContext.Add($_) } + $sentryFrame.PostContext.Clear() + $lines | Select-Object -First $postContextCount -Skip ($preContextCount + 1) | ForEach-Object { $sentryFrame.PostContext.Add($_) } + } +} diff --git a/vendor/Sentry/private/SynchronousTransport.ps1 b/vendor/Sentry/private/SynchronousTransport.ps1 new file mode 100644 index 0000000..6dd027d --- /dev/null +++ b/vendor/Sentry/private/SynchronousTransport.ps1 @@ -0,0 +1,79 @@ +# 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 { + [Sentry.Extensibility.IDiagnosticLogger] $logger + # PowerShell 7.5.2+ changed how property assignment works in constructors when inheriting from .NET classes. + # Using a hashtable instead of individual [System.Reflection.MethodInfo] properties works around this issue. + # See: https://github.com/PowerShell/PowerShell/releases/tag/v7.5.2 + [hashtable] $reflectionMethods = @{} + + SynchronousTransport([Sentry.SentryOptions] $options) : base($options) { + $this.logger = $options.DiagnosticLogger + if ($null -eq $this.logger) { + $this.logger = Get-Variable -Scope script -Name SentryPowerShellDiagnosticLogger -ValueOnly -ErrorAction SilentlyContinue + } + + # These are internal methods, so we need to use reflection to access them. + $instanceMethod = [System.Reflection.BindingFlags]::Instance + [System.Reflection.BindingFlags]::NonPublic + [System.Reflection.BindingFlags]::Public; + $this.reflectionMethods['ProcessEnvelope'] = [Sentry.Http.HttpTransportBase].GetMethod('ProcessEnvelope', $instanceMethod) + if ($null -eq $this.reflectionMethods['ProcessEnvelope']) { + throw "Failed to find ProcessEnvelope method on Sentry.Http.HttpTransportBase" + } + + $this.reflectionMethods['CreateRequest'] = [Sentry.Http.HttpTransportBase].GetMethod('CreateRequest', $instanceMethod) + if ($null -eq $this.reflectionMethods['CreateRequest']) { + throw "Failed to find CreateRequest method on Sentry.Http.HttpTransportBase" + } + + $EnvelopeHttpContentType = [Sentry.SentrySdk].Assembly.GetType('Sentry.Internal.Http.EnvelopeHttpContent') + if ($null -eq $EnvelopeHttpContentType) { + throw "Failed to find Sentry.Internal.Http.EnvelopeHttpContent type" + } + + $this.reflectionMethods['SerializeToStream'] = $EnvelopeHttpContentType.GetMethod('SerializeToStream', $instanceMethod) + if ($null -eq $this.reflectionMethods['SerializeToStream']) { + throw "Failed to find SerializeToStream method on EnvelopeHttpContent" + } + } + + [System.Threading.Tasks.Task] SendEnvelopeAsync([Sentry.Protocol.Envelopes.Envelope] $envelope, [System.Threading.CancellationToken]$cancellationToken = [System.Threading.CancellationToken]::None) { + $processedEnvelope = $this.reflectionMethods['ProcessEnvelope'].Invoke($this, @($envelope)) + if ($processedEnvelope.Items.count -gt 0) { + $request = $this.reflectionMethods['CreateRequest'].Invoke($this, @($processedEnvelope)) + + $headers = @{} + foreach ($header in $request.Headers) { + $Key = $header.Key + $Value = $header.Value.Trim() -join ', ' + $headers[$Key] = $Value + } + + $memoryStream = [System.IO.MemoryStream]::new() + $this.reflectionMethods['SerializeToStream'].Invoke($request.Content, @($memoryStream, $null, $cancellationToken)) + $memoryStream.Position = 0 + + if ($null -ne $this.logger) { + $this.logger.Log([Sentry.SentryLevel]::Debug, 'Sending content synchronously, Content-Length: {0}', $null, $memoryStream.Length) + } + + $ProgressPreference = 'SilentlyContinue' + $psResponse = Invoke-WebRequest -Uri $request.RequestUri -Method $request.Method.Method -Headers $headers -Body $memoryStream -UseBasicParsing + + $response = [System.Net.Http.HttpResponseMessage]::new($psResponse.StatusCode) + $contentType = $psResponse.Headers['Content-Type'] + 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()) { + $response.Headers.TryAddWithoutValidation($header.Key, $header.Value) + } + + $this.HandleResponse($response, $processedEnvelope) + } + + return [System.Threading.Tasks.Task]::CompletedTask + } +} diff --git a/vendor/Sentry/private/SynchronousWorker.ps1 b/vendor/Sentry/private/SynchronousWorker.ps1 new file mode 100644 index 0000000..9a0a54f --- /dev/null +++ b/vendor/Sentry/private/SynchronousWorker.ps1 @@ -0,0 +1,35 @@ +. "$privateDir/New-HttpTransport.ps1" + +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) { + $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) { + $this.transport = New-HttpTransport($options) + } + } + + [bool] EnqueueEnvelope([Sentry.Protocol.Envelopes.Envelope] $envelope) { + $task = $this.transport.SendEnvelopeAsync($envelope, [System.Threading.CancellationToken]::None) + 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]::WhenAll($this.unfinishedTasks).Wait($timeout) + $this.unfinishedTasks.Clear() + return [System.Threading.Tasks.Task]::CompletedTask + } + + [int] get_QueuedItems() { + return $this.unfinishedTasks.Count + } +} diff --git a/vendor/Sentry/public/Add-SentryBreadcrumb.ps1 b/vendor/Sentry/public/Add-SentryBreadcrumb.ps1 new file mode 100644 index 0000000..9f5e608 --- /dev/null +++ b/vendor/Sentry/public/Add-SentryBreadcrumb.ps1 @@ -0,0 +1,22 @@ +function Add-SentryBreadcrumb { + param( + [Parameter(Mandatory, ValueFromPipeline = $true)] + [string] $Message, + + [string] $Category = $null, + [string] $Type = $null, + [hashtable] $Data = $null, + [Sentry.BreadcrumbLevel] $Level = [Sentry.BreadcrumbLevel]::Info) + + begin { + if ($null -eq $Data) { + $DataDict = $null + } else { + $DataDict = [System.Collections.Generic.Dictionary[string, string]]::new() + $Data.Keys | ForEach-Object { $DataDict.Add($_, $Data[$_]) } + } + } + process { + [Sentry.SentrySdk]::AddBreadcrumb($Message, $Category, $Type, $DataDict, $Level) + } +} diff --git a/vendor/Sentry/public/Edit-SentryScope.ps1 b/vendor/Sentry/public/Edit-SentryScope.ps1 new file mode 100644 index 0000000..b495821 --- /dev/null +++ b/vendor/Sentry/public/Edit-SentryScope.ps1 @@ -0,0 +1,14 @@ +function Edit-SentryScope { + param( + [Parameter(Mandatory)] + [scriptblock] $ScopeSetup + ) + + 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. + $scope | ForEach-Object $ScopeSetup + }) + } +} diff --git a/vendor/Sentry/public/Invoke-WithSentry.ps1 b/vendor/Sentry/public/Invoke-WithSentry.ps1 new file mode 100644 index 0000000..11915f2 --- /dev/null +++ b/vendor/Sentry/public/Invoke-WithSentry.ps1 @@ -0,0 +1,15 @@ +. "$publicDir/Out-Sentry.ps1" + +function Invoke-WithSentry { + param( + [scriptblock] + $ScriptBlock + ) + + try { + & $ScriptBlock + } catch { + $_ | Out-Sentry + throw + } +} diff --git a/vendor/Sentry/public/Out-Sentry.ps1 b/vendor/Sentry/public/Out-Sentry.ps1 new file mode 100644 index 0000000..4c6167f --- /dev/null +++ b/vendor/Sentry/public/Out-Sentry.ps1 @@ -0,0 +1,97 @@ +. "$privateDir/StackTraceProcessor.ps1" +. "$privateDir/Get-CurrentOptions.ps1" + +function Out-Sentry { + [OutputType([Sentry.SentryId])] + [CmdletBinding(DefaultParameterSetName = 'ErrorRecord')] + param( + [Parameter(ValueFromPipeline = $true, ParameterSetName = 'ErrorRecord')] + [System.Management.Automation.ErrorRecord] + $ErrorRecord, + + [Parameter(ValueFromPipeline = $true, ParameterSetName = 'Exception')] + [System.Exception] + $Exception, + + [Parameter(ValueFromPipeline = $true, ParameterSetName = 'Message')] + [string] + $Message, + + [Parameter(ParameterSetName = 'ErrorRecord')] + [Parameter(ParameterSetName = 'Exception')] + [Parameter(ParameterSetName = 'Message')] + [scriptblock] $EditScope + ) + + begin {} + 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.' + } catch {} + return + } + + $options = Get-CurrentOptions + [Sentry.SentryEvent]$event_ = $null + $processor = [StackTraceProcessor]::new($options) + + if ($ErrorRecord -ne $null) { + $event_ = [Sentry.SentryEvent]::new($ErrorRecord.Exception) + $processor.SentryException = [Sentry.Protocol.SentryException]::new() + + if ($($ErrorRecord.CategoryInfo.Activity) -eq 'Write-Error') { + # FullyQualifiedErrorId would be "Microsoft.PowerShell.Commands.WriteErrorException,funcB" + $processor.SentryException.Type = 'Write-Error' + } else { + $processor.SentryException.Type = $ErrorRecord.FullyQualifiedErrorId + } + + if (($details = $ErrorRecord.ErrorDetails) -and $null -ne $details.Message) { + $processor.SentryException.Value = $details.Message + } else { + $processor.SentryException.Value = $ErrorRecord.Exception.Message + } + + 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) { + $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) { + $event_ = [Sentry.SentryEvent]::new() + $event_.Message = $Message + $event_.Level = [Sentry.SentryLevel]::Info + } else { + Write-Warning 'Out-Sentry: No argument matched, nothing to do' + return + } + + if ($null -eq $event_) { + Write-Debug 'Out-Sentry: Nothing to capture' + return + } + + if ($options.AttachStackTrace -and $null -eq $processor.StackTraceFrames) { + $processor.StackTraceFrames = Get-PSCallStack | Select-Object -Skip 1 + } + + return [Sentry.SentrySdk]::CaptureEvent($event_, [System.Action[Sentry.Scope]] { + param([Sentry.Scope]$scope) + $scope.AddEventProcessor($processor) + + # Execute the script block in the caller's scope (nothing to do $scope) & set the automatic $_ variable to the $scope object. + $scope | ForEach-Object $EditScope + }) + } +} diff --git a/vendor/Sentry/public/Start-Sentry.ps1 b/vendor/Sentry/public/Start-Sentry.ps1 new file mode 100644 index 0000000..3b7476c --- /dev/null +++ b/vendor/Sentry/public/Start-Sentry.ps1 @@ -0,0 +1,73 @@ +. "$privateDir/DiagnosticLogger.ps1" +. "$privateDir/ScopeIntegration.ps1" +. "$privateDir/SynchronousWorker.ps1" +. "$privateDir/SynchronousTransport.ps1" +. "$privateDir/EventUpdater.ps1" + +function Start-Sentry { + [CmdletBinding(DefaultParameterSetName = 'Simple')] + param( + [Parameter(Mandatory, ParameterSetName = 'Simple', Position = 0)] + [Uri] $Dsn, + + [Parameter(Mandatory, ParameterSetName = 'Options', Position = 0)] + [scriptblock] $EditOptions + ) + + begin { + $options = [Sentry.SentryOptions]::new() + $options.FlushTimeout = [System.TimeSpan]::FromSeconds(10) + $options.ShutDownTimeout = $options.FlushTimeout + $options.ReportAssembliesMode = [Sentry.ReportAssembliesMode]::None + $options.IsGlobalModeEnabled = $true + $options.AddIntegration([ScopeIntegration]::new()) + $options.AddEventProcessor([EventUpdater]::new()) + + if ($DebugPreference -eq 'SilentlyContinue') { + $Options.Debug = $false + $options.DiagnosticLevel = [Sentry.SentryLevel]::Info + } else { + $Options.Debug = $true + $options.DiagnosticLevel = [Sentry.SentryLevel]::Debug + } + + if ($EditOptions -eq $null) { + $options.Dsn = $Dsn + } else { + # Execute the script block in the caller's scope & set the automatic $_ variable to the options object. + $options | ForEach-Object $EditOptions + } + + $logger = [DiagnosticLogger]::new($options.DiagnosticLevel) + + # Note: this is currently a no-op if options.debug == false; see https://github.com/getsentry/sentry-dotnet/issues/3212 + # As a workaround, we set the logger as a global variable so that we can reach it in other scripts. + $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 + } + } + } + + 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 + } + } + } + } + process { + [Sentry.SentrySdk]::init($options) | Out-Null + } +} diff --git a/vendor/Sentry/public/Start-SentryTransaction.ps1 b/vendor/Sentry/public/Start-SentryTransaction.ps1 new file mode 100644 index 0000000..6672d9f --- /dev/null +++ b/vendor/Sentry/public/Start-SentryTransaction.ps1 @@ -0,0 +1,57 @@ +function Start-SentryTransaction { + [OutputType([Sentry.ITransactionTracer])] + [CmdletBinding(DefaultParameterSetName = 'Basic')] + param( + [Parameter(Mandatory, ParameterSetName = 'Basic', Position = 0)] + [Parameter(Mandatory, ParameterSetName = 'BasicWithDescription', Position = 0)] + [string] $Name, + + [Parameter(Mandatory, ParameterSetName = 'Basic', Position = 1)] + [Parameter(Mandatory, ParameterSetName = 'BasicWithDescription', Position = 1)] + [string] $Operation, + + [Parameter(ParameterSetName = 'BasicWithDescription', Position = 2)] + [string] $Description = $null, + + [Parameter(Mandatory, ParameterSetName = 'TransactionContext', Position = 0)] + [Sentry.ITransactionContext] $TransactionContext, + + [Parameter(ParameterSetName = 'Basic', Position = 2)] + [Parameter(ParameterSetName = 'BasicWithDescription', Position = 3)] + [Parameter(ParameterSetName = 'TransactionContext', Position = 1)] + [hashtable] $CustomSamplingContext, + + [Parameter(ParameterSetName = 'Basic')] + [Parameter(ParameterSetName = 'BasicWithDescription')] + [Parameter(ParameterSetName = 'TransactionContext')] + [switch] $ForceSampled + ) + + begin { + if ($null -eq $TransactionContext) { + $IsSampled = $null + if ($ForceSampled) { + $IsSampled = $true + } + $TransactionContext = [Sentry.TransactionContext]::new($Name, $Operation, $null, $null, $null, $Description, $null, $IsSampled) + } + + } + process { + if ($CustomSamplingContext -eq $null) { + return [Sentry.SentrySdk]::StartTransaction($TransactionContext) + } else { + $samplingContext = HashTableToDictionary $CustomSamplingContext + return [Sentry.SentrySdk]::StartTransaction($TransactionContext, $samplingContext) + } + } +} + +# Converts [hashtable] to [System.Collections.generic.dictionary] +function HashTableToDictionary([hashtable] $hash) { + $dict = [System.Collections.Generic.Dictionary[string, object]]::new() + foreach ($key in $hash.Keys) { + $dict.Add($key, $hash[$key]) + } + return $dict +} diff --git a/vendor/Sentry/public/Stop-Sentry.ps1 b/vendor/Sentry/public/Stop-Sentry.ps1 new file mode 100644 index 0000000..cee7c66 --- /dev/null +++ b/vendor/Sentry/public/Stop-Sentry.ps1 @@ -0,0 +1,4 @@ +function Stop-Sentry { + [Sentry.SentrySdk]::Close() + Remove-Variable -Scope script -Name SentryPowerShellDiagnosticLogger -ErrorAction SilentlyContinue +} From 7422614de8cf249a5a7b60d9f76d0da89d0ee7fb Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 16:51:15 +0100 Subject: [PATCH 10/14] docs: add vendor README and remove Windows PowerShell assemblies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add documentation explaining why Sentry module is bundled and how to update it. Remove lib/net462 assemblies since this toolkit requires PowerShell Core 7+ (not Windows PowerShell 5.1). Changes: - Add vendor/README.md documenting bundling rationale and update process - Remove vendor/Sentry/lib/net462/ directory (~2.6MB of Windows PowerShell assemblies) - Document PowerShell Core 7+ requirement - Update size estimate to 1.6MB (down from 4.2MB) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- vendor/README.md | 63 +++++++++ .../Microsoft.Bcl.AsyncInterfaces.license | 23 ---- .../Microsoft.Bcl.AsyncInterfaces.version | 1 - vendor/Sentry/lib/net462/Sentry.license | 1 - vendor/Sentry/lib/net462/Sentry.version | 1 - .../Sentry/lib/net462/System.Buffers.license | 23 ---- .../Sentry/lib/net462/System.Buffers.version | 1 - .../System.Collections.Immutable.license | 23 ---- .../System.Collections.Immutable.version | 1 - .../Sentry/lib/net462/System.Memory.license | 23 ---- .../Sentry/lib/net462/System.Memory.version | 1 - .../Sentry/lib/net462/System.Net.Http.license | 128 ------------------ .../Sentry/lib/net462/System.Net.Http.version | 1 - .../net462/System.Numerics.Vectors.license | 23 ---- .../net462/System.Numerics.Vectors.version | 1 - .../net462/System.Reflection.Metadata.license | 23 ---- .../net462/System.Reflection.Metadata.version | 1 - ....Runtime.CompilerServices.Unsafe.4.license | 23 ---- ....Runtime.CompilerServices.Unsafe.4.version | 1 - ....Runtime.CompilerServices.Unsafe.6.license | 23 ---- ....Runtime.CompilerServices.Unsafe.6.version | 1 - .../net462/System.Text.Encodings.Web.license | 23 ---- .../net462/System.Text.Encodings.Web.version | 1 - .../lib/net462/System.Text.Json.license | 23 ---- .../lib/net462/System.Text.Json.version | 1 - .../System.Threading.Tasks.Extensions.license | 23 ---- .../System.Threading.Tasks.Extensions.version | 1 - .../lib/net462/System.ValueTuple.license | 23 ---- .../lib/net462/System.ValueTuple.version | 1 - 29 files changed, 63 insertions(+), 419 deletions(-) create mode 100644 vendor/README.md delete mode 100644 vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.license delete mode 100644 vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.version delete mode 100644 vendor/Sentry/lib/net462/Sentry.license delete mode 100644 vendor/Sentry/lib/net462/Sentry.version delete mode 100644 vendor/Sentry/lib/net462/System.Buffers.license delete mode 100644 vendor/Sentry/lib/net462/System.Buffers.version delete mode 100644 vendor/Sentry/lib/net462/System.Collections.Immutable.license delete mode 100644 vendor/Sentry/lib/net462/System.Collections.Immutable.version delete mode 100644 vendor/Sentry/lib/net462/System.Memory.license delete mode 100644 vendor/Sentry/lib/net462/System.Memory.version delete mode 100644 vendor/Sentry/lib/net462/System.Net.Http.license delete mode 100644 vendor/Sentry/lib/net462/System.Net.Http.version delete mode 100644 vendor/Sentry/lib/net462/System.Numerics.Vectors.license delete mode 100644 vendor/Sentry/lib/net462/System.Numerics.Vectors.version delete mode 100644 vendor/Sentry/lib/net462/System.Reflection.Metadata.license delete mode 100644 vendor/Sentry/lib/net462/System.Reflection.Metadata.version delete mode 100644 vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.license delete mode 100644 vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.version delete mode 100644 vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.license delete mode 100644 vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.version delete mode 100644 vendor/Sentry/lib/net462/System.Text.Encodings.Web.license delete mode 100644 vendor/Sentry/lib/net462/System.Text.Encodings.Web.version delete mode 100644 vendor/Sentry/lib/net462/System.Text.Json.license delete mode 100644 vendor/Sentry/lib/net462/System.Text.Json.version delete mode 100644 vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.license delete mode 100644 vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.version delete mode 100644 vendor/Sentry/lib/net462/System.ValueTuple.license delete mode 100644 vendor/Sentry/lib/net462/System.ValueTuple.version diff --git a/vendor/README.md b/vendor/README.md new file mode 100644 index 0000000..ce9b745 --- /dev/null +++ b/vendor/README.md @@ -0,0 +1,63 @@ +# Vendored Dependencies + +This directory contains third-party dependencies bundled directly in the repository. + +## Sentry PowerShell Module + +**Version**: 0.4.0 +**Source**: [getsentry/sentry-powershell](https://github.com/getsentry/sentry-powershell) +**Release**: [v0.4.0](https://github.com/getsentry/sentry-powershell/releases/tag/0.4.0) +**License**: MIT + +**Note**: The `lib/net462` directory has been removed from this bundle. This toolkit requires **PowerShell Core 7+** (not Windows PowerShell 5.1) for all functionality including telemetry. + +### Why Bundled? + +The Sentry PowerShell module is bundled rather than installed from PSGallery to ensure: + +1. **Reliability** - No dependency on PSGallery availability during CI runs or in isolated environments +2. **Consistency** - All developers and CI environments use the exact same version +3. **Offline Support** - Works in air-gapped or restricted network environments +4. **Performance** - No first-run installation delay or network overhead +5. **Simplicity** - Zero setup required for telemetry functionality + +Since this toolkit is internal Sentry testing infrastructure, bundling the module provides the best developer experience with guaranteed availability. + +### Updating the Module + +To update to a newer version: + +1. Download the `Sentry.zip` artifact from the [releases page](https://github.com/getsentry/sentry-powershell/releases) +2. Extract to a temporary location +3. Replace the contents of `vendor/Sentry/` with the new version +4. Update the version number in this README +5. Test that telemetry still works with the new version +6. Commit the changes + +```powershell +# Example update process +$version = "0.5.0" +curl -L -o Sentry.zip "https://github.com/getsentry/sentry-powershell/releases/download/$version/Sentry.zip" +Remove-Item -Recurse -Force vendor/Sentry +Expand-Archive -Path Sentry.zip -DestinationPath vendor/Sentry +Remove-Item Sentry.zip + +# Remove Windows PowerShell assemblies (not supported) +Remove-Item -Recurse -Force vendor/Sentry/lib/net462 +``` + +### Contents + +- `Sentry.psd1` - PowerShell module manifest +- `Sentry.psm1` - Main module file +- `assemblies-loader.ps1` - .NET assembly loader +- `lib/net8.0/` - .NET 8.0 assemblies (for PowerShell 7.4+) +- `lib/net9.0/` - .NET 9.0 assemblies (for future PowerShell versions) +- `public/` - Public cmdlets (Start-Sentry, Out-Sentry, Add-SentryBreadcrumb, etc.) +- `private/` - Internal implementation files + +**Note**: `lib/net462` (Windows PowerShell) has been removed as this toolkit requires PowerShell Core 7+. + +### Size + +Approximately 1.6 MB (PowerShell Core assemblies only; net462 removed) diff --git a/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.license b/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.version b/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.version deleted file mode 100644 index 8c26f0d..0000000 --- a/vendor/Sentry/lib/net462/Microsoft.Bcl.AsyncInterfaces.version +++ /dev/null @@ -1 +0,0 @@ -6.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/Sentry.license b/vendor/Sentry/lib/net462/Sentry.license deleted file mode 100644 index 8ab70c0..0000000 --- a/vendor/Sentry/lib/net462/Sentry.license +++ /dev/null @@ -1 +0,0 @@ -MIT \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/Sentry.version b/vendor/Sentry/lib/net462/Sentry.version deleted file mode 100644 index c21f961..0000000 --- a/vendor/Sentry/lib/net462/Sentry.version +++ /dev/null @@ -1 +0,0 @@ -5.16.1.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Buffers.license b/vendor/Sentry/lib/net462/System.Buffers.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Buffers.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Buffers.version b/vendor/Sentry/lib/net462/System.Buffers.version deleted file mode 100644 index dd17671..0000000 --- a/vendor/Sentry/lib/net462/System.Buffers.version +++ /dev/null @@ -1 +0,0 @@ -4.0.3.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Collections.Immutable.license b/vendor/Sentry/lib/net462/System.Collections.Immutable.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Collections.Immutable.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Collections.Immutable.version b/vendor/Sentry/lib/net462/System.Collections.Immutable.version deleted file mode 100644 index 47f017f..0000000 --- a/vendor/Sentry/lib/net462/System.Collections.Immutable.version +++ /dev/null @@ -1 +0,0 @@ -5.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Memory.license b/vendor/Sentry/lib/net462/System.Memory.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Memory.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Memory.version b/vendor/Sentry/lib/net462/System.Memory.version deleted file mode 100644 index df80b37..0000000 --- a/vendor/Sentry/lib/net462/System.Memory.version +++ /dev/null @@ -1 +0,0 @@ -4.0.1.1 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Net.Http.license b/vendor/Sentry/lib/net462/System.Net.Http.license deleted file mode 100644 index 92b6c44..0000000 --- a/vendor/Sentry/lib/net462/System.Net.Http.license +++ /dev/null @@ -1,128 +0,0 @@ - -MICROSOFT SOFTWARE LICENSE TERMS - - -MICROSOFT .NET LIBRARY - -These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft - -· updates, - -· supplements, - -· Internet-based services, and - -· support services - -for this software, unless other terms accompany those items. If so, those terms apply. - -BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE. - - -IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE PERPETUAL RIGHTS BELOW. - -1. INSTALLATION AND USE RIGHTS. - -a. Installation and Use. You may install and use any number of copies of the software to design, develop and test your programs. - -b. Third Party Programs. The software may include third party programs that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party program are included for your information only. - -2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. - -a. DISTRIBUTABLE CODE. The software is comprised of Distributable Code. “Distributable Code” is code that you are permitted to distribute in programs you develop if you comply with the terms below. - -i. Right to Use and Distribute. - -· You may copy and distribute the object code form of the software. - -· Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs. - -ii. Distribution Requirements. For any Distributable Code you distribute, you must - -· add significant primary functionality to it in your programs; - -· require distributors and external end users to agree to terms that protect it at least as much as this agreement; - -· display your valid copyright notice on your programs; and - -· indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your programs. - -iii. Distribution Restrictions. You may not - -· alter any copyright, trademark or patent notice in the Distributable Code; - -· use Microsoft’s trademarks in your programs’ names or in a way that suggests your programs come from or are endorsed by Microsoft; - -· include Distributable Code in malicious, deceptive or unlawful programs; or - -· modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that - -· the code be disclosed or distributed in source code form; or - -· others have the right to modify it. - -3. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not - -· work around any technical limitations in the software; - -· reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation; - -· publish the software for others to copy; - -· rent, lease or lend the software; - -· transfer the software or this agreement to any third party; or - -· use the software for commercial software hosting services. - -4. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the software. - -5. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes. - -6. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see www.microsoft.com/exporting. - -7. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. - -8. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. - -9. APPLICABLE LAW. - -a. United States. If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort. - -b. Outside the United States. If you acquired the software in any other country, the laws of that country apply. - -10. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so. - -11. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS OR STATUTORY GUARANTEES UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - -FOR AUSTRALIA – YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS. - -12. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES. - -This limitation applies to - -· anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and - -· claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. - -It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages. - -Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French. - -Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français. - -EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues. - -LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. - -Cette limitation concerne : - -· tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et - -· les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur. - -Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre égard. - -EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas. - - diff --git a/vendor/Sentry/lib/net462/System.Net.Http.version b/vendor/Sentry/lib/net462/System.Net.Http.version deleted file mode 100644 index 47d6c59..0000000 --- a/vendor/Sentry/lib/net462/System.Net.Http.version +++ /dev/null @@ -1 +0,0 @@ -4.1.1.3 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Numerics.Vectors.license b/vendor/Sentry/lib/net462/System.Numerics.Vectors.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Numerics.Vectors.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Numerics.Vectors.version b/vendor/Sentry/lib/net462/System.Numerics.Vectors.version deleted file mode 100644 index fc931ed..0000000 --- a/vendor/Sentry/lib/net462/System.Numerics.Vectors.version +++ /dev/null @@ -1 +0,0 @@ -4.1.4.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Reflection.Metadata.license b/vendor/Sentry/lib/net462/System.Reflection.Metadata.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Reflection.Metadata.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Reflection.Metadata.version b/vendor/Sentry/lib/net462/System.Reflection.Metadata.version deleted file mode 100644 index 47f017f..0000000 --- a/vendor/Sentry/lib/net462/System.Reflection.Metadata.version +++ /dev/null @@ -1 +0,0 @@ -5.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.license b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.version b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.version deleted file mode 100644 index 23a3694..0000000 --- a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.4.version +++ /dev/null @@ -1 +0,0 @@ -4.0.4.1 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.license b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.version b/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.version deleted file mode 100644 index 8c26f0d..0000000 --- a/vendor/Sentry/lib/net462/System.Runtime.CompilerServices.Unsafe.6.version +++ /dev/null @@ -1 +0,0 @@ -6.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Text.Encodings.Web.license b/vendor/Sentry/lib/net462/System.Text.Encodings.Web.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Text.Encodings.Web.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Text.Encodings.Web.version b/vendor/Sentry/lib/net462/System.Text.Encodings.Web.version deleted file mode 100644 index 8c26f0d..0000000 --- a/vendor/Sentry/lib/net462/System.Text.Encodings.Web.version +++ /dev/null @@ -1 +0,0 @@ -6.0.0.0 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Text.Json.license b/vendor/Sentry/lib/net462/System.Text.Json.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Text.Json.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Text.Json.version b/vendor/Sentry/lib/net462/System.Text.Json.version deleted file mode 100644 index e842b65..0000000 --- a/vendor/Sentry/lib/net462/System.Text.Json.version +++ /dev/null @@ -1 +0,0 @@ -6.0.0.10 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.license b/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.version b/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.version deleted file mode 100644 index 137b831..0000000 --- a/vendor/Sentry/lib/net462/System.Threading.Tasks.Extensions.version +++ /dev/null @@ -1 +0,0 @@ -4.2.0.1 \ No newline at end of file diff --git a/vendor/Sentry/lib/net462/System.ValueTuple.license b/vendor/Sentry/lib/net462/System.ValueTuple.license deleted file mode 100644 index 984713a..0000000 --- a/vendor/Sentry/lib/net462/System.ValueTuple.license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/Sentry/lib/net462/System.ValueTuple.version b/vendor/Sentry/lib/net462/System.ValueTuple.version deleted file mode 100644 index dd17671..0000000 --- a/vendor/Sentry/lib/net462/System.ValueTuple.version +++ /dev/null @@ -1 +0,0 @@ -4.0.3.0 \ No newline at end of file From 593b68a47df894a70271e3558254cdfa27df5e0b Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 21:38:16 +0100 Subject: [PATCH 11/14] refactor: simplify TrySentry import logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary conditional check when importing TrySentry module. Since TrySentry.psm1 is part of this repository (not an external dependency), we can import it directly. The try-catch handles any import failures, and TrySentry itself provides graceful degradation if the bundled Sentry module is unavailable. Changes: - Remove `if (Get-Module -Name TrySentry)` conditional check - Change ErrorAction from SilentlyContinue to Stop for clearer error handling - Update comment to remove "optional" - telemetry is always initialized - Update debug message from "skipped" to "failed" for accuracy 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app-runner/SentryAppRunner.psm1 | 15 ++++++--------- sentry-api-client/SentryApiClient.psm1 | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/app-runner/SentryAppRunner.psm1 b/app-runner/SentryAppRunner.psm1 index a2d8366..e0bade1 100644 --- a/app-runner/SentryAppRunner.psm1 +++ b/app-runner/SentryAppRunner.psm1 @@ -1,16 +1,13 @@ $ErrorActionPreference = 'Stop' $PSNativeCommandUseErrorActionPreference = $true -# Initialize Sentry telemetry (optional, graceful degradation if unavailable) +# Initialize Sentry telemetry try { - Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction SilentlyContinue - if (Get-Module -Name TrySentry) { - $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryAppRunner.psd1') - TrySentry\Start-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion $moduleManifest.ModuleVersion - } -} -catch { - Write-Debug "Sentry telemetry initialization skipped: $_" + Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction Stop + $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryAppRunner.psd1') + TrySentry\Start-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion $moduleManifest.ModuleVersion +} catch { + Write-Debug "Sentry telemetry initialization failed: $_" } # Import device providers in the correct order (base provider first, then implementations, then factory) diff --git a/sentry-api-client/SentryApiClient.psm1 b/sentry-api-client/SentryApiClient.psm1 index ba2bf88..3dc395d 100644 --- a/sentry-api-client/SentryApiClient.psm1 +++ b/sentry-api-client/SentryApiClient.psm1 @@ -1,13 +1,10 @@ -# Initialize Sentry telemetry (optional, graceful degradation if unavailable) +# Initialize Sentry telemetry try { - Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction SilentlyContinue - if (Get-Module -Name TrySentry) { - $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryApiClient.psd1') - TrySentry\Start-Sentry -ModuleName 'SentryApiClient' -ModuleVersion $moduleManifest.ModuleVersion - } -} -catch { - Write-Debug "Sentry telemetry initialization skipped: $_" + Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction Stop + $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryApiClient.psd1') + TrySentry\Start-Sentry -ModuleName 'SentryApiClient' -ModuleVersion $moduleManifest.ModuleVersion +} catch { + Write-Debug "Sentry telemetry initialization failed: $_" } $Script:SentryApiConfig = @{ From 03cba48e06d9c451973a21131bbda1e9de1112c0 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 6 Nov 2025 22:15:49 +0100 Subject: [PATCH 12/14] refactor: remove unused ErrorHandler class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove ErrorHandling.ps1 which defines an ErrorHandler class that is never used anywhere in the codebase. The file was being dot-sourced via wildcard import but no code calls [ErrorHandler]::LogError(). The codebase uses standard PowerShell error handling (throw/catch) throughout, making this abstraction unnecessary. If we need centralized error reporting to Sentry in the future, we can use PowerShell's built-in error stream hooks instead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app-runner/Private/ErrorHandling.ps1 | 170 --------------------------- 1 file changed, 170 deletions(-) delete mode 100644 app-runner/Private/ErrorHandling.ps1 diff --git a/app-runner/Private/ErrorHandling.ps1 b/app-runner/Private/ErrorHandling.ps1 deleted file mode 100644 index c139d20..0000000 --- a/app-runner/Private/ErrorHandling.ps1 +++ /dev/null @@ -1,170 +0,0 @@ -# Standardized Error Handling Framework -# Provides consistent error handling patterns across the module - -# Error Categories -enum ConsoleErrorCategory { - SessionManagement - PlatformConnection - ConsoleLifecycle - ApplicationManagement - Diagnostics - Configuration - NetworkTimeout - Authentication - Validation - Unknown -} - -# Custom Exception Classes -class ConsoleException : System.Exception { - [ConsoleErrorCategory]$Category - [string]$Platform - [string]$SessionId - [hashtable]$Context - - ConsoleException([string]$message) : base($message) { - $this.Category = [ConsoleErrorCategory]::Unknown - $this.Context = @{} - } - - ConsoleException([string]$message, [ConsoleErrorCategory]$category) : base($message) { - $this.Category = $category - $this.Context = @{} - } - - ConsoleException([string]$message, [ConsoleErrorCategory]$category, [Exception]$innerException) : base($message, $innerException) { - $this.Category = $category - $this.Context = @{} - } - - [string]GetDetailedMessage() { - $details = @() - $details += "Error: $($this.Message)" - $details += "Category: $($this.Category)" - - if ($this.Platform) { - $details += "Platform: $($this.Platform)" - } - - if ($this.SessionId) { - $details += "Session ID: $($this.SessionId)" - } - - if ($this.Context.Count -gt 0) { - $details += "Context:" - foreach ($key in $this.Context.Keys) { - $details += " ${key}: $($this.Context[$key])" - } - } - - if ($this.InnerException) { - $details += "Inner Exception: $($this.InnerException.Message)" - } - - return $details -join "`n" - } -} - -class SessionException : ConsoleException { - SessionException([string]$message) : base($message, [ConsoleErrorCategory]::SessionManagement) {} - SessionException([string]$message, [Exception]$innerException) : base($message, [ConsoleErrorCategory]::SessionManagement, $innerException) {} -} - -class PlatformException : ConsoleException { - PlatformException([string]$message, [string]$platform) : base($message, [ConsoleErrorCategory]::PlatformConnection) { - $this.Platform = $platform - } - PlatformException([string]$message, [string]$platform, [Exception]$innerException) : base($message, [ConsoleErrorCategory]::PlatformConnection, $innerException) { - $this.Platform = $platform - } -} - -class ConsoleLifecycleException : ConsoleException { - ConsoleLifecycleException([string]$message) : base($message, [ConsoleErrorCategory]::ConsoleLifecycle) {} - ConsoleLifecycleException([string]$message, [Exception]$innerException) : base($message, [ConsoleErrorCategory]::ConsoleLifecycle, $innerException) {} -} - -class ApplicationException : ConsoleException { - ApplicationException([string]$message) : base($message, [ConsoleErrorCategory]::ApplicationManagement) {} - ApplicationException([string]$message, [Exception]$innerException) : base($message, [ConsoleErrorCategory]::ApplicationManagement, $innerException) {} -} - -class ConfigurationException : ConsoleException { - ConfigurationException([string]$message) : base($message, [ConsoleErrorCategory]::Configuration) {} - ConfigurationException([string]$message, [Exception]$innerException) : base($message, [ConsoleErrorCategory]::Configuration, $innerException) {} -} - -# Error Handler Class -class ErrorHandler { - static [hashtable]$ErrorLog = @{} - static [int]$ErrorCount = 0 - - static [void]LogError([ConsoleException]$exception) { - $errorId = [Guid]::NewGuid().ToString() - $timestamp = Get-Date - - [ErrorHandler]::ErrorLog[$errorId] = @{ - Timestamp = $timestamp - Exception = $exception - Category = $exception.Category - Platform = $exception.Platform - ConsoleId = $exception.ConsoleId - Message = $exception.Message - InnerException = $exception.InnerException - Context = $exception.Context - StackTrace = $exception.StackTrace - } - - [ErrorHandler]::ErrorCount++ - - # Log to PowerShell error stream - Write-Error $exception.GetDetailedMessage() -ErrorId $errorId - - # Log to debug stream for troubleshooting - Write-Debug "Error logged with ID: $errorId" - - # Send to Sentry for operational visibility - if (Get-Command -Name TrySentry\Out-Sentry -ErrorAction SilentlyContinue) { - $sentryTags = @{ - error_id = $errorId - category = $exception.Category.ToString() - } - - if ($exception.Platform) { - $sentryTags['platform'] = $exception.Platform - } - - if ($exception.SessionId) { - $sentryTags['session_id'] = $exception.SessionId - } - - $message = $exception.GetDetailedMessage() - TrySentry\Out-Sentry -InputObject $message -Tag $sentryTags -Level Error - } - } - - static [void]LogError([string]$message, [ConsoleErrorCategory]$category) { - $exception = [ConsoleException]::new($message, $category) - [ErrorHandler]::LogError($exception) - } - - static [array]GetRecentErrors([int]$count = 10) { - $sortedErrors = [ErrorHandler]::ErrorLog.Values | Sort-Object Timestamp -Descending - return $sortedErrors | Select-Object -First $count - } - - static [array]GetErrorsByCategory([ConsoleErrorCategory]$category) { - return [ErrorHandler]::ErrorLog.Values | Where-Object { $_.Category -eq $category } - } - - static [void]ClearErrorLog() { - [ErrorHandler]::ErrorLog.Clear() - [ErrorHandler]::ErrorCount = 0 - } - - static [int]GetErrorCount() { - return [ErrorHandler]::ErrorCount - } -} - -# Essential Error Handling Functions \ No newline at end of file From 9a9848fa703f876f6075cb27a68c0caf22c39d47 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Fri, 7 Nov 2025 12:50:46 +0100 Subject: [PATCH 13/14] refactor: change debug messages to include type context and improve warning output for Sentry initialization --- app-runner/SentryAppRunner.psm1 | 2 +- utils/TrySentry.psm1 | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app-runner/SentryAppRunner.psm1 b/app-runner/SentryAppRunner.psm1 index e0bade1..318513c 100644 --- a/app-runner/SentryAppRunner.psm1 +++ b/app-runner/SentryAppRunner.psm1 @@ -7,7 +7,7 @@ try { $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryAppRunner.psd1') TrySentry\Start-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion $moduleManifest.ModuleVersion } catch { - Write-Debug "Sentry telemetry initialization failed: $_" + Write-Warning "Sentry telemetry initialization failed: $_" } # Import device providers in the correct order (base provider first, then implementations, then factory) diff --git a/utils/TrySentry.psm1 b/utils/TrySentry.psm1 index 49d5e9d..dcd0e50 100644 --- a/utils/TrySentry.psm1 +++ b/utils/TrySentry.psm1 @@ -44,9 +44,9 @@ function Ensure-SentryReady { try { $null = [Sentry.SentrySdk] $sentryTypeAvailable = $true - Write-Debug 'Sentry SDK type already available' + Write-Debug '[Sentry.SentrySdk] type already available' } catch { - Write-Debug 'Sentry SDK type not available, attempting to load module' + Write-Debug '[Sentry.SentrySdk] type not available, attempting to load module' } # Try to import Sentry module if type not available @@ -80,7 +80,7 @@ function Ensure-SentryReady { # Initialize Sentry SDK try { - $dsn = if ($env:SENTRY_DSN) { $env:SENTRY_DSN } else { $script:DefaultDsn } + $dsn = if ($env:F) { $env:SENTRY_DSN } else { $script:DefaultDsn } if ([string]::IsNullOrEmpty($dsn) -or $dsn -eq 'https://TODO@TODO.ingest.sentry.io/TODO') { Write-Debug 'Sentry DSN not configured, telemetry disabled' From 549ae7c7ee131357d80a79bf764573cb5e8ede6b Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Tue, 11 Nov 2025 13:58:07 +0100 Subject: [PATCH 14/14] refactor: change telemetry to opt-in with module-specific DSNs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove hardcoded default DSN from TrySentry.psm1 - Add -Dsn parameter to Start-Sentry function - Require explicit SENTRY_APP_RUNNER_DSN for app-runner module - Require explicit SENTRY_API_CLIENT_DSN for sentry-api-client module - Update README to reflect opt-in telemetry behavior - Change initialization failure from Write-Warning to Write-Debug Telemetry is now disabled by default and must be explicitly enabled by setting the appropriate environment variable for each module. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- README.md | 20 ++++++------ app-runner/SentryAppRunner.psm1 | 6 ++-- sentry-api-client/SentryApiClient.psm1 | 6 ++-- utils/TrySentry.psm1 | 42 +++++++++++++++----------- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 6b81887..ec47ee0 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Future support planned: ## Telemetry -This toolkit automatically collects operational telemetry using [Sentry](https://sentry.io) to improve reliability and diagnose issues. Telemetry helps identify test infrastructure failures, device connection problems, and automation bottlenecks. +This toolkit supports optional operational telemetry using [Sentry](https://sentry.io) to improve reliability and diagnose issues. When enabled, telemetry helps identify test infrastructure failures, device connection problems, and automation bottlenecks. ### What's Collected @@ -36,25 +36,25 @@ Examples of the types of telemetry data collected: ### Privacy & Control -**Telemetry is optional, enabled by default, and controllably by environment variable:** +**Telemetry is opt-in and requires explicit configuration:** -**To disable telemetry completely:** +Telemetry is disabled by default. To enable it, set one of the following environment variables with your Sentry DSN: + +**To enable telemetry for app-runner:** ```powershell -$env:SENTRY_DSN = $null # or empty string +$env:SENTRY_APP_RUNNER_DSN = 'https://your-key@o123.ingest.sentry.io/your-project' ``` -**To use your own Sentry project:** +**To enable telemetry for sentry-api-client:** ```powershell -$env:SENTRY_DSN = 'https://your-key@o123.ingest.sentry.io/your-project' +$env:SENTRY_API_CLIENT_DSN = 'https://your-key@o123.ingest.sentry.io/your-project' ``` -**Note:** DSNs are public client keys that are safe to expose in code or configuration. -They cannot be used to access your Sentry account or data. -See [Sentry DSN documentation](https://docs.sentry.io/product/sentry-basics/dsn-explainer/) for details. +**Note:** You can use the same DSN for both. ### Dependencies -The `Sentry` PowerShell module (v0.4.0) is bundled in the `vendor/Sentry` directory, so no installation is required. Telemetry works out of the box. +The `Sentry` PowerShell module (v0.4.0) is bundled in the `vendor/Sentry` directory, so no installation is required. Telemetry will work automatically when a DSN is configured via environment variable. **Learn more:** [sentry-powershell on GitHub](https://github.com/getsentry/sentry-powershell) diff --git a/app-runner/SentryAppRunner.psm1 b/app-runner/SentryAppRunner.psm1 index 318513c..9f6d86f 100644 --- a/app-runner/SentryAppRunner.psm1 +++ b/app-runner/SentryAppRunner.psm1 @@ -1,13 +1,13 @@ $ErrorActionPreference = 'Stop' $PSNativeCommandUseErrorActionPreference = $true -# Initialize Sentry telemetry +# Initialize Sentry telemetry (opt-in) try { Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction Stop $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryAppRunner.psd1') - TrySentry\Start-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion $moduleManifest.ModuleVersion + TrySentry\Start-Sentry -Dsn $env:SENTRY_APP_RUNNER_DSN -ModuleName 'SentryAppRunner' -ModuleVersion $moduleManifest.ModuleVersion } catch { - Write-Warning "Sentry telemetry initialization failed: $_" + Write-Debug "Sentry telemetry initialization failed: $_" } # Import device providers in the correct order (base provider first, then implementations, then factory) diff --git a/sentry-api-client/SentryApiClient.psm1 b/sentry-api-client/SentryApiClient.psm1 index 3dc395d..16c99f8 100644 --- a/sentry-api-client/SentryApiClient.psm1 +++ b/sentry-api-client/SentryApiClient.psm1 @@ -1,8 +1,8 @@ -# Initialize Sentry telemetry +# Initialize Sentry telemetry (opt-in) try { Import-Module (Join-Path $PSScriptRoot '..\utils\TrySentry.psm1') -ErrorAction Stop $moduleManifest = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'SentryApiClient.psd1') - TrySentry\Start-Sentry -ModuleName 'SentryApiClient' -ModuleVersion $moduleManifest.ModuleVersion + TrySentry\Start-Sentry -Dsn $env:SENTRY_API_CLIENT_DSN -ModuleName 'SentryApiClient' -ModuleVersion $moduleManifest.ModuleVersion } catch { Write-Debug "Sentry telemetry initialization failed: $_" } @@ -27,4 +27,4 @@ foreach ($Function in @($PublicFunctions + $PrivateFunctions)) { } } -Export-ModuleMember -Function $PublicFunctions.BaseName \ No newline at end of file +Export-ModuleMember -Function $PublicFunctions.BaseName diff --git a/utils/TrySentry.psm1 b/utils/TrySentry.psm1 index dcd0e50..fa8e311 100644 --- a/utils/TrySentry.psm1 +++ b/utils/TrySentry.psm1 @@ -1,13 +1,11 @@ # Sentry PowerShell SDK wrapper module # Provides graceful degradation when Sentry module is unavailable - -# Default DSN for app-runner telemetry -# Override with $env:SENTRY_DSN or disable with $env:SENTRY_DSN = $null -$script:DefaultDsn = 'https://8e7867b699467018c4f8a64a5a0b5b43@o447951.ingest.us.sentry.io/4510317734854656' +# Telemetry is opt-in and requires explicit DSN configuration # Track initialization state to avoid repeated attempts $script:InitializationAttempted = $false $script:SentryAvailable = $false +$script:ConfiguredDsn = $null <# .SYNOPSIS @@ -25,13 +23,6 @@ function Ensure-SentryReady { [OutputType([bool])] param() - # Check if explicitly disabled via environment variable (set to empty string) - # If not set at all, we'll use the default DSN - if ((Test-Path env:SENTRY_DSN) -and [string]::IsNullOrEmpty($env:SENTRY_DSN)) { - Write-Debug 'Sentry disabled: SENTRY_DSN environment variable is explicitly set to empty' - return $false - } - # Return cached result if we already attempted initialization if ($script:InitializationAttempted) { return $script:SentryAvailable @@ -80,9 +71,10 @@ function Ensure-SentryReady { # Initialize Sentry SDK try { - $dsn = if ($env:F) { $env:SENTRY_DSN } else { $script:DefaultDsn } + # Use configured DSN (must be explicitly set via Start-Sentry) + $dsn = $script:ConfiguredDsn - if ([string]::IsNullOrEmpty($dsn) -or $dsn -eq 'https://TODO@TODO.ingest.sentry.io/TODO') { + if ([string]::IsNullOrEmpty($dsn)) { Write-Debug 'Sentry DSN not configured, telemetry disabled' $script:SentryAvailable = $false return $false @@ -114,8 +106,10 @@ Optionally initialize Sentry with module context and tags. .DESCRIPTION Ensures Sentry is ready and sets contextual tags like module name, version, -PowerShell version, and OS. This is optional - Sentry will auto-initialize -on first use of any Try* function if not already started. +PowerShell version, and OS. Requires a DSN to be provided for telemetry to be enabled. + +.PARAMETER Dsn +The Sentry DSN (Data Source Name) for telemetry. If not provided, telemetry is disabled. .PARAMETER ModuleName Name of the module using Sentry (e.g., 'SentryAppRunner'). @@ -127,10 +121,10 @@ Version of the module. Additional custom tags to set on all events. .EXAMPLE -Start-Sentry -ModuleName 'SentryAppRunner' -ModuleVersion '1.0.0' +Start-Sentry -Dsn $env:SENTRY_APP_RUNNER_DSN -ModuleName 'SentryAppRunner' -ModuleVersion '1.0.0' .EXAMPLE -Start-Sentry -ModuleName 'MyModule' -ModuleVersion '2.1.0' -Tags @{ +Start-Sentry -Dsn $env:SENTRY_API_CLIENT_DSN -ModuleName 'MyModule' -ModuleVersion '2.1.0' -Tags @{ environment = 'ci' build_id = '12345' } @@ -142,6 +136,9 @@ function Start-Sentry { [CmdletBinding()] [OutputType([bool])] param( + [Parameter(Mandatory = $false)] + [string]$Dsn, + [Parameter(Mandatory = $false)] [string]$ModuleName, @@ -152,6 +149,17 @@ function Start-Sentry { [hashtable]$Tags = @{} ) + # If DSN is provided, configure it before initialization + if (-not [string]::IsNullOrEmpty($Dsn)) { + $script:ConfiguredDsn = $Dsn + } + + # Telemetry is opt-in - DSN must be explicitly provided + if ([string]::IsNullOrEmpty($script:ConfiguredDsn)) { + Write-Debug 'Sentry DSN not provided, telemetry disabled' + return $false + } + if (-not (Ensure-SentryReady)) { return $false }