Sql server SQL Server日志记录失败的查询
我正在尝试实现一个系统范围的日志记录,它将在我们的dabatase中记录所有失败的存储过程执行,我正在查看扩展事件 我做了一些研究,似乎很容易使用以下代码捕获失败的语句:Sql server SQL Server日志记录失败的查询,sql-server,stored-procedures,dbcc,extended-events,Sql Server,Stored Procedures,Dbcc,Extended Events,我正在尝试实现一个系统范围的日志记录,它将在我们的dabatase中记录所有失败的存储过程执行,我正在查看扩展事件 我做了一些研究,似乎很容易使用以下代码捕获失败的语句: --Create an extended event session CREATE EVENT SESSION what_queries_are_failing ON SERVER ADD EVENT sqlserver.error_reported ( ACTION (sqlserver.sql_text
--Create an extended event session
CREATE EVENT SESSION what_queries_are_failing ON SERVER
ADD EVENT sqlserver.error_reported (
ACTION (sqlserver.sql_text
, sqlserver.tsql_stack
, sqlserver.database_id
, sqlserver.username
)
WHERE ([severity] > 10)
)
ADD TARGET package0.asynchronous_file_target (
SET filename = 'C:\XEventSessions\what_queries_are_failing.xel'
, metadatafile = 'C:\XEventSessions\what_queries_are_failing.xem'
, max_file_size = 5
, max_rollover_files = 5
)
WITH (MAX_DISPATCH_LATENCY = 5 SECONDS)
GO
-- Start the session
ALTER EVENT SESSION what_queries_are_failing ON SERVER STATE = START
GO
;WITH events_cte
AS (
SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP), xevents.event_data.value('(event/@timestamp)[1]', 'datetime2')) AS [err_timestamp]
, xevents.event_data.value('(event/data[@name="severity"]/value)[1]', 'bigint') AS [err_severity]
, xevents.event_data.value('(event/data[@name="error_number"]/value)[1]', 'bigint') AS [err_number]
, xevents.event_data.value('(event/data[@name="message"]/value)[1]', 'nvarchar(512)') AS [err_message]
, xevents.event_data.value('(event/action[@name="sql_text"]/value)[1]', 'nvarchar(max)') AS [sql_text]
, xevents.event_data
FROM sys.fn_xe_file_target_read_file('S:\XEventSessions\what_queries_are_failing*.xel', 'S:\XEventSessions\what_queries_are_failing*.xem', NULL, NULL)
CROSS APPLY (
SELECT CAST(event_data AS XML) AS event_data
) AS xevents
)
SELECT *
FROM events_cte
ORDER BY err_timestamp;
然而,我想立即将失败的语句存储到一个表中,我们称之为Logs。错误,但我找不到方法,上面的方法必须作为计划作业来工作
现在,我们的程序是这样的:
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
SELECT 1;
END TRY
BEGIN CATCH
EXECUTE Logs.PrintError;
EXECUTE Logs.LogError;
END CATCH
END
其中Logs.LogError
过程正在使用DBCC INPUTBUFFER()代码>但它不捕获参数,只捕获执行的确切过程。这就是我能从中得到的:
+----------------------------+-----------+-----------+------------------------------+
| ErrorMessage | EventType | Parameter | Statement |
+----------------------------+-----------+-----------+------------------------------+
| Incorrect syntax near '.'. | RPC Event | 0 | DbName.dbo.FailedProcedure;1 |
+----------------------------+-----------+-----------+------------------------------+
我正在寻找一种方法,通过强制它捕获整个语句或XE将记录直接插入到某个表中(如果可能的话),使DBCC INPUTBUFFER()
工作
任何问题-请告诉我。我发现XEvents非常适合监控事件的发生。但是,它们不提供“处理”观察到的事件的机制。为了填补这个空白,我使用了。我经常将它们描述为异步DDL触发器。我会让你决定,如果tl;dr
定义是否准确
如果您想尝试使用事件通知,可以从下面的脚本开始(抱歉,太长了)。如果您有任何问题,请告诉我。我会尽力回答你
--Create these objects within a database that has service broker enabled.
USE DbaData
GO
--Drop objects first before trying to create them (in specific sequence).
IF EXISTS (
SELECT *
FROM sys.services
WHERE name = 'svcUserErrorReportedNotification'
)
DROP SERVICE svcUserErrorReportedNotification;
GO
IF EXISTS (
SELECT *
FROM sys.service_queues
WHERE name = 'queUserErrorReportedNotification'
)
DROP QUEUE queUserErrorReportedNotification;
GO
IF EXISTS (
SELECT *
FROM sys.server_event_notifications
WHERE name = 'enUserErrorReportedEvents'
)
DROP EVENT NOTIFICATION enUserErrorReportedEvents
ON SERVER
GO
--Create a queue just for user error events.
CREATE QUEUE queUserErrorReportedNotification
GO
--Create a service just for user error events.
CREATE SERVICE svcUserErrorReportedNotification
ON QUEUE queUserErrorReportedNotification ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification])
GO
-- Create the event notification for user error events on the service.
CREATE EVENT NOTIFICATION enUserErrorReportedEvents
ON SERVER
WITH FAN_IN
FOR USER_ERROR_MESSAGE
TO SERVICE 'svcUserErrorReportedNotification', 'current database';
GO
IF EXISTS (
SELECT *
FROM INFORMATION_SCHEMA.ROUTINES r
WHERE r.ROUTINE_SCHEMA = 'dbo' AND r.ROUTINE_NAME = 'ReceiveUserErrorReportedEvent'
)
DROP PROCEDURE dbo.ReceiveUserErrorReportedEvent
GO
CREATE PROCEDURE dbo.ReceiveUserErrorReportedEvent
/*****************************************************************************
* Name : dbo.ReceiveUserErrorReportedEvent
* Purpose : Runs when there is a USER_ERROR_MESSAGE event.
* Inputs : None
* Outputs : None
* Returns : Nothing
******************************************************************************
* Change History
* 11/28/2016 DMason Created
******************************************************************************/
AS
BEGIN
SET NOCOUNT ON
DECLARE @MsgBody XML
WHILE (1 = 1)
BEGIN
BEGIN TRANSACTION
-- Receive the next available message FROM the queue
WAITFOR (
RECEIVE TOP(1) -- just handle one message at a time
@MsgBody = CAST(message_body AS XML)
FROM queUserErrorReportedNotification
), TIMEOUT 1000 -- if the queue is empty for one second, give UPDATE and go away
-- If we didn't get anything, bail out
IF (@@ROWCOUNT = 0)
BEGIN
ROLLBACK TRANSACTION
BREAK
END
ELSE
BEGIN
--Grab some relevant items from the message body XML (it is EVENTDATA(), btw)
DECLARE @Login SYSNAME;
DECLARE @ErrMsgText VARCHAR(MAX);
DECLARE @ApplicationName VARCHAR(MAX);
DECLARE @Severity INT;
DECLARE @ErrorNumber INT;
DECLARE @DBName SYSNAME;
SET @Login = @MsgBody.value('(/EVENT_INSTANCE/LoginName)[1]', 'VARCHAR(128)' );
SET @ErrMsgText = @MsgBody.value('(/EVENT_INSTANCE/TextData)[1]', 'VARCHAR(MAX)' );
SET @ApplicationName = @MsgBody.value('(/EVENT_INSTANCE/ApplicationName)[1]', 'VARCHAR(MAX)' );
SET @Severity = @MsgBody.value('(/EVENT_INSTANCE/Severity)[1]', 'INT' );
SET @ErrorNumber = @MsgBody.value('(/EVENT_INSTANCE/Error)[1]', 'INT' );
SET @DBName = @MsgBody.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'VARCHAR(128)' );
--Do stuff here.
--Log to a table, etc.
/*
Commit the transaction. At any point before this, we
could roll back -- the received message would be back
on the queue AND the response wouldn't be sent.
*/
COMMIT TRANSACTION
END
END
END
GO
ALTER QUEUE dbo.queUserErrorReportedNotification
WITH
STATUS = ON,
ACTIVATION (
PROCEDURE_NAME = dbo.ReceiveUserErrorReportedEvent,
STATUS = ON,
MAX_QUEUE_READERS = 1,
EXECUTE AS OWNER)
GO
你能详细说明一下上面的方法必须按计划工作。
@游戏是肯定的。我认为扩展事件可以在后台运行,并将失败的查询信息存储到给定的文件中。然后根据时间表(比如每小时一次),我可以读取该文件并将记录插入Logs.Errors
表中。现在它更有意义了吗?你不需要像作业一样运行扩展事件开始和停止事件,一旦你启动它,它就会在后台运行。你可以使用批启动、停止事件,看看我在dba.se上的答案。这也可能会有帮助:哦,孩子。这正是我要找的。我会在我的本地机器上尝试,并在可能的时候提供反馈。谢谢我刚刚想到的一件事……用户错误消息可能会产生很多“噪音”。它包括所有严重级别的错误(我认为)。例如,您可能会发现大量严重级别低于10的“错误”事件,而您可能并不关心这些事件。这可能会以SQL无法处理的速度淹没队列。是否可以只筛选高于特定严重性的失败过程?这真是太棒了,感觉您已将我引导到正确的路径。谢谢!不客气!如果遇到问题,请在此处添加一些注释。如果有任何遗漏或其他错误,我很乐意更新脚本/答案。