SQL Server扩展事件:关联跟踪失败RPC调用与抛出的异常
关联RPC事件与错误事件以追踪失败的存储过程调用
我之前处理过完全相同的场景——要追踪失败的RPC调用,同时获取存储过程语句、参数和抛出的异常,但卡在了关联不同事件的环节。下面是我验证过的可行方案,核心是利用SQL Server扩展事件中的会话/请求唯一标识来把RPC执行事件和错误事件绑定到同一执行上下文:
1. 创建包含关联字段的扩展事件会话
所有rpc_starting、rpc_completed和error_reported事件都会携带session_id和request_id字段,这两个字段的组合可以唯一标识一个数据库请求。我们可以创建一个扩展事件会话,同时捕获这三类事件,并添加必要的动作来获取所需信息:
CREATE EVENT SESSION [TrackFailedRPC] ON SERVER ADD EVENT sqlserver.rpc_starting( ACTION( sqlserver.sql_text, sqlserver.session_id, sqlserver.request_id, sqlserver.username, sqlserver.rpc_parameters -- 捕获RPC调用的输入/输出参数 ) WHERE ([sqlserver].[is_system]=(0)) -- 排除系统进程 ), ADD EVENT sqlserver.rpc_completed( ACTION( sqlserver.sql_text, sqlserver.session_id, sqlserver.request_id, sqlserver.username, sqlserver.rpc_parameters ) WHERE ([sqlserver].[is_system]=(0)) ), ADD EVENT sqlserver.error_reported( ACTION( sqlserver.sql_text, sqlserver.session_id, sqlserver.request_id, sqlserver.username ) WHERE ( [sqlserver].[is_system]=(0) AND [severity]>=11 -- 只捕获严重程度≥11的错误,可按需调整 ) ) ADD TARGET package0.event_file( SET filename=N'TrackFailedRPC.xel', max_file_size=(5), -- 单个文件最大5GB max_rollover_files=(4) -- 最多保留4个滚动文件 ) WITH (STARTUP_STATE=OFF);
2. 启动会话并捕获数据
创建完成后,启动会话开始捕获数据:
ALTER EVENT SESSION [TrackFailedRPC] ON SERVER STATE = START;
当有失败的RPC调用发生时,相关的事件会被写入指定的.xel文件中。
3. 关联事件并提取所需信息
通过查询扩展事件文件,我们可以用session_id和request_id关联同一请求的RPC事件和错误事件,提取完整的调用语句、参数和异常信息:
WITH EventData AS ( SELECT CAST(event_data AS XML) AS event_data, file_name, file_offset FROM sys.fn_xe_file_target_read_file('TrackFailedRPC*.xel', NULL, NULL, NULL) ), ParsedEvents AS ( SELECT event_data.value('(event/@name)[1]', 'NVARCHAR(100)') AS EventName, event_data.value('(event/action[@name="session_id"]/value)[1]', 'INT') AS SessionID, event_data.value('(event/action[@name="request_id"]/value)[1]', 'INT') AS RequestID, event_data.value('(event/action[@name="sql_text"]/value)[1]', 'NVARCHAR(MAX)') AS FullRPCStatement, event_data.value('(event/action[@name="rpc_parameters"]/value)[1]', 'NVARCHAR(MAX)') AS RPCParameters, event_data.value('(event/data[@name="error_number"]/value)[1]', 'INT') AS ErrorNumber, event_data.value('(event/data[@name="message"]/value)[1]', 'NVARCHAR(MAX)') AS ErrorMessage, event_data.value('(event/@timestamp)[1]', 'DATETIME2') AS EventTimestamp FROM EventData ) SELECT pe_rpc.EventTimestamp AS RPCTimestamp, pe_rpc.FullRPCStatement, pe_rpc.RPCParameters, pe_error.EventTimestamp AS ErrorTimestamp, pe_error.ErrorNumber, pe_error.ErrorMessage FROM ParsedEvents pe_rpc JOIN ParsedEvents pe_error ON pe_rpc.SessionID = pe_error.SessionID AND pe_rpc.RequestID = pe_error.RequestID WHERE pe_rpc.EventName IN ('rpc_starting', 'rpc_completed') AND pe_error.EventName = 'error_reported' ORDER BY pe_rpc.EventTimestamp DESC;
4. 关键注意事项
- 过滤条件优化:如果你的环境并发量高,建议在扩展事件会话中添加更具体的过滤条件(比如指定目标数据库、存储过程名称或用户),避免生成过大的事件文件。
- 错误匹配:同一个请求可能会触发多个
error_reported事件,建议通过EventTimestamp的先后顺序来匹配对应RPC调用的错误。 - 实时监控:如果需要实时追踪,可以将目标改为
package0.ring_buffer,或者集成到SQL Server Management Studio的扩展事件查看器中。
内容的提问来源于stack exchange,提问作者Juozas
相关产品推荐
相关产品推荐

