info@techdevops.com | 437-991-3573 | Data Engineering Services
TechDevOps.com
Resources Tools
Experts in Microsoft SQL Server on Windows, Linux, Containers | Clusters, Always On, FCI | Migrations, Cloud, Performance



SQL Space Monitor - Version 2
by BF (Principal Consultant; Architecture; Engineering)
2017-07-12








SQL Space Monitor - Version 2:

Captures, Logs, Alerts & Reports for Microsoft SQL Server Database Data and Log File Space plus Disk Space.

We have included in Version 2 the logic for Warning and Alert Thresholds - per Database Data and Log Files Internal Space and Disk Space - as parameters and also added the ability to email a HTML generated report. The report has row-level markers that differentiate each type of space monitor and easily displays to the user the items needing attention. Version 2 also includes a permanent table for logging of all system & user databases space and all disk mounts space.

If needed, Version 1 is located here: T-SQL Get Databases File Sizes



T-SQL Solution:


Create Logging Table:


SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[LOG_SPACE_DB_DISK](
[LogID] [int] IDENTITY(1,1) NOT NULL,
[DB] [sysname] NOT NULL,
[LogicalFileName] [nvarchar](100) NULL,
[PhysicalFileName] [nvarchar](500) NULL,
[FileID] [int] NULL,
[FileSizeMB] [decimal](18, 2) NULL,
[FileFreeSpaceMB] [decimal](18, 2) NULL,
[FileFreeSpace%] [decimal](18, 2) NULL,
[DiskMount] [nvarchar](5) NULL,
[DiskSizeGB] [decimal](18, 2) NULL,
[DiskFreeSpaceGB] [decimal](18, 2) NULL,
[DiskFreeSpace%] [decimal](18, 2) NULL,
[InsertedDate] [datetime] NULL,
[PeriodEnding] [datetime] NULL,
CONSTRAINT [PK_LOG_SPACE_DB_DISK] PRIMARY KEY CLUSTERED
(
[LogID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO


Create Stored Procedure:

Create Procedure dbo.sp_Server_Space_DB_DISK
@WarningThresholdPercent decimal(18,0) = 10, -- <10%
@WarningThresholdValue decimal(18,0) = 10, -- <5GB
@AlertThresholdPercent decimal(18,0) = 5, -- <5%
@AlertThresholdValue decimal(18,0) = 5, -- <1GB
@EmailReport int = 1
as


/*
Reference: www.TechDevOps.com
*/

Set nocount on

Declare @PeriodEnding datetime;
Declare @IsWarnings bit = 0;
Declare @IsAlerts bit = 0;
Declare @tableHTML nvarchar(max);
Set @PeriodEnding = GetDate();

Create Table #TMP
(
[DB] sysname,
[LogicalFileName] nvarchar(100),
[PhysicalFileName] nvarchar(500),
[FileID] int,
[FileSizeMB] decimal (18,2),
[FileFreeSpaceMB] decimal (18,2),
[FileFreeSpace%] decimal (18,2),
[DiskMount] nvarchar(5),
[DiskSizeGB] decimal (18,2),
[DiskFreeSpaceGB] decimal (18,2),
[DiskFreeSpace%] decimal (18,2),
)
Exec sp_msforeachdb '
Use [?];
INSERT INTO #TMP (DB, LogicalFileName, PhysicalFileName, FileID, FileSizeMB, FileFreeSpaceMB, [FileFreeSpace%], [DiskMount], DiskSizeGB, DiskFreeSpaceGB, [DiskFreeSpace%])
SELECT DB_NAME() AS [DatabaseName], f.Name, f.physical_name, f.[file_id] As [FileID],
CONVERT(DECIMAL(18,2),CONVERT(DECIMAL(18,2),CONVERT(DECIMAL(18,2),f.size) * 8.0/1024.0,2)) As FileSizeMB,
CONVERT(DECIMAL(18,2),CONVERT(DECIMAL(18,2),CONVERT(DECIMAL(18,2),f.size) * 8.0/1024.0,2) -
CONVERT(DECIMAL(18,2),FILEPROPERTY(f.name, ''SpaceUsed'') * 8.0/1024.0)) As FileFreeSpaceMB,
CONVERT(DECIMAL(18,2),CAST(f.size/128.0 - CAST(FILEPROPERTY(f.name, ''SpaceUsed'') AS int)/128.0 AS DECIMAL(18,2)) / CAST((f.size/128.0) AS DECIMAL(18,3)) * 100) As [File Free Space(%)],
volume_mount_point [Disk Mount],
CONVERT(DECIMAL(18,2),total_bytes/1024.00/1024.00/1024.00) As [Disk Size(GB)],
CONVERT(DECIMAL(18,2),available_bytes/1024.00/1024.00/1024.00) AS [Disk Space Available(GB)],
CAST(CAST(available_bytes AS DECIMAL(18,2)) / CAST(total_bytes AS DECIMAL(18,2)) AS DECIMAL(18,3)) * 100 As [Disk Free Space %]
FROM sys.database_files f
INNER JOIN sys.master_files m on f.file_id = m.file_id
LEFT OUTER JOIN sys.data_spaces As ds WITH (NOLOCK) ON f.data_space_id = ds.data_space_id
CROSS APPLY sys.dm_os_volume_stats(database_id, m.file_id)
WHERE m.database_id = db_id()
'
Insert into [dbo].[LOG_SPACE_DB_DISK] ([DB],[LogicalFileName],[PhysicalFileName],[FileID],[FileSizeMB],[FileFreeSpaceMB],[FileFreeSpace%],
[DiskMount],[DiskSizeGB],[DiskFreeSpaceGB],[DiskFreeSpace%],[InsertedDate],[PeriodEnding])
Select
[DB],[LogicalFileName],[PhysicalFileName],[FileID],[FileSizeMB],[FileFreeSpaceMB],[FileFreeSpace%],
[DiskMount],[DiskSizeGB],[DiskFreeSpaceGB],[DiskFreeSpace%], GetDate(),@PeriodEnding
From #TMP order by [DB] asc, [FileID] asc

--Begin Warnings:
IF EXISTS(
Select 1 from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([FileFreeSpace%] > @AlertThresholdPercent and [FileFreeSpace%] < @WarningThresholdPercent)
or ([DiskFreeSpace%] > @AlertThresholdPercent and [DiskFreeSpace%] < @WarningThresholdPercent and [DiskFreeSpaceGB] < @WarningThresholdValue)
)
Begin

Set @IsWarnings = 1

IF EXISTS(
Select 1 from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([FileFreeSpace%] > @AlertThresholdPercent and [FileFreeSpace%] < @WarningThresholdPercent)
)
Begin
Select 'Warning[!] DB Space [Btw:' + Convert(varchar(5),@AlertThresholdPercent) + '%-' + Convert(varchar(5),@WarningThresholdPercent) + '%]' as 'Message',
[FileFreeSpace%], DB, [PhysicalFilename] from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding
and ([FileFreeSpace%] > @AlertThresholdPercent and [FileFreeSpace%] < @WarningThresholdPercent) order by [FileFreeSpace%] asc
End
IF EXISTS(
Select 1 from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([DiskFreeSpace%] > @AlertThresholdPercent
and [DiskFreeSpace%] < @WarningThresholdPercent) and ([DiskFreeSpaceGB] < @WarningThresholdValue)
)
Begin
Select distinct 'Warning[!] Disk Space(' + Convert(varchar(5),@AlertThresholdPercent) + '%-' + Convert(varchar(5),@WarningThresholdPercent) + '%;<' + Convert(varchar(5),@WarningThresholdValue) + 'gb)' as 'Message',
[DiskFreeSpace%], [DiskFreeSpaceGB], DiskMount
from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([DiskFreeSpace%] > @AlertThresholdPercent and [DiskFreeSpace%] < @WarningThresholdPercent)
and ([DiskFreeSpaceGB] < @WarningThresholdValue)
order by [DiskFreeSpace%] asc
End
End
Else
Begin
Select 'No Warnings' as 'Message Warnings:'
End

--Begin Alerts:
IF EXISTS(
Select 1 from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([FileFreeSpace%] < @AlertThresholdPercent or [DiskFreeSpace%] < @AlertThresholdPercent
and [DiskFreeSpaceGB] < @WarningThresholdValue)
)
Begin

Set @IsAlerts = 1

IF EXISTS(
Select 1 from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([FileFreeSpace%] < @AlertThresholdPercent)
)
Begin
Select 'Alert[X] DB Space(<' + Convert(varchar(5),@AlertThresholdPercent) + '%)' as 'Message', [FileFreeSpace%], DB, [PhysicalFilename]
from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([FileFreeSpace%]) < @AlertThresholdPercent order by [FileFreeSpace%] asc
End
IF EXISTS(
Select 1 from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([DiskFreeSpace%] < @AlertThresholdPercent) and ([DiskFreeSpaceGB] < @AlertThresholdValue)
)
Begin
Select 'Alert[X] Disk Space(<' + Convert(varchar(5),@AlertThresholdPercent) + '%)' as 'Message', [DiskFreeSpace%], [DiskFreeSpaceGB], DiskMount
from [dbo].[LOG_SPACE_DB_DISK] where PeriodEnding = @PeriodEnding and ([DiskFreeSpace%] < @AlertThresholdPercent) order by [DiskFreeSpace%] asc
End
End
Else
Begin
Select 'No Alerts' as 'Message Alerts:'
End

--Begin Notifications:
If (@IsWarnings = 1 or @IsAlerts = 1) and @EmailReport = 1
Begin

SET @tableHTML =
N'<H4><Font Color=black><font face="Arial, Verdana, sans-serif;"><u>REPORT TITLE:</u> DATABASE FILE & DISK SPACE - WARNINGS & ALERTS</H4>' +
N'<H4><Font Color=black><font face="Arial, Verdana, sans-serif;">' + @@SERVERNAME + '</H4></font>' +
N'<H4><Font Color=black><font face="Arial, Verdana, sans-serif;">' + convert(nvarchar(25),@PeriodEnding) + '</H4></font>' +
N'<table border="1" style=”font-family:arial;color:black;font-size:11pt;”> ' +
N'<tr align="left"><th align="left" bgcolor="black" style="color:white;">Server</th><th align="left" bgcolor="black" style="color:white;">DB</th>
<th align="left" bgcolor="black" style="color:white;">Run Date</th> <th align="left" bgcolor="black" style="color:white;">FileFreeSpace%</th>
<th align="left" bgcolor="black" style="color:white;">PhysicalFileName</th><th align="left" bgcolor="black" style="color:white;">Disk Mount</th>
<th align="left" bgcolor="black" style="color:white;">DiskFreeSpace%</th>
</tr>' +
CAST ((

Select
Case
When [FileFreeSpace%] > @AlertThresholdPercent and [FileFreeSpace%] < @WarningThresholdPercent then '#ffff33'
When [FileFreeSpace%] < @AlertThresholdPercent then '#ff3333'
Else '#d9d9d9'
end AS [@bgcolor],
td = [Server], '',
td = [DB], '',
td = [PeriodEnding], '',
td = [FileFreeSpace%], '',
td = [PhysicalFileName], '',
td = [DiskMount], '',
td = [DiskFreeSpace%], ''
From
(
Select
@@ServerName as [Server],
[DB],
CONVERT(VARCHAR(12),@PeriodEnding,107) as [PeriodEnding],
[FileFreeSpace%],
[PhysicalFileName],
[DiskMount],
[DiskFreeSpace%]
from [dbo].[LOG_SPACE_DB_DISK]
where PeriodEnding = @PeriodEnding
) t

FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;

Set @tableHTML = '</br><font size=2>' + @tableHTML + '</br></br>' + '- Report Warning Run Values: File Space: Between ' + Convert(varchar(5),@AlertThresholdPercent) + '%-' + Convert(varchar(5),@WarningThresholdPercent) + '% free space'

Set @tableHTML = @tableHTML + '</br>' + '- Report Warning Run Values: Disk Space: Between ' + Convert(varchar(5),@AlertThresholdPercent) + '%-' + Convert(varchar(5),@WarningThresholdPercent) + '% free space and Less Than ' + Convert(varchar(5),@WarningThresholdValue) + 'GB free space'

Set @tableHTML = @tableHTML + '</br></br>' + '- Report Alert Run Values: File Space: Less Than ' + Convert(varchar(5),@AlertThresholdPercent) + '% free space'

Set @tableHTML = @tableHTML + '</br>' + '- Report Alert Run Values: Disk Space: Less Than ' + Convert(varchar(5),@AlertThresholdValue) + 'GB free space'

Set @tableHTML = @tableHTML + '</br></br>' + '<font size=2>- Source: sp_Server_Space_DB_DISK'

Set @tableHTML = @tableHTML + '</br></br>' + '- Delivered by DBMail on SRV-NYC-01' +
+
'</font>'

If @tableHTML <> '' and @tableHTML IS NOT NULL
Begin
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'Profilexyz',
@recipients='ops@xyz.ca',
@subject = 'MSSQL - Database File & Disk Space - Warnings & Alerts Report: SRV-NYC-01',
@body = @tableHTML,
@body_format = 'HTML' ;
End

End

Drop Table #TMP
GO


HTML Generated Report with row-level markers for Warnings and Alerts: