diff --git a/sp_HealthParser/sp_HealthParser.sql b/sp_HealthParser/sp_HealthParser.sql index 57875a7..459c4a4 100644 --- a/sp_HealthParser/sp_HealthParser.sql +++ b/sp_HealthParser/sp_HealthParser.sql @@ -44,7 +44,7 @@ ALTER PROCEDURE @what_to_check varchar(10) = 'all', /*Specify which portion of the data to check*/ @start_date datetimeoffset(7) = NULL, /*Begin date for events*/ @end_date datetimeoffset(7) = NULL, /*End date for events*/ - @warnings_only bit = NULL, /*Only show results from recorded warnings*/ + @warnings_only bit = 0, /*Only show results from recorded warnings*/ @database_name sysname = NULL, /*Filter to a specific database for blocking)*/ @wait_duration_ms bigint = 0, /*Minimum duration to show query waits*/ @wait_round_interval_minutes bigint = 60, /*Nearest interval to round wait stats to*/ @@ -283,8 +283,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @end_date ) END, - @wait_duration_ms = /*convert to microseconds*/ - @wait_duration_ms * 1000, @wait_round_interval_minutes = /*do this i guess?*/ CASE WHEN @wait_round_interval_minutes < 1 @@ -771,7 +769,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ) AS x CROSS APPLY x.x.nodes('//event') AS e(x) WHERE 1 = 1 - AND e.x.exist('@timestamp[. >= sql:variable("@start_date") and .< sql:variable("@end_date")]') = 1 + AND e.x.exist('@timestamp[.>= sql:variable("@start_date") and .< sql:variable("@end_date")]') = 1 AND e.x.exist('@name[.= "security_error_ring_buffer_recorded"]') = 0 AND e.x.exist('@name[.= "error_reported"]') = 0 AND e.x.exist('@name[.= "memory_broker_ring_buffer_recorded"]') = 0 @@ -888,18 +886,18 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. w.x.value('@timestamp', 'datetime2') ), wait_type = w.x.value('(data[@name="wait_type"]/text/text())[1]', 'nvarchar(60)'), - duration_ms = CONVERT(decimal(38, 2), w.x.value('(data[@name="duration"]/value/text())[1]', 'bigint') / 1000.), - signal_duration_ms = CONVERT(decimal(38, 2), w.x.value('(data[@name="signal_duration"]/value/text())[1]', 'bigint') / 1000.), + duration_ms = CONVERT(bigint, w.x.value('(data[@name="duration"]/value/text())[1]', 'bigint')), + signal_duration_ms = CONVERT(bigint, w.x.value('(data[@name="signal_duration"]/value/text())[1]', 'bigint')), wait_resource = w.x.value('(data[@name="wait_resource"]/value/text())[1]', 'nvarchar(256)'), sql_text_pre = w.x.value('(action[@name="sql_text"]/value/text())[1]', 'nvarchar(max)'), - session_id = w.x.value('(action[@name="session_id"]/value/text())[1]', 'bigint'), + session_id = w.x.value('(action[@name="session_id"]/value/text())[1]', 'integer'), xml = w.x.query('.') INTO #waits_queries FROM #wait_info AS wi CROSS APPLY wi.wait_info.nodes('//event') AS w(x) - WHERE w.x.exist('(action[@name="session_id"]/value/text())[.=0]') = 0 + WHERE w.x.exist('(action[@name="session_id"]/value/text())[.= 0]') = 0 AND w.x.exist('(action[@name="sql_text"]/value/text())') = 1 - AND w.x.exist('(data[@name="duration"]/value/text())[. >= sql:variable("@wait_duration_ms")]') = 1 + AND w.x.exist('(data[@name="duration"]/value/text())[.>= sql:variable("@wait_duration_ms")]') = 1 AND NOT EXISTS ( SELECT @@ -939,8 +937,38 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. finding = 'queries with significant waits', wq.event_time, wq.wait_type, - wq.duration_ms, - wq.signal_duration_ms, + duration_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + wq.duration_ms + ), + 1 + ), + N'.00', + N'' + ), + signal_duration_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + wq.signal_duration_ms + ), + 1 + ), + N'.00', + N'' + ), wq.wait_resource, query_text = ( @@ -978,15 +1006,15 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ), wait_type = w2.x2.value('@waitType', 'nvarchar(60)'), waits = w2.x2.value('@waits', 'bigint'), - average_wait_time_ms = CONVERT(decimal(38, 2), w2.x2.value('@averageWaitTime', 'bigint') / 1000.), - max_wait_time_ms = CONVERT(decimal(38, 2), w2.x2.value('@maxWaitTime', 'bigint') / 1000.), + average_wait_time_ms = CONVERT(bigint, w2.x2.value('@averageWaitTime', 'bigint')), + max_wait_time_ms = CONVERT(bigint, w2.x2.value('@maxWaitTime', 'bigint')), xml = w.x.query('.') INTO #topwaits_count FROM #sp_server_diagnostics_component_result AS wi CROSS APPLY wi.sp_server_diagnostics_component_result.nodes('/event') AS w(x) CROSS APPLY w.x.nodes('/event/data/value/queryProcessing/topWaits/nonPreemptive/byCount/wait') AS w2(x2) - WHERE w.x.exist('(data[@name="component"]/text[.="QUERY_PROCESSING"])') = 1 - AND (w.x.exist('(data[@name="state"]/text[.="WARNING"])') = @warnings_only OR @warnings_only IS NULL) + WHERE w.x.exist('(data[@name="component"]/text[.= "QUERY_PROCESSING"])') = 1 + AND (w.x.exist('(data[@name="state"]/text[.= "WARNING"])') = @warnings_only OR @warnings_only IS NULL) AND NOT EXISTS ( SELECT @@ -1027,8 +1055,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SUM(CONVERT(bigint, tc.waits)) * AVG(tc.average_wait_time_ms) + MAX(tc.max_wait_time_ms), - average_wait_time_ms = CONVERT(decimal(38, 2), AVG(tc.average_wait_time_ms)), - max_wait_time_ms = CONVERT(decimal(38, 2), MAX(tc.max_wait_time_ms)) + average_wait_time_ms = CONVERT(bigint, AVG(tc.average_wait_time_ms)), + max_wait_time_ms = CONVERT(bigint, MAX(tc.max_wait_time_ms)) + INTO #tc FROM #topwaits_count AS tc GROUP BY tc.wait_type, @@ -1048,6 +1077,80 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. event_time_rounded DESC, waits DESC OPTION(RECOMPILE); + + SELECT + t.finding, + t.event_time_rounded, + t.wait_type, + waits = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + t.waits + ), + 1 + ), + N'.00', + N'' + ), + total_wait_time_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + t.total_wait_time_ms + ), + 1 + ), + N'.00', + N'' + ), + average_wait_time_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + t.average_wait_time_ms + ), + 1 + ), + N'.00', + N'' + ), + max_wait_time_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + t.max_wait_time_ms + ), + 1 + ), + N'.00', + N'' + ) + FROM #tc AS t + ORDER BY + t.event_time_rounded DESC, + t.waits DESC + OPTION(RECOMPILE); /*Grab waits by duration*/ IF @debug = 1 @@ -1073,15 +1176,15 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. state = w.x.value('(data[@name="state"]/text/text())[1]', 'nvarchar(256)'), wait_type = w2.x2.value('@waitType', 'nvarchar(60)'), waits = w2.x2.value('@waits', 'bigint'), - average_wait_time_ms = CONVERT(decimal(38, 2), w2.x2.value('@averageWaitTime', 'bigint') / 1000.), - max_wait_time_ms = CONVERT(decimal(38, 2), w2.x2.value('@maxWaitTime', 'bigint') / 1000.), + average_wait_time_ms = CONVERT(bigint, w2.x2.value('@averageWaitTime', 'bigint')), + max_wait_time_ms = CONVERT(bigint, w2.x2.value('@maxWaitTime', 'bigint')), xml = w.x.query('.') INTO #topwaits_duration FROM #sp_server_diagnostics_component_result AS wi CROSS APPLY wi.sp_server_diagnostics_component_result.nodes('/event') AS w(x) CROSS APPLY w.x.nodes('/event/data/value/queryProcessing/topWaits/nonPreemptive/byDuration/wait') AS w2(x2) - WHERE w.x.exist('(data[@name="component"]/text[.="QUERY_PROCESSING"])') = 1 - AND (w.x.exist('(data[@name="state"]/text[.="WARNING"])') = @warnings_only OR @warnings_only IS NULL) + WHERE w.x.exist('(data[@name="component"]/text[.= "QUERY_PROCESSING"])') = 1 + AND (w.x.exist('(data[@name="state"]/text[.= "WARNING"])') = @warnings_only OR @warnings_only IS NULL) AND NOT EXISTS ( SELECT @@ -1122,8 +1225,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SUM(CONVERT(bigint, td.waits)) * AVG(td.average_wait_time_ms) + MAX(td.max_wait_time_ms), - average_wait_time_ms = CONVERT(decimal(38, 2), AVG(td.average_wait_time_ms)), - max_wait_time_ms = CONVERT(decimal(38, 2), MAX(td.max_wait_time_ms)) + average_wait_time_ms = CONVERT(bigint, AVG(td.average_wait_time_ms)), + max_wait_time_ms = CONVERT(bigint, MAX(td.max_wait_time_ms)) + INTO #td FROM #topwaits_duration AS td GROUP BY td.wait_type, @@ -1143,6 +1247,80 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. event_time_rounded DESC, total_wait_time_ms DESC OPTION(RECOMPILE); + + SELECT + t.finding, + t.event_time_rounded, + t.wait_type, + waits = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + t.waits + ), + 1 + ), + N'.00', + N'' + ), + total_wait_time_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + t.total_wait_time_ms + ), + 1 + ), + N'.00', + N'' + ), + average_wait_time_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + t.average_wait_time_ms + ), + 1 + ), + N'.00', + N'' + ), + max_wait_time_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + t.max_wait_time_ms + ), + 1 + ), + N'.00', + N'' + ) + FROM #td AS t + ORDER BY + t.event_time_rounded DESC, + t.total_wait_time_ms DESC + OPTION(RECOMPILE); END; /*Grab IO stuff*/ @@ -1170,17 +1348,15 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ioLatchTimeouts = w.x.value('(/event/data[@name="data"]/value/ioSubsystem/@ioLatchTimeouts)[1]', 'bigint'), intervalLongIos = w.x.value('(/event/data[@name="data"]/value/ioSubsystem/@intervalLongIos)[1]', 'bigint'), totalLongIos = w.x.value('(/event/data[@name="data"]/value/ioSubsystem/@totalLongIos)[1]', 'bigint'), - longestPendingRequests_duration_ms = - CONVERT(decimal(38, 2), w2.x2.value('@duration', 'bigint') / 1000.), - longestPendingRequests_filePath = - w2.x2.value('@filePath', 'nvarchar(500)'), + longestPendingRequests_duration_ms = CONVERT(bigint, w2.x2.value('@duration', 'bigint')), + longestPendingRequests_filePath = w2.x2.value('@filePath', 'nvarchar(500)'), xml = w.x.query('.') INTO #io FROM #sp_server_diagnostics_component_result AS wi CROSS APPLY wi.sp_server_diagnostics_component_result.nodes('//event') AS w(x) OUTER APPLY w.x.nodes('/event/data/value/ioSubsystem/longestPendingRequests/pendingRequest') AS w2(x2) - WHERE w.x.exist('(data[@name="component"]/text[.="IO_SUBSYSTEM"])') = 1 - AND (w.x.exist('(data[@name="state"]/text[.="WARNING"])') = @warnings_only OR @warnings_only IS NULL) + WHERE w.x.exist('(data[@name="component"]/text[.= "IO_SUBSYSTEM"])') = 1 + AND (w.x.exist('(data[@name="state"]/text[.= "WARNING"])') = @warnings_only OR @warnings_only IS NULL) OPTION(RECOMPILE); IF @debug = 1 @@ -1200,10 +1376,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. i.ioLatchTimeouts, i.intervalLongIos, i.totalLongIos, - longestPendingRequests_duration_s = + longestPendingRequests_duration_ms = ISNULL(SUM(i.longestPendingRequests_duration_ms), 0), longestPendingRequests_filePath = ISNULL(i.longestPendingRequests_filePath, 'N/A') + INTO #i FROM #io AS i GROUP BY i.event_time, @@ -1215,6 +1392,35 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ORDER BY i.event_time DESC OPTION(RECOMPILE); + + SELECT + i.finding, + i.event_time, + i.state, + i.ioLatchTimeouts, + i.intervalLongIos, + i.totalLongIos, + longestPendingRequests_duration_ms = + REPLACE + ( + CONVERT + ( + nvarchar(30), + CONVERT + ( + money, + i.longestPendingRequests_duration_ms + ), + 1 + ), + N'.00', + N'' + ), + i.longestPendingRequests_filePath + FROM #i AS i + ORDER BY + i.event_time DESC + OPTION(RECOMPILE); END; /*Grab CPU details*/ @@ -1254,8 +1460,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. INTO #scheduler_details FROM #sp_server_diagnostics_component_result AS wi CROSS APPLY wi.sp_server_diagnostics_component_result.nodes('/event') AS w(x) - WHERE w.x.exist('(data[@name="component"]/text[.="QUERY_PROCESSING"])') = 1 - AND (w.x.exist('(data[@name="state"]/text[.="WARNING"])') = @warnings_only OR @warnings_only IS NULL) + WHERE w.x.exist('(data[@name="component"]/text[.= "QUERY_PROCESSING"])') = 1 + AND (w.x.exist('(data[@name="state"]/text[.= "WARNING"])') = @warnings_only OR @warnings_only IS NULL) OPTION(RECOMPILE); IF @debug = 1 @@ -1313,24 +1519,24 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. isAnyPoolOutOfMemory = r.c.value('@isAnyPoolOutOfMemory', 'bit'), processOutOfMemoryPeriod = r.c.value('@processOutOfMemoryPeriod', 'bigint'), name = r.c.value('(//memoryReport/@name)[1]', 'varchar(128)'), - available_physical_memory_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="Available Physical Memory"]]/@value)[1]', 'bigint') / 1024. / 1024. / 1024.), - available_virtual_memory_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="Available Virtual Memory"]]/@value)[1]', 'bigint') / 1024. / 1024. / 1024.), - available_paging_file_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="Available Paging File"]]/@value)[1]', 'bigint') / 1024. / 1024. / 1024.), - working_set_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="Working Set"]]/@value)[1]', 'bigint') / 1024. / 1024. / 1024.), + available_physical_memory_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="Available Physical Memory"]]/@value)[1]', 'bigint') / 1024. / 1024. / 1024.), + available_virtual_memory_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="Available Virtual Memory"]]/@value)[1]', 'bigint') / 1024. / 1024. / 1024.), + available_paging_file_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="Available Paging File"]]/@value)[1]', 'bigint') / 1024. / 1024. / 1024.), + working_set_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="Working Set"]]/@value)[1]', 'bigint') / 1024. / 1024. / 1024.), percent_of_committed_memory_in_ws = r.c.value('(//memoryReport/entry[@description[.="Percent of Committed Memory in WS"]]/@value)[1]', 'bigint'), page_faults = r.c.value('(//memoryReport/entry[@description[.="Page Faults"]]/@value)[1]', 'bigint'), system_physical_memory_high = r.c.value('(//memoryReport/entry[@description[.="System physical memory high"]]/@value)[1]', 'bigint'), system_physical_memory_low = r.c.value('(//memoryReport/entry[@description[.="System physical memory low"]]/@value)[1]', 'bigint'), process_physical_memory_low = r.c.value('(//memoryReport/entry[@description[.="Process physical memory low"]]/@value)[1]', 'bigint'), process_virtual_memory_low = r.c.value('(//memoryReport/entry[@description[.="Process virtual memory low"]]/@value)[1]', 'bigint'), - vm_reserved_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="VM Reserved"]]/@value)[1]', 'bigint') / 1024. / 1024.), - vm_committed_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="VM Committed"]]/@value)[1]', 'bigint') / 1024. / 1024.), + vm_reserved_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="VM Reserved"]]/@value)[1]', 'bigint') / 1024. / 1024.), + vm_committed_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="VM Committed"]]/@value)[1]', 'bigint') / 1024. / 1024.), locked_pages_allocated = r.c.value('(//memoryReport/entry[@description[.="Locked Pages Allocated"]]/@value)[1]', 'bigint'), large_pages_allocated = r.c.value('(//memoryReport/entry[@description[.="Large Pages Allocated"]]/@value)[1]', 'bigint'), - emergency_memory_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="Emergency Memory"]]/@value)[1]', 'bigint') / 1024. / 1024.), - emergency_memory_in_use_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="Emergency Memory In Use"]]/@value)[1]', 'bigint') / 1024. / 1024.), - target_committed_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="Target Committed"]]/@value)[1]', 'bigint') / 1024. / 1024.), - current_committed_gb = CONVERT(decimal(38, 2), r.c.value('(//memoryReport/entry[@description[.="Current Committed"]]/@value)[1]', 'bigint') / 1024. / 1024.), + emergency_memory_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="Emergency Memory"]]/@value)[1]', 'bigint') / 1024. / 1024.), + emergency_memory_in_use_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="Emergency Memory In Use"]]/@value)[1]', 'bigint') / 1024. / 1024.), + target_committed_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="Target Committed"]]/@value)[1]', 'bigint') / 1024. / 1024.), + current_committed_gb = CONVERT(bigint, r.c.value('(//memoryReport/entry[@description[.="Current Committed"]]/@value)[1]', 'bigint') / 1024. / 1024.), pages_allocated = r.c.value('(//memoryReport/entry[@description[.="Pages Allocated"]]/@value)[1]', 'bigint'), pages_reserved = r.c.value('(//memoryReport/entry[@description[.="Pages Reserved"]]/@value)[1]', 'bigint'), pages_free = r.c.value('(//memoryReport/entry[@description[.="Pages Free"]]/@value)[1]', 'bigint'), @@ -1436,8 +1642,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. INTO #health FROM #sp_server_diagnostics_component_result AS wi CROSS APPLY wi.sp_server_diagnostics_component_result.nodes('//event') AS w(x) - WHERE w.x.exist('(data[@name="component"]/text[.="SYSTEM"])') = 1 - AND (w.x.exist('(data[@name="state"]/text[.="WARNING"])') = @warnings_only OR @warnings_only IS NULL) + WHERE w.x.exist('(data[@name="component"]/text[.= "SYSTEM"])') = 1 + AND (w.x.exist('(data[@name="state"]/text[.= "WARNING"])') = @warnings_only OR @warnings_only IS NULL) OPTION(RECOMPILE); IF @debug = 1 @@ -1523,9 +1729,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. FROM #sp_server_diagnostics_component_result AS wi CROSS APPLY wi.sp_server_diagnostics_component_result.nodes('//event') AS w(x) CROSS APPLY w.x.nodes('//data[@name="data"]/value/queryProcessing/cpuIntensiveRequests/request') AS w2(x2) - WHERE w.x.exist('(data[@name="component"]/text[.="QUERY_PROCESSING"])') = 1 + WHERE w.x.exist('(data[@name="component"]/text[.= "QUERY_PROCESSING"])') = 1 AND w.x.exist('//data[@name="data"]/value/queryProcessing/cpuIntensiveRequests/request') = 1 - AND (w.x.exist('(data[@name="state"]/text[.="WARNING"])') = @warnings_only OR @warnings_only IS NULL) + AND (w.x.exist('(data[@name="state"]/text[.= "WARNING"])') = @warnings_only OR @warnings_only IS NULL) OPTION(RECOMPILE); IF @debug = 1 @@ -1574,9 +1780,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. INTO #blocking_xml FROM #sp_server_diagnostics_component_result AS wi CROSS APPLY wi.sp_server_diagnostics_component_result.nodes('//event') AS w(x) - WHERE w.x.exist('(data[@name="component"]/text[.="QUERY_PROCESSING"])') = 1 + WHERE w.x.exist('(data[@name="component"]/text[.= "QUERY_PROCESSING"])') = 1 AND w.x.exist('//data[@name="data"]/value/queryProcessing/blockingTasks/blocked-process-report') = 1 - AND (w.x.exist('(data[@name="state"]/text[.="WARNING"])') = @warnings_only OR @warnings_only IS NULL) + AND (w.x.exist('(data[@name="state"]/text[.= "WARNING"])') = @warnings_only OR @warnings_only IS NULL) OPTION(RECOMPILE); IF @debug = 1 diff --git a/sp_LogHunter/sp_LogHunter.sql b/sp_LogHunter/sp_LogHunter.sql index 648d580..b25a238 100644 --- a/sp_LogHunter/sp_LogHunter.sql +++ b/sp_LogHunter/sp_LogHunter.sql @@ -10,20 +10,20 @@ SET STATISTICS TIME, IO OFF; GO /* -██╗ ██████╗ ██████╗ -██║ ██╔═══██╗██╔════╝ -██║ ██║ ██║██║ ███╗ -██║ ██║ ██║██║ ██║ -███████╗╚██████╔╝╚██████╔╝ -╚══════╝ ╚═════╝ ╚═════╝ - +██╗ ██████╗ ██████╗ +██║ ██╔═══██╗██╔════╝ +██║ ██║ ██║██║ ███╗ +██║ ██║ ██║██║ ██║ +███████╗╚██████╔╝╚██████╔╝ +╚══════╝ ╚═════╝ ╚═════╝ + ██╗ ██╗██╗ ██╗███╗ ██╗████████╗███████╗██████╗ ██║ ██║██║ ██║████╗ ██║╚══██╔══╝██╔════╝██╔══██╗ ███████║██║ ██║██╔██╗ ██║ ██║ █████╗ ██████╔╝ ██╔══██║██║ ██║██║╚██╗██║ ██║ ██╔══╝ ██╔══██╗ ██║ ██║╚██████╔╝██║ ╚████║ ██║ ███████╗██║ ██║ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ - + Copyright 2024 Darling Data, LLC https://www.erikdarlingdata.com/ @@ -42,11 +42,11 @@ EXEC sp_LogHunter; */ -IF OBJECT_ID('dbo.sp_LogHunter') IS NULL - BEGIN - EXEC ('CREATE PROCEDURE dbo.sp_LogHunter AS RETURN 138;'); - END; -GO +IF OBJECT_ID('dbo.sp_LogHunter') IS NULL + BEGIN + EXEC ('CREATE PROCEDURE dbo.sp_LogHunter AS RETURN 138;'); + END; +GO ALTER PROCEDURE dbo.sp_LogHunter @@ -65,9 +65,9 @@ ALTER PROCEDURE ) WITH RECOMPILE AS -SET STATISTICS XML OFF; +SET STATISTICS XML OFF; SET NOCOUNT ON; -SET XACT_ABORT ON; +SET XACT_ABORT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; BEGIN @@ -83,7 +83,7 @@ BEGIN SELECT 'you can use me to look through your error logs for bad stuff' UNION ALL SELECT 'all scripts and documentation are available here: https://github.com/erikdarlingdata/DarlingData/tree/main/sp_LogHunter' UNION ALL SELECT 'from your loving sql server consultant, erik darling: https://erikdarlingdata.com'; - + SELECT parameter_name = ap.name, @@ -138,38 +138,49 @@ BEGIN AND ap.user_type_id = t.user_type_id WHERE o.name = N'sp_LogHunter' OPTION(RECOMPILE); - + SELECT mit_license_yo = 'i am MIT licensed, so like, do whatever' - + UNION ALL - + SELECT mit_license_yo = 'see printed messages for full license'; - + RAISERROR(' MIT License - + Copyright 2023 Darling Data, LLC - + https://www.erikdarlingdata.com/ - + 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. ', 0, 1) WITH NOWAIT; - + RETURN; END; - + + /*Check if we have sa permissisions*/ + IF + ( + SELECT + sa = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) + ) = 0 + BEGIN + RAISERROR(N'Current user is not a member of sysadmin, so we can''t read the error log', 11, 1) WITH NOWAIT; + RETURN; + END; + /*Check if we're using RDS*/ IF OBJECT_ID(N'rdsadmin.dbo.rds_read_error_log') IS NOT NULL BEGIN @@ -204,7 +215,7 @@ BEGIN RAISERROR(N'%i is not not a valid language_id in sys.messages.', 11, 1, @language_id) WITH NOWAIT; RETURN; END; - + /*Fix days back a little bit*/ IF @days_back = 0 BEGIN @@ -217,7 +228,7 @@ BEGIN SELECT @days_back *= -1; END; - + IF @start_date IS NOT NULL AND @end_date IS NOT NULL AND @days_back IS NOT NULL @@ -266,7 +277,7 @@ BEGIN @t_searches int = 0 /*total number of searches to run*/, @l_count int = 1 /*loop count*/, @stopper bit = 0 /*stop loop execution safety*/; - + /*temp tables for holding temporary things*/ CREATE TABLE #error_log @@ -275,11 +286,11 @@ BEGIN process_info nvarchar(100), text nvarchar(4000) ); - + CREATE TABLE #enum ( - archive int + archive int PRIMARY KEY, log_date date, log_size bigint @@ -346,7 +357,7 @@ BEGIN AND e.archive > 0 OPTION(RECOMPILE); END; - + /*filter out log files we won't use, if @start_date and @end_date are set*/ IF @start_date IS NOT NULL AND @end_date IS NOT NULL @@ -426,22 +437,22 @@ BEGIN FROM ( VALUES - ('error'), ('corrupt'), ('insufficient'), ('DBCC CHECKDB'), ('Attempt to fetch logical page'), ('Total Log Writer threads'), + ('error'), ('corrupt'), ('insufficient'), ('DBCC CHECKDB'), ('Attempt to fetch logical page'), ('Total Log Writer threads'), ('Wait for redo catchup for the database'), ('Restart the server to resolve this problem'), ('running low'), ('unexpected'), - ('fail'), ('contact'), ('incorrect'), ('allocate'), ('allocation'), ('Timeout occurred'), ('memory manager'), ('operating system'), + ('fail'), ('contact'), ('incorrect'), ('allocate'), ('allocation'), ('Timeout occurred'), ('memory manager'), ('operating system'), ('cannot obtain a LOCK resource'), ('Server halted'), ('spawn'), ('BobMgr'), ('Sort is retrying the read'), ('service'), - ('resumed'), ('repair the database'), ('buffer'), ('I/O Completion Port'), ('assert'), ('integrity'), ('latch'), ('SQL Server is exiting'), + ('resumed'), ('repair the database'), ('buffer'), ('I/O Completion Port'), ('assert'), ('integrity'), ('latch'), ('SQL Server is exiting'), ('SQL Server is unable to run'), ('suspect'), ('restore the database'), ('checkpoint'), ('version store is full'), ('Setting database option'), ('Perform a restore if necessary'), ('Autogrow of file'), ('Bringing down database'), ('hot add'), ('Server shut down'), - ('stack'), ('inconsistency.'), ('invalid'), ('time out occurred'), ('The transaction log for database'), ('The virtual log file sequence'), + ('stack'), ('inconsistency.'), ('invalid'), ('time out occurred'), ('The transaction log for database'), ('The virtual log file sequence'), ('Cannot accept virtual log file sequence'), ('The transaction in database'), ('Shutting down'), ('thread pool'), ('debug'), ('resolving'), ('Cannot load the Query Store metadata'), ('Cannot acquire'), ('SQL Server evaluation period has expired'), ('terminat'), ('currently busy'), ('SQL Server has been configured for lightweight pooling'), ('IOCP'), ('Not enough memory for the configured number of locks'), - ('The tempdb database data files are not configured with the same initial size and autogrowth settings'), ('The SQL Server image'), ('affinity'), - ('SQL Server is starting'), ('Ignoring trace flag '), ('20 physical cores'), ('No free space'), ('Warning ******************'), + ('The tempdb database data files are not configured with the same initial size and autogrowth settings'), ('The SQL Server image'), ('affinity'), + ('SQL Server is starting'), ('Ignoring trace flag '), ('20 physical cores'), ('No free space'), ('Warning ******************'), ('SQL Server should be restarted'), ('Server name is'), ('Could not connect'), ('yielding'), ('worker thread'), ('A new connection was rejected'), - ('A significant part of sql server process memory has been paged out'), ('Dispatcher'), ('I/O requests taking longer than'), ('killed'), - ('SQL Server could not start'), ('SQL Server cannot start'), ('System Manufacturer:'), ('columnstore'), ('timed out'), ('inconsistent'), + ('A significant part of sql server process memory has been paged out'), ('Dispatcher'), ('I/O requests taking longer than'), ('killed'), + ('SQL Server could not start'), ('SQL Server cannot start'), ('System Manufacturer:'), ('columnstore'), ('timed out'), ('inconsistent'), ('flushcache'), ('Recovery for availability database') ) AS v (search_string) CROSS JOIN @@ -455,7 +466,7 @@ BEGIN N'"' + CONVERT(nvarchar(30), @end_date) + N'"' ) AS c WHERE @custom_message_only = 0 - OPTION(RECOMPILE); + OPTION(RECOMPILE); /*deal with a custom search string here*/ INSERT @@ -488,7 +499,7 @@ BEGIN BEGIN SELECT table_name = '#search', s.* FROM #search AS s; END; - + /*Set the min and max logs we're getting for the loop*/ SELECT @l_log = MIN(e.archive), @@ -505,7 +516,7 @@ BEGIN END; IF @debug = 1 BEGIN RAISERROR('Declaring cursor', 0, 1) WITH NOWAIT; END; - + /*start the loops*/ WHILE @l_log <= @h_log BEGIN @@ -520,17 +531,17 @@ BEGIN SELECT command FROM #search; - + IF @debug = 1 BEGIN RAISERROR('Opening cursor', 0, 1) WITH NOWAIT; END; - - OPEN c; + OPEN c; + FETCH FIRST FROM c INTO @c; IF @debug = 1 BEGIN RAISERROR('Entering WHILE loop', 0, 1) WITH NOWAIT; END; - WHILE @@FETCH_STATUS = 0 AND @stopper = 0 + WHILE @@FETCH_STATUS = 0 AND @stopper = 0 BEGIN IF @debug = 1 BEGIN RAISERROR('Entering cursor', 0, 1) WITH NOWAIT; END; /*Replace the canary value with the log number we're working in*/ @@ -547,9 +558,9 @@ BEGIN BEGIN RAISERROR('log %i of %i', 0, 1, @l_log, @h_log) WITH NOWAIT; RAISERROR('search %i of %i', 0, 1, @l_count, @t_searches) WITH NOWAIT; - RAISERROR('@c: %s', 0, 1, @c) WITH NOWAIT; + RAISERROR('@c: %s', 0, 1, @c) WITH NOWAIT; END; - + IF @debug = 1 BEGIN RAISERROR('Inserting to error log', 0, 1) WITH NOWAIT; END; BEGIN BEGIN TRY @@ -574,10 +585,10 @@ BEGIN VALUES ( @c - ); + ); END CATCH; END; - + IF @debug = 1 BEGIN RAISERROR('Fetching next', 0, 1) WITH NOWAIT; END; /*Get the next search command*/ FETCH NEXT @@ -589,7 +600,7 @@ BEGIN @l_count += 1; END; - + IF @debug = 1 BEGIN RAISERROR('Getting next log', 0, 1) WITH NOWAIT; END; /*Increment the log numbers*/ SELECT @@ -601,18 +612,18 @@ BEGIN IF @debug = 1 BEGIN - RAISERROR('log %i of %i', 0, 1, @l_log, @h_log) WITH NOWAIT; + RAISERROR('log %i of %i', 0, 1, @l_log, @h_log) WITH NOWAIT; END; /*Stop the loop if this is NULL*/ IF @l_log IS NULL BEGIN - IF @debug = 1 BEGIN RAISERROR('Breaking', 0, 1) WITH NOWAIT; END; + IF @debug = 1 BEGIN RAISERROR('Breaking', 0, 1) WITH NOWAIT; END; SET @stopper = 1; BREAK; - END; + END; IF @debug = 1 BEGIN RAISERROR('Ended WHILE loop', 0, 1) WITH NOWAIT; END; - + /*Close out the cursor*/ CLOSE c; DEALLOCATE c; @@ -668,7 +679,7 @@ BEGIN 1/0 FROM #errors AS e ) - BEGIN + BEGIN SELECT table_name = '#errors',