Check SQL DB Free space
System Center Operations Manager is monitoring DB space used by default if you have set the database to a fixed size. If you are using autogrowth with unlimited file growth, your diskspace monitoring will kick in when you are running out of disk space (don’t forget to customize these settings for large disks: you don’t want to get warned on a 500GB volume when there is only 2 GB free space).
However, if you are using autogrow options with a limited size, then SCOM 2007 doesn’t generate alerts as also documented in the product knowledge tab for “DB Space Free (%)” Monitor:
This monitor checks the database percentage free space to ensure it is above the defined thresholds. A warning or error alert will be raised if it is below one of the defined thresholds.
Databases that have autogrow set will never generate an alert regardless of the reported free space.
If your database is filling up, you get the following error: Could not allocate space for object in database because the filegroup is full.
To prevent this error and get warned in advance, I have written a custom monitor that will detect databases with the settings mentioned above and monitors database free space when autogrow AND limited file size are on.
For detailed instruction on how to setup a monitor for monitoring SQL Server, have a look at: Check your SQL backup automatically.
Script is updated on 26-11-2009, some bugs are fixed and it is now using the “SQL 2005 DB Engine” monitor instead of the “SQL 2005 DB” monitor. First I thought it would be better to handle all individual databases by SCOM. However is something is wrong with the script, SCOM generates an alert for every database. If you have a lot of databases on one server (I have servers with over 500 databases), it can generate a lot of alerts. Now only one alert per engine is generated. And the script takes only 3 seconds on my 500+ database server.
Here are the short instructions for this monitor:
$Target/Property[Type="MicrosoftSQLServerLibrary6064600!Microsoft.SQLServer.DBEngine"]/ConnectionString$
Low DB Free space on $Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetbiosComputerName$ in instance $Target/Property[Type="MicrosoftSQLServerLibrary6064600!Microsoft.SQLServer.DBEngine"]/ServiceName$, list of datafiles: $Data/Context/Property[@Name='DBList']$
Dim i, oAPI, propertyBag, objShell
Dim strStatus
Dim objParameters, sConnectionString
' define constants
Const EVENT_TYPE_ERROR = 1
Const EVENT_TYPE_WARNING = 2
Const EVENT_TYPE_INFORMATION = 4
' check parameters
Set objParameters = WScript.Arguments
If objParameters.Count <> 1 Then
' Set objShell = Wscript.CreateObject("Wscript.Shell")
' objShell.LogEvent EVENT_TYPE_ERROR, "This Script requires exactly 1 parameter: ConnectionString"
WScript.Quit -1
End If
' map arguments to friendly names
sConnectionString= objParameters(0)
' initialize SQL statement
SQL = "SET NOCOUNT ON; " & _
"DECLARE @dbid int DECLARE @dbname sysname DECLARE @sql varchar(3000) " & _
"CREATE TABLE #DBSpace ( " & _
" DBName varchar (50), " & _
" [Size] int, " & _
" max_size int, " & _
" growth int, " & _
" is_percentage_growth bit, " & _
" percentage_used real, " & _
" [type] varchar(15), " & _
" severity varchar(8)) " & _
"SET @dbid = (SELECT MIN(database_id) FROM master.sys.databases) " & _
"WHILE @dbid IS NOT NULL " & _
" BEGIN " & _
" SET @dbname = (SELECT [name] FROM master.sys.databases WHERE database_id = @dbid) " & _
" SET @sql = 'INSERT INTO #DBSpace SELECT dbname , [size], max_size, growth, is_percent_growth, percentage_used, " & _
" CASE " & _
" WHEN [type] = 0 THEN ''Database'' " & _
" WHEN [type] = 1 THEN ''Transaction Log'' " & _
" END AS [type], " & _
" CASE " & _
" WHEN is_percent_growth = 1 THEN " & _
" CASE " & _
" WHEN db.percentage_used < (100 - ((db.percentage_used / 100) * db.growth * 1.2)) AND db.percentage_used > (100 - ((db.percentage_used / 100) * db.growth * 2.5)) THEN ''warning'' " & _
" WHEN db.percentage_used > (100 - ((db.percentage_used / 100) * db.growth * 1.2)) THEN ''critical'' " & _
" ELSE ''healthy'' " & _
" END " & _
" ELSE " & _
" CASE " & _
" WHEN db.size < (db.max_size - (db.growth * 2)) AND db.size > (db.max_size - (db.growth * 4)) THEN ''warning'' " & _
" WHEN db.size > (db.max_size - (db.growth * 2)) THEN ''critical'' " & _
" ELSE ''healthy'' " & _
" END " & _
" END AS severity " & _
" FROM " & _
" ( SELECT ''' + @dbname + ''' as dbname, [size] , [type], [max_size], [growth] , " & _
" [is_percent_growth] , " & _
" (CAST([size] AS REAL) / CAST([max_size] AS REAL) * 100) AS percentage_used " & _
" FROM [' + @dbname + '].sys.database_files )AS db " & _
" WHERE max_size > 0 AND growth > 0 ' " & _
" EXEC(@sql) " & _
" SET @dbid = (SELECT MIN(database_id) FROM master.sys.databases WHERE database_id > @dbid) " & _
" END " & _
"SELECT * FROM #DBSpace WHERE severity <> 'healthy' " & _
"drop table #DBSpace"
On Error resume next
' Setup Database connection
Set cnADOConnection = CreateObject("ADODB.Connection")
cnADOConnection.Provider = "sqloledb"
cnADOConnection.ConnectionTimeout = 30
strProv = "Server=" & sConnectionString & ";Database=Master;Trusted_Connection=yes"
' open connection and execute query
cnADOConnection.Open strProv
Set rsCustomDBSpaceMonitor = cnADOConnection.Execute(SQL)
do until rsCustomDBSpaceMonitor.EOF
strDatabase = CStr(rsCustomDBSpaceMonitor("DBName").Value)
if rsCustomDBSpaceMonitor("severity").Value = "warning" Then
strSeverityWarning = "Warning"
strList = strList & "warning: " & rsCustomDBSpaceMonitor("type").Value & " " & strDatabase & " Percentage Used: " & rsCustomDBSpaceMonitor("percentage_used").Value & ", "
elseif rsCustomDBSpaceMonitor("severity").Value = "critical" Then
strSeverityCritical = "Critical"
strList = strList & "Critical: " & rsCustomDBSpaceMonitor("type").Value & " " & strDatabase & " Percentage Used: " & rsCustomDBSpaceMonitor("percentage_used").Value & ", "
else
strSeverityHealthy = "Healthy"
End If
' wscript.echo "percentage used " & rsCustomDBSpaceMonitor("percentage_used").Value
Err.Clear
rsCustomDBSpaceMonitor.MoveNext
' if 0 <> Err.number then Exit Do
loop
' clean up connection
rsCustomDBSpaceMonitor.close
cnADOConnection.close
' Set SCOM parameters
Set oAPI = CreateObject("MOM.ScriptAPI")
' set state depending on Free space (order of next statemenst is important, if only in one row the state is critical, the state will be critical)
If strSeverityHealthy = "Healthy" Then strStatus = "Healthy"
If strSeverityWarning = "Warning" Then strStatus = "Warning"
If strSeverityCritical = "Critical" Then strStatus = "Critical"
If strStatus = "Critical" Then
' wscript.echo strList
Call oAPI.LogScriptEvent("SBPDBFreeSpaceMonitor", 3000, EVENT_TYPE_ERROR, "The Following datafiles are low on free space:" & strList)
ElseIf strStatus = "Warning" Then
' wscript.echo strList
Call oAPI.LogScriptEvent("SBPDBFreeSpaceMonitor", 3001, EVENT_TYPE_WARNING, "The Following datafiles are low on free space:" & strList)
Else
' wscript.echo "healthy"
Call oAPI.LogScriptEvent("SBPDBFreeSpaceMonitor", 3002, EVENT_TYPE_INFORMATION, "All datafiles on " & sConnectionString & " have enough free space")
End If
' Return values to SCOM to set state and generate Alert
Set propertyBag = oAPI.CreatePropertyBag ()
Call propertyBag.AddValue ("Status", strStatus)
Call propertyBag.AddValue ("DBList", strList)
Call oAPI.Return(propertyBag)
I don’t believe this works on databases which for example have multiple data files. It will report on each data file seperatly instead of on the sum of each. So for example, if I have a database with two data files, the first being 99% full and the second 5%, the health of the database as a whole is ok since there is plenty of space. Not the case with the above script.
That’s my only complaint
Awesome otherwise.