SQL Agent Job Logs – Can’t get the Error Log
Question
I’ve some logs that I want to extract to a report in order to get the SQL_Agent_Jobs status that runs during the night. If the Job fails then I want to receive the Error Log in a table. I am trying to get that information with this query:
DECLARE @job_id UNIQUEIDENTIFIER
SELECT
@job_id = job_id FROM msdb.dbo.sysjobs
WHERE
[name] like '%JOB_1%'
OR [name] like '%JOB_2%'
OR [name] like '%JOB_3%'
OR [name] like '%JOB_4%'
OR [name] like '%JOB_5%'
;WITH Error_Output (job_id, error_log) AS
(
SELECT
JS.job_id,
CASE
WHEN JSL.[log] IS NULL THEN JH.[Message]
ELSE JSL.[log]
END AS LogOutput
FROM
msdb.dbo.sysjobsteps JS
INNER JOIN msdb.dbo.sysjobhistory JH
ON JS.job_id = JH.job_id AND JS.step_id = JH.step_id
LEFT OUTER JOIN msdb.dbo.sysjobstepslogs JSL
ON JS.step_uid = JSL.step_uid
WHERE
INSTANCE_ID >
(SELECT
MIN(INSTANCE_ID)
FROM
(SELECT top (2)
INSTANCE_ID, job_id
FROM
msdb.dbo.sysjobhistory
WHERE
job_id = @job_id
AND STEP_ID = 0
ORDER BY
INSTANCE_ID desc
) A
)
AND JS.step_id <> 0
AND JH.job_id = @job_id
AND JH.run_status = 0
)
SELECT
sj.name AS [Job Name]
,MAX(sja.run_requested_date) AS [Start Date]
,MAX(sja.start_execution_date) AS [Effective Start Date]
,MAX(sja.stop_execution_date) AS [Effective End Date]
,DATEDIFF(MINUTE, MAX(sja.start_execution_date), MAX(sja.stop_execution_date)) as [Job Execution Time - M]
,CASE WHEN error_log IS NULL THEN 'Job runs successfully' else error_log end as [Job Log]
FROM
msdb.dbo.sysjobactivity AS sja
INNER JOIN msdb.dbo.sysjobs AS sj ON sja.job_id = sj.job_id
LEFT OUTER JOIN Error_Output AS error ON error.job_id = sja.job_id AND error.job_id = sj.job_id
WHERE
[name] like '%JOB_1%'
OR [name] like '%JOB_2%'
OR [name] like '%JOB_3%'
OR [name] like '%JOB_4%'
OR [name] like '%JOB_5%'
GROUP BY
sj.name, error_log
However, I’m always getting that the Job runs ‘Job runs successfully’ and I already test and see that the job failed in execution. I even configured SQL_Agent_Job to receive email whenever the job failed, and I have received the emails and the status in the query does not change to the error log (failed).
What I’m doing wrong?
asked 2017-06-25 by John_Rodgers
Answer
I have written a post about retrieving job status from msdb, which you can see here. The code in that post does not pull in data from dbo.sysjobstepslogs, but it’s pretty straightforward to extend that code to pull in the last error message from dbo.sysjobstepslogs if you are logging to that table.
By default, job steps do not log to msdb. To configure your job steps to log to dbo.sysjobstepslogs, you must go into the job step properties for every step in the job, visit the “Advanced” tab, and select the option for “Log to table”:

You can then create this Table-Valued Function to get the most recent job status. I’ve modified the code from the post above to also pull the most recent error from the job, if it is available:
CREATE FUNCTION dbo.SqlAgentJob_GetStatus (@JobName sysname)
RETURNS TABLE
AS
RETURN
SELECT TOP 1
JobName = j.name,
IsRunning = CASE
WHEN ja.job_id IS NOT NULL
AND ja.stop_execution_date IS NULL
THEN 1 ELSE 0
END,
RequestSource = ja.run_requested_source,
LastRunTime = ja.start_execution_date,
NextRunTime = ja.next_scheduled_run_date,
LastJobStep = js.step_name,
RetryAttempt = jh.retries_attempted,
JobLastOutcome = CASE
WHEN ja.job_id IS NOT NULL
AND ja.stop_execution_date IS NULL THEN 'Running'
WHEN jh.run_status = 0 THEN 'Failed'
WHEN jh.run_status = 1 THEN 'Succeeded'
WHEN jh.run_status = 2 THEN 'Retry'
WHEN jh.run_status = 3 THEN 'Cancelled'
END,
LastError = (SELECT TOP 1 jsl.log
FROM msdb.dbo.sysjobstepslogs jsl
WHERE jsl.step_uid = js.step_uid
AND jsl.date_modified >= ja.start_execution_date)
FROM msdb.dbo.sysjobs j
LEFT JOIN msdb.dbo.sysjobactivity ja
ON ja.job_id = j.job_id
AND ja.run_requested_date IS NOT NULL
AND ja.start_execution_date IS NOT NULL
LEFT JOIN msdb.dbo.sysjobsteps js
ON js.job_id = ja.job_id
AND js.step_id = ja.last_executed_step_id
LEFT JOIN msdb.dbo.sysjobhistory jh
ON jh.job_id = j.job_id
AND jh.instance_id = ja.job_history_id
WHERE j.name = @JobName
ORDER BY ja.start_execution_date DESC;
GO
Finally, you can leverage the TVF to query for your job status, last step to run, last logged error, etc:
--Specific jobs
SELECT sts.*
FROM msdb.dbo.sysjobs j
CROSS APPLY dbo.SqlAgentJob_GetStatus (j.name) sts
WHERE
j.[name] like '%JOB_1%'
OR j.[name] like '%JOB_2%'
OR j.[name] like '%JOB_3%'
OR j.[name] like '%JOB_4%'
OR j.[name] like '%JOB_5%';
--Failed Jobs
SELECT sts.*
FROM msdb.dbo.sysjobs j
CROSS APPLY dbo.SqlAgentJob_GetStatus (j.name) sts
WHERE sts.JobLastOutcome <> 'Succeeded';
answered 2017-06-25 by Andy Mallon
