Запись стека вызовов SQL Server при сообщении об ошибках - PullRequest
6 голосов
/ 18 января 2010

Это продолжение вопроса Вложенные хранимые процедуры, содержащие шаблон TRY CATCH ROLLBACK?

В блоке перехвата я использую хранимую процедуру для сообщения (ререйзирования) ошибки путем чтения из ERROR_MESSAGE (), ERROR_PROCEDURE (), ERROR_LINE () и т. Д. Как описано здесь У меня также есть проверка чтобы он мог определить, была ли ошибка повторно обработана (это происходит с вложенными хранимыми процедурами, когда информация об ошибке передается через каждый блок TRY CATCH).

То, что я хотел бы сделать, либо непосредственно в «ReportError», либо косвенно с моим шаблоном (как описано в первом вопросе), это запись трассировки стека - поэтому, когда ReportError обнаруживает, что он получает ошибку, выданную самому себе , он добавляет следующий уровень стека к сообщению об ошибке. Это помогло бы мне избежать случаев, когда я вижу сообщение об ошибке из какой-нибудь маленькой служебной хранимой процедуры, без какого-либо способа узнать, как она вызывается. Если я попытаюсь сделать это непосредственно в ReportError, произойдет сбой, так как повторно отправленная ошибка сообщает о себе как о ReportError - видна только исходная ошибка.

Есть ли способ для ReportError выполнить трассировку стека в SQL Server, не передавая аргумент каждой хранимой процедуре и не поддерживая вручную такую ​​трассировку с помощью таблицы #temp? По сути, я хочу рекурсивный вызов ERROR_PROCEDURE () и ERROR_LINE ().

Ответы [ 2 ]

1 голос
/ 18 января 2010

Хорошо, я добавлю нашу обработку ошибок обратно в: -)

Функции ERROR _% () видны в области видимости блока CATCH. Это означает, что вы можете использовать их в хранимых процедурах или вызовах функций в каждом блоке CATCH

А для вложенных хранимых процедур полезно знать, что вызвало ошибку и что регистрирует ошибку

...
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    EXEC dbo.MyExceptionHandler @@PROCID, @errmsg OUTPUT;
    RAISERROR (@errmsg, 16, 1);
END CATCH

---with this handler (cut down version of ours)
CREATE PROCEDURE dbo.MyExceptionHandler
    @CallerProcID int,
    @ErrorMessage varchar(2000) OUTPUT
WITH EXECUTE AS OWNER --may be needed to get around metadata visibility issues of OBJECT_NAME
AS
SET NOCOUNT, XACT_ABORT ON;

BEGIN TRY
    SET @ErrorMessage = --cutdown
            CASE
                WHEN @errproc = @callerproc THEN        --Caller = error generator
                        --build up stuff

                ELSE    --Just append stuff             --Nested error stack
            END;

    IF @@TRANCOUNT = 0
        INSERT dbo.Exception (Who, TheError, WhatBy, LoggedBy)
        VALUES (ORIGINAL_LOGIN()), RTRIM(ERROR_MESSAGE()), ERROR_PROCEDURE(), OBJECT_NAME(@CallerProcID));
END TRY
BEGIN CATCH
   --and do what exactly?
END CATCH
GO

В любом случае, это основная идея: каждый блок CATCH прост, работа продолжается в обработчике ошибок. Например, добавьте ERROR_NUMBER(), если хотите

0 голосов
/ 18 января 2010

Ограниченным ответом на это будет передача OBJECT_NAME (@@ PROCID) процедуре ReportError - когда ReportError обнаруживает, что получает рекурсивную ошибку (ошибку, выданную сама по себе), он может использовать это значение и добавить его к сообщение об ошибке, обеспечивающее частичную трассировку стека (в трассировке стека не будет номеров строк, кроме первого элемента)

...