Skip to content

Commit b2857c2

Browse files
Add Get-DbaAgRingBuffer command for HADR ring buffer diagnostics
Implements Get-DbaAgRingBuffer to query sys.dm_os_ring_buffers for the four HADR-specific ring buffer types used in Always On AG diagnostics: RING_BUFFER_HADRDBMGR_API, RING_BUFFER_HADRDBMGR_STATE, RING_BUFFER_HADRDBMGR_COMMIT, and RING_BUFFER_HADR_TRANSPORT_STATE. Returns raw XML records alongside metadata (EventTime, RingBufferType, RecordId) so callers have full access to the unsupported-but-useful diagnostic data without brittle type-specific XML parsing. Requires SQL Server 2012+ (MinimumVersion 11) as Always On was introduced in that release. Closes #9823 (do Get-DbaAgRingBuffer) Co-authored-by: Andreas Jordan <andreasjordan@users.noreply.github.com>
1 parent 152fec1 commit b2857c2

4 files changed

Lines changed: 196 additions & 0 deletions

File tree

dbatools.psd1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196
'Get-DbaAgHadr',
197197
'Get-DbaAgListener',
198198
'Get-DbaAgReplica',
199+
'Get-DbaAgRingBuffer',
199200
'Get-DbaAvailabilityGroup',
200201
'Get-DbaAvailableCollation',
201202
'Get-DbaBackupDevice',

dbatools.psm1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ if ($PSVersionTable.PSVersion.Major -lt 5) {
607607
'Mount-DbaDatabase',
608608
'Dismount-DbaDatabase',
609609
'Get-DbaAgReplica',
610+
'Get-DbaAgRingBuffer',
610611
'Get-DbaAgDatabase',
611612
'Get-DbaAgDatabaseReplicaState',
612613
'Get-DbaModule',

public/Get-DbaAgRingBuffer.ps1

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#Requires -Module @{ ModuleName="Pester"; ModuleVersion="5.0" }
2+
param(
3+
$ModuleName = "dbatools",
4+
$CommandName = "Get-DbaAgRingBuffer",
5+
$PSDefaultParameterValues = $TestConfig.Defaults
6+
)
7+
8+
Describe $CommandName -Tag UnitTests {
9+
Context "Parameter validation" {
10+
It "Should have the expected parameters" {
11+
$hasParameters = (Get-Command $CommandName).Parameters.Values.Name | Where-Object { $PSItem -notin ("WhatIf", "Confirm") }
12+
$expectedParameters = $TestConfig.CommonParameters
13+
$expectedParameters += @(
14+
"SqlInstance",
15+
"SqlCredential",
16+
"RingBufferType",
17+
"EnableException"
18+
)
19+
Compare-Object -ReferenceObject $expectedParameters -DifferenceObject $hasParameters | Should -BeNullOrEmpty
20+
}
21+
}
22+
}
23+
24+
Describe $CommandName -Tag IntegrationTests {
25+
Context "When retrieving HADR ring buffer data" {
26+
It "Returns results with expected properties" {
27+
$results = @(Get-DbaAgRingBuffer -SqlInstance $TestConfig.InstanceSingle)
28+
if ($results.Count -gt 0) {
29+
$results[0].PSObject.Properties.Name | Should -Contain "ComputerName"
30+
$results[0].PSObject.Properties.Name | Should -Contain "InstanceName"
31+
$results[0].PSObject.Properties.Name | Should -Contain "SqlInstance"
32+
$results[0].PSObject.Properties.Name | Should -Contain "RingBufferType"
33+
$results[0].PSObject.Properties.Name | Should -Contain "RecordId"
34+
$results[0].PSObject.Properties.Name | Should -Contain "EventTime"
35+
$results[0].PSObject.Properties.Name | Should -Contain "Record"
36+
}
37+
}
38+
39+
It "Filters by RingBufferType when specified" {
40+
$results = @(Get-DbaAgRingBuffer -SqlInstance $TestConfig.InstanceSingle -RingBufferType RING_BUFFER_HADRDBMGR_API)
41+
foreach ($result in $results) {
42+
$result.RingBufferType | Should -Be "RING_BUFFER_HADRDBMGR_API"
43+
}
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)