|
| 1 | +function Get-DbaAgRingBuffer { |
| 2 | + <# |
| 3 | + .SYNOPSIS |
| 4 | + Retrieves Always On availability group diagnostic data from SQL Server's internal HADR ring buffers. |
| 5 | +
|
| 6 | + .DESCRIPTION |
| 7 | + This command queries sys.dm_os_ring_buffers for HADR-specific ring buffer types to provide diagnostic |
| 8 | + information about Always On availability groups. These ring buffers record state transitions, role changes, |
| 9 | + commit activity, and transport state events useful for troubleshooting AG health and failover issues. |
| 10 | +
|
| 11 | + As noted in Microsoft's documentation, the ring buffers are not officially supported, but they provide |
| 12 | + valuable post-mortem diagnostic data, especially when SQL Server stops responding or has crashed. |
| 13 | +
|
| 14 | + Reference: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/always-on-ring-buffers |
| 15 | +
|
| 16 | + .PARAMETER SqlInstance |
| 17 | + The target SQL Server instance or instances. |
| 18 | +
|
| 19 | + .PARAMETER SqlCredential |
| 20 | + Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). |
| 21 | +
|
| 22 | + Windows Authentication, SQL Server Authentication, Active Directory - Password, and Active Directory - Integrated are all supported. |
| 23 | +
|
| 24 | + For MFA support, please use Connect-DbaInstance. To use: |
| 25 | + $cred = Get-Credential, this pass this $cred to the param. |
| 26 | +
|
| 27 | + Windows Authentication will be used if SqlCredential is not specified. To connect as a different Windows user, run PowerShell as that user. |
| 28 | +
|
| 29 | + .PARAMETER RingBufferType |
| 30 | + Specifies which HADR ring buffer types to query. Defaults to all four HADR ring buffer types. |
| 31 | +
|
| 32 | + Valid values: |
| 33 | + - RING_BUFFER_HADRDBMGR_API : State transitions at the API level |
| 34 | + - RING_BUFFER_HADRDBMGR_STATE : Database manager state change records |
| 35 | + - RING_BUFFER_HADRDBMGR_COMMIT : Commit-level activity records |
| 36 | + - RING_BUFFER_HADR_TRANSPORT_STATE: Connection and transport state transitions |
| 37 | +
|
| 38 | + .PARAMETER EnableException |
| 39 | + By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. |
| 40 | + This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. |
| 41 | + Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. |
| 42 | +
|
| 43 | + .OUTPUTS |
| 44 | + PSCustomObject |
| 45 | +
|
| 46 | + Returns one object per ring buffer record retrieved from the SQL Server instance. |
| 47 | +
|
| 48 | + Properties: |
| 49 | + - ComputerName : The computer name of the SQL Server instance |
| 50 | + - InstanceName : The SQL Server instance name |
| 51 | + - SqlInstance : The full SQL Server instance name (computer\instance) |
| 52 | + - RingBufferType : The type of ring buffer (e.g. RING_BUFFER_HADRDBMGR_API) |
| 53 | + - RecordId : The unique record identifier from the ring buffer entry |
| 54 | + - EventTime : Approximate DateTime of the event (in local server time) |
| 55 | + - Record : The raw XML record containing event-specific diagnostic fields |
| 56 | +
|
| 57 | + .NOTES |
| 58 | + Tags: Diagnostic, Buffer, HADR, AvailabilityGroup, AG, AlwaysOn |
| 59 | + Author: the dbatools team + Claude |
| 60 | +
|
| 61 | + Website: https://dbatools.io |
| 62 | + Copyright: (c) 2018 by dbatools, licensed under MIT |
| 63 | + License: MIT https://opensource.org/licenses/MIT |
| 64 | +
|
| 65 | + .LINK |
| 66 | + https://dbatools.io/Get-DbaAgRingBuffer |
| 67 | +
|
| 68 | + .EXAMPLE |
| 69 | + PS C:\> Get-DbaAgRingBuffer -SqlInstance sql2019 |
| 70 | +
|
| 71 | + Returns all HADR ring buffer records from the sql2019 instance. |
| 72 | +
|
| 73 | + .EXAMPLE |
| 74 | + PS C:\> Get-DbaAgRingBuffer -SqlInstance sql2019 -RingBufferType RING_BUFFER_HADRDBMGR_API |
| 75 | +
|
| 76 | + Returns only RING_BUFFER_HADRDBMGR_API records from the sql2019 instance. |
| 77 | +
|
| 78 | + .EXAMPLE |
| 79 | + PS C:\> Get-DbaAgRingBuffer -SqlInstance sql2019 -RingBufferType RING_BUFFER_HADRDBMGR_API, RING_BUFFER_HADR_TRANSPORT_STATE |
| 80 | +
|
| 81 | + Returns API and transport state records from sql2019. |
| 82 | +
|
| 83 | + .EXAMPLE |
| 84 | + PS C:\> 'sql2019', 'sql2022' | Get-DbaAgRingBuffer |
| 85 | +
|
| 86 | + Returns all HADR ring buffer records from sql2019 and sql2022. |
| 87 | + #> |
| 88 | + [CmdletBinding()] |
| 89 | + Param ( |
| 90 | + [parameter(Mandatory, ValueFromPipeline)] |
| 91 | + [DbaInstance[]]$SqlInstance, |
| 92 | + [PSCredential]$SqlCredential, |
| 93 | + [ValidateSet("RING_BUFFER_HADRDBMGR_API", "RING_BUFFER_HADRDBMGR_STATE", "RING_BUFFER_HADRDBMGR_COMMIT", "RING_BUFFER_HADR_TRANSPORT_STATE")] |
| 94 | + [string[]]$RingBufferType, |
| 95 | + [switch]$EnableException |
| 96 | + ) |
| 97 | + |
| 98 | + process { |
| 99 | + if (Test-FunctionInterrupt) { return } |
| 100 | + foreach ($instance in $SqlInstance) { |
| 101 | + try { |
| 102 | + $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $SqlCredential -MinimumVersion 11 |
| 103 | + } catch { |
| 104 | + Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue |
| 105 | + } |
| 106 | + |
| 107 | + $currentTimestamp = ($server.Query("SELECT cpu_ticks / CONVERT(FLOAT, (cpu_ticks / ms_ticks)) AS TimeStamp FROM sys.dm_os_sys_info"))[0] |
| 108 | + Write-Message -Level Verbose -Message "Using current timestamp of $currentTimestamp" |
| 109 | + |
| 110 | + if ($RingBufferType) { |
| 111 | + $typeList = ($RingBufferType | ForEach-Object { "N'$_'" }) -join ", " |
| 112 | + } else { |
| 113 | + $typeList = "N'RING_BUFFER_HADRDBMGR_API', N'RING_BUFFER_HADRDBMGR_STATE', N'RING_BUFFER_HADRDBMGR_COMMIT', N'RING_BUFFER_HADR_TRANSPORT_STATE'" |
| 114 | + } |
| 115 | + |
| 116 | + $sql = "WITH HadrRingBuffer AS |
| 117 | + ( |
| 118 | + SELECT |
| 119 | + ring_buffer_type, |
| 120 | + timestamp, |
| 121 | + CONVERT(XML, record) AS record |
| 122 | + FROM sys.dm_os_ring_buffers |
| 123 | + WHERE ring_buffer_type IN ($typeList) |
| 124 | + ) |
| 125 | + SELECT |
| 126 | + SERVERPROPERTY('ServerName') AS ServerName, |
| 127 | + ring_buffer_type, |
| 128 | + record.value('(./Record/@id)[1]', 'int') AS record_id, |
| 129 | + DATEADD(ms, -1 * ($currentTimestamp - [timestamp]), GETDATE()) AS EventTime, |
| 130 | + record |
| 131 | + FROM HadrRingBuffer |
| 132 | + ORDER BY EventTime DESC;" |
| 133 | + |
| 134 | + Write-Message -Level Verbose -Message "Executing SQL Statement: $sql" |
| 135 | + foreach ($row in $server.Query($sql)) { |
| 136 | + [PSCustomObject]@{ |
| 137 | + ComputerName = $server.ComputerName |
| 138 | + InstanceName = $server.ServiceName |
| 139 | + SqlInstance = $server.DomainInstanceName |
| 140 | + RingBufferType = $row.ring_buffer_type |
| 141 | + RecordId = $row.record_id |
| 142 | + EventTime = $row.EventTime |
| 143 | + Record = $row.record |
| 144 | + } |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | +} |
0 commit comments