当作业失败时,我如何让SQL Server将错误详细信息发送给我的邮箱?

SQL Server允许您配置作业在失败时发送电子邮件提醒。这是一种简单而有效的监控作业的方式。然而,这些提醒并不包含任何详细信息,只有成功或失败的通知。 如果作业失败,典型的提醒电子邮件将如下所示:
JOB RUN:        'DBA - Consistency Check Databases' was run on 8/14/2011 at 12:00:04 AM
DURATION:       0 hours, 0 minutes, 0 seconds
STATUS:         Failed
MESSAGES:       The job failed.  The Job was invoked by Schedule 2 (Nightly Before 
                Backup 12AM).  The last step to run was step 1 (Check Databases).
要确定故障的原因,您需要在SQL Server Management Studio中导航到实例,找到作业,并查看其执行历史记录。在大型环境中,不断这样做可能会很麻烦。 理想的警报电子邮件应该直接提供故障原因,并让您立即开始解决方案。 我对this solution解决方案很熟悉。有人对此有任何经验吗?它的缺点包括: 1. 您必须为每个作业添加一个新步骤, 2. 您必须祈祷没有人弄乱警报过程spDBA_job_notification。 有人想出更好的解决方案吗?
4个回答

有些事情你可能只是一时的想法,抛出一些想法...

创建一个单独的作业,定期检查 msdb 中的作业表,看是否有任何作业失败,可以通过一个良好的 T-SQL 查询 来完成。然后你可以进入 sysjobsteps 表,查看该作业是否设置了输出日志。编写一个存储过程,将该文件作为附件发送电子邮件。这样你就能够从开始到失败完全了解作业的执行情况,而无需触碰服务器。

然后,还可以使用 PowerShell 脚本检查事件日志中的错误。它允许您根据需要筛选消息类型。您可以将其设置为定期运行的 SQL 代理作业。然后在 PowerShell 脚本中使用邮件命令来发送消息(如果找到错误)。

这些都是一些我想到的很牵强的想法。


我有关于上述想法的经验。这个想法不错,但更好的想法是按照Shawn所说的做。

我们所做的是每5分钟运行一次作业,并扫描有关作业失败的MSDB表。对于每个失败的作业,我们将运行存储过程spDBA_job_notification并使用它自己的ID,因此该存储过程将扫描MSDB历史步骤中的错误并将它们全部发送电子邮件。根据该存储过程的文档:“该存储过程使用作业ID查询msdb代理表以获取该作业的最新错误消息。”

所以,不只是更改每个作业,最好创建一个能够完成所有任务的单一作业 ;-).

另一个想法是将所有作业设置为在出现错误/失败时写入Windows事件查看器,并使用扩展proc xp_ReadErrorLog或自动工具从中读取,如果您的网络中已经有这样的工具。例如,我们使用HPOV来检查任何系统问题,并可以为所有事件查看器错误配置一个简单的警报(不需要任何自定义作业或过程)。

试一试,根据需要在TSQL中插入您的变量。关键是将此作为每个单独的SQL代理作业的最后一步,但是上面的每个作业步骤无论是失败还是成功都需要转到下一步... 对我来说大部分情况下都很有效,但如果遇到任何问题,请务必报告。我们使用的是SQL Server 2008 R2,所以目前我已经设置好了。
SELECT  step_name, message
FROM    msdb.dbo.sysjobhistory
WHERE   instance_id > COALESCE((SELECT MAX(instance_id) FROM msdb.dbo.sysjobhistory
                                WHERE job_id = $(ESCAPE_SQUOTE(JOBID)) AND step_id = 0), 0)
        AND job_id = $(ESCAPE_SQUOTE(JOBID))
        AND run_status <> 1 -- success

IF      @@ROWCOUNT <> 0
BEGIN
        RAISERROR('*** SQL Agent Job Prior Step Failure Occurred ***', 16, 1)

DECLARE @job_name NVARCHAR(256) = (SELECT name FROM msdb.dbo.sysjobs WHERE job_id = $(ESCAPE_SQUOTE(JOBID)))
DECLARE @email_profile NVARCHAR(256) = 'SQLServer Alerts'
DECLARE @emailrecipients NVARCHAR(500) = 'EmailAddr@email.com'
DECLARE @subject NVARCHAR(MAX) = 'SQL Server Agent Job Failure Report: ' + @@SERVERNAME
DECLARE @msgbodynontable NVARCHAR(MAX) = 'SQL Server Agent Job Failure Report For: "' + @job_name + '"'

--Dump report data to a temp table to be put into XML formatted HTML table to email out
SELECT sjh.[server]
    ,sj.NAME
    ,sjh.step_id
    ,sjh.[message]
    ,sjh.run_date
    ,sjh.run_time
INTO #TempJobFailRpt
FROM msdb..sysjobhistory sjh
INNER JOIN msdb..sysjobs sj ON (sj.job_id = sjh.job_id)
WHERE run_date = convert(INT, convert(VARCHAR(8), getdate(), 112))
    AND run_status != 4 -- Do not show status of 4 meaning in progress steps
    AND run_status != 1 -- Do not show status of 1 meaning success
    AND NAME = @job_name
ORDER BY run_date

IF EXISTS (
        SELECT *
        FROM #TempJobFailRpt
        )
BEGIN

-----Build report to HTML formatted email using FOR XML PATH
DECLARE @tableHTML NVARCHAR(MAX) = '
<html>
<body>
    <H1>' + @msgbodynontable + '</H1>
        <table border="1" style=
        "background-color: #C0C0C0; border-collapse: collapse">
        <caption style="font-weight: bold">
            ****** 
            Failure occurred in the SQL Agent job named: ''' + @job_name + ''' in at least one of the steps. 
            Below is the job failure history detail for ALL runs of this job today without needing to connect to SSMS to check.
            ******
        </caption>

<tr>
    <th style="width:25%; text-decoration: underline">SQL Instance</th>
    <th style="text-decoration: underline">Job Name</th>
    <th style="text-decoration: underline">Step</th>
    <th style="text-decoration: underline">Message Text</th>
    <th style="text-decoration: underline">Job Run Date</th>
    <th style="text-decoration: underline">Job Run Time</th>
</tr>' + CAST((
            SELECT td = [server]
                ,''
                ,td = NAME
                ,''
                ,td = step_id
                ,''
                ,td = [message]
                ,''
                ,td = run_date
                ,''
                ,td = run_time
            FROM #TempJobFailRpt a
            ORDER BY run_date
            FOR XML PATH('tr')
                ,TYPE
                ,ELEMENTS XSINIL
            ) AS NVARCHAR(MAX)) + '
    </table>
</body>
</html>';

EXEC msdb.dbo.sp_send_dbmail @profile_name = @email_profile
    ,@recipients = @emailrecipients
    ,@subject = @subject
    ,@body = @tableHTML
    ,@body_format = 'HTML'

--Drop Temp table
    DROP TABLE #TempJobFailRpt
END
ELSE
BEGIN
    PRINT '*** No Records Generated ***' 
    DROP TABLE #TempJobFailRpt
END
END

我知道这是一个旧的帖子,但是@Crazy Ivan提供的解决方案非常有效 - 我可以确认它适用于SQL Server 2012。 - Michael


我投票支持这个回答,因为这是我最终选择的解决方案。安装了Tibor的脚本,然后只需添加一个最后的作业步骤来调用它。效果很好。你确实需要将之前的步骤设置为“在失败时跳转到下一步”,并保存输出文件。 - Will