You are currently viewing Send email when log or data file grows
Microsoft SQL Server

Send email when log or data file grows

One way to keep track of your data- and log file sizes in SQL Server, is to send an email notification whenever a file growth occurs.

If you can learn at which times file growth occurs, you may be able to dig out the root cause (e.g. long running queries) for file expansions. Note that file expansions are not necessarily a problem however. The cause may just be normal linear growth. But if you suspect that some process(es) is responsible for a large part of the growth, the method described here may be useful.

The solution uses the Default Trace in SQL Server to list the latest file growth events. When such events are detected, an email with the new events since last email is sent. The mail uses a HTML table in the mail body.

I suggest running the job every 10 minutes from SQL Agent. Create a job step with the following T-SQL. You’ll need to change the parameter settings on the msdb.dbo.sp_send_dbmail procedure.

IF (SELECT OBJECT_ID('tempdb..#TLind_LOG_GROWTH_EVENTS')) IS NULL BEGIN
    CREATE TABLE #TLind_LOG_GROWTH_EVENTS
        (
			DatabaseName NVARCHAR(128) NOT NULL
			,FileName NVARCHAR(256) NOT NULL
			,HostName NVARCHAR(256) NULL
			,ApplicationName NVARCHAR(256) NULL
			,LoginName NVARCHAR(256) NULL
			,StartTime DATETIME NULL
			,EndTime DATETIME NULL
			,ChangeSize NUMERIC(10,2) NULL
			,EmailSent DATETIME NULL
        )

	CREATE UNIQUE CLUSTERED INDEX TLind_LOG_GROWTH_EVENTS_CLU ON #TLind_LOG_GROWTH_EVENTS (DatabaseName,StartTime DESC, EndTime)
	CREATE INDEX TLind_LOG_GROWTH_EVENTS_EmailSent_IDX ON #TLind_LOG_GROWTH_EVENTS (EmailSent)
END

INSERT #TLind_LOG_GROWTH_EVENTS
SELECT DISTINCT DB_NAME(DatabaseID) AS DatabaseName
	,[FileName]
	,HostName
	,ApplicationName
	,LoginName
	,StartTime
	,EndTime
	,CAST((IntegerData*8.0/1024) AS NUMERIC(10,2)) AS ChangeSize
	,NULL AS EmailSent
FROM
    ::fn_trace_gettable((SELECT LEFT([path], LEN([path]) - PATINDEX('%\%', REVERSE([path]))) + '\log.trc' FROM sys.traces WHERE is_default = 1), DEFAULT) AS TRC
WHERE
	TRC.EventClass IN (92,93)
AND
	NOT EXISTS
		(
			SELECT *
			FROM #TLind_LOG_GROWTH_EVENTS PREV_TRC
			WHERE PREV_TRC.DatabaseName = TRC.DatabaseName
			AND PREV_TRC.StartTime >= TRC.StartTime
		)

IF @@ROWCOUNT > 0 BEGIN
	DECLARE @MAIL_BODY VARCHAR(MAX)
 
	/* HEADER */
	SET @MAIL_BODY = '<table border="1" align="center" cellpadding="2" cellspacing="0" style="color:black;font-family:consolas;text-align:center;">' +
		'<tr>
		<th>DatabaseName</th>
		<th>FileName</th>
		<th>HostName</th>
		<th>ApplicationName</th>
		<th>LoginName</th>
		<th>StartTime</th>
		<th>EndTime</th>
		<th>ChangeSizeMB</th>
		</tr>'
 
	/* ROWS */
	SELECT
		@MAIL_BODY = @MAIL_BODY +
			'<tr>' +
			'<td>' + DatabaseName + '</td>' +
			'<td>' + FileName + '</td>' +
			'<td>' + ISNULL(HostName, '...') + '</td>' +
			'<td>' + ISNULL(ApplicationName, '...') + '</td>' +
			'<td>' + ISNULL(LoginName, '...') + '</td>' +
			'<td>' + ISNULL(CONVERT(VARCHAR(19), StartTime, 121), '...') + '</td>' +
			'<td>' + ISNULL(CONVERT(VARCHAR(19), EndTime, 121), '...') + '</td>' +
			'<td>' + ISNULL(CAST(ChangeSize AS VARCHAR(12)), '...') + '</td>' +
			'</tr>'
	FROM
		#TLind_LOG_GROWTH_EVENTS
	WHERE
		EmailSent IS NULL
 
	SELECT @MAIL_BODY = @MAIL_BODY + '</table>'

	SELECT @MAIL_BODY
 
	EXEC msdb.dbo.sp_send_dbmail
		@profile_name = '<YouEmailProfile>',
		@recipients = '<YourEmailRecipients>',
		@subject = 'Log Growth Events on <YourServer> (Table is tempdb..#TLind_LOG_GROWTH_EVENTS. SQL Agent job is <YourSQLAgentJobName>',
		@body = @MAIL_BODY,
		@body_format='HTML'

	UPDATE #TLind_LOG_GROWTH_EVENTS SET EmailSent = GETDATE() WHERE EmailSent IS NULL
END

The email will look something like this example:

Email With Log Growth Events
Email With Log Growth Events

To create file growth events in order to test the solution, run the following script. Preferably on a test server of course.

CREATE DATABASE LogFileAutoGrow
GO

USE LogFileAutoGrow
GO

CREATE TABLE SomeTable (SomeColumn CHAR(8000))
GO

INSERT SOMETABLE
SELECT TOP 2000 CAST('' AS CHAR(8000)) AS SomeColumn
FROM SYS.OBJECTS S1
	CROSS JOIN SYS.OBJECTS S2
	CROSS JOIN SYS.OBJECTS S3

Tomas Lind

Tomas Lind - Consulting services as SQL Server DBA and Database Developer at High Coast Database Solutions AB.

Leave a Reply