sp_LogHunter has been turning away people who could read the error log perfectly well. That stops here.
sp_LogHunter stops asking the wrong question
The permission check was IS_SRVROLEMEMBER(N'sysadmin'), and sysadmin was never the permission the procedure needed. xp_readerrorlog can be handed out with GRANT EXECUTE, so an account holding exactly that grant read the log fine — while sp_LogHunter looked at role membership, saw no, and quit before trying.
It now asks about the permission it actually uses:
HAS_PERMS_BY_NAME(N'master.dbo.xp_readerrorlog', N'OBJECT', N'EXECUTE')The error message names that permission too, so a failure tells you what to grant instead of telling you to become sysadmin.
sp_enumerrorlogs — which enumerates the archived logs — is a separate and nastier problem. It checks membership in securityadmin itself, and no GRANT substitutes for that, because it is the role it tests and not a permission you can hand out. Rather than letting error 27219 kill the whole run, sp_LogHunter catches it, reads the current log (which xp_readerrorlog can still do), and tells you that is what happened:
Not a member of securityadmin, so archived error logs cannot be enumerated. Reading the current log only.
Verified against the reporter's exact permission set, which incidentally proved that nothing else in the procedure needs elevation. Thanks to @jbelina for reporting it and for not accepting the first answer. (#858, #859)
sp_QuickieStore
@find_parameter_sensitive went to production and came back different (#854). Coefficient of variation on its own is scale-blind: a 3ms→60ms swing out-ranks a 2s→40s one every time, and on an 11-database fleet that meant sub-second queries held 91 of 162 top-15 slots. Ranking is now work-weighted, so a shape has to be both volatile and expensive to surface. On one tenant the window CPU represented by the top 15 went from 295 seconds to 4,170.
Four more from the same dogfooding:
@include_query_hashes/@ignore_query_hashes/@include_plan_hashes/@ignore_plan_hashesare honored inside the mode. An index-maintenance query held a top-15 slot on 11 of 11 production databases — genuinely volatile, genuinely expensive, and previously impossible to exclude.- A new
mixed swingssignal fills a classification hole that left 25 of 162 surfaced shapes with a blank verdict, which reads as "nothing to see" on a row the mode itself just ranked in the top 15. - Ratio displays cap at
9999+rather than printingcpu 2850350x, and a shape that never returned a row saysrows flatinstead ofrows 0x. - The summary distinguishes "no waits" from "wait stats capture is off" instead of silently dropping the column. Only 1 of those 11 databases had capture on, and the silent omission fooled the harness that found the rest of this list.
Two wait-accounting fixes. @wait_filter matched waits from all of Query Store history rather than the interval you asked for (#852), and the wait sort orders counted across all of history the same way (#850). Both made waits look like they belonged to a window they had nothing to do with.
New log and total log sort orders, so you can rank by log bytes generated. Thanks to @ReeceGoding. (#819)
sp_PerfCheck
@database_name narrowed the summary but not the per-file I/O detail, so a run filtered to one database still handed back files from every database on the instance — 16 rows where 2 were asked for. The filter now goes to sys.dm_io_virtual_file_stats itself, which is how the Azure SQL DB path already worked, instead of a WHERE clause the detail query never had. Thanks again to @jbelina. (#856, #860)
All ten procs move to .9, version date 20260901.