web-dev-qa-db-ja.com

動的SQLバックアップコマンドにtry / catchを使用するときにエラーの詳細をログに記録する方法

Try catchと動的SQLを使用するストアドプロシージャ内でバックアップコマンドを発行する場合、バックアップコマンドを直接実行する場合と比較すると、エラーメッセージは非常に一般的です。

SP内で試行/キャッチ:

    begin try
        execute sp_executesql @sql;  -- a backup command
    end try
    begin catch  
        print ERROR_MESSAGE();  -- save to log, etc.
    end catch

結果

50000:usp_Backup:117:BACKUP DATABASEが異常終了しています。

rawコマンドを発行するwheareas:

    backup DATABASE someDb to disk...

より詳細な結果:

ルックアップエラー-SQL Serverデータベースエラー:ファイル "H:\ FolderName\Filename.bak:" 112で回復不可能なI/Oエラーが発生しました(ディスクに十分なスペースがありません。).

これらの詳細をストアドプロシージャ内の変数にキャッチする方法はありますか(ログを記録し、呼び出し元に戻し、再試行ロジックのために)?詳細はメッセージチャネルで送信されているようですが、SP内で利用できるようにしたいと思います。

10
crokusek

BACKUP DATABASEがエラーを生成すると、実際には2つ生成されます。残念ながら、TRY/CATCHは最初のエラーをキャプチャできません。 2番目のエラーのみをキャプチャします。

バックアップが失敗した本当の理由をキャプチャする最善の策は、バックアップを自動化することです [〜#〜] sqlcmd [〜#〜]-oを使用して出力をファイル)、SSIS、C#、PowerShellなど。これらすべてを使用すると、エラーのキャプチャallを大幅に制御できます。

SOコメントの回答はDBCC OUTPUTBUFFERの使用を提案しています-可能ですが、これは子供の遊びのようには見えません。自由に楽しんでください この手順Erland Sommarskogのサイト ですが、これはTRY/CATCHと組み合わせてもまだうまく機能しないようです。

spGET_LastErrorMessageを使用してエラーメッセージをキャプチャできるように思われた唯一の方法は、実際のエラーがスローされた場合です。 TRY/CATCHでラップすると、エラーが飲み込まれ、ストアドプロシージャは何もしません。

BEGIN TRY
  EXEC sp_executesql N'backup that fails...';
END TRY
BEGIN CATCH
  EXEC dbo.spGet_LastErrorMessage;
END CATCH

SQL Server <2012では、エラーを自分で再発生させることはできませんが、SQL Server 2012以降では可能です。したがって、次の2つのバリエーションが機能します。

CREATE PROCEDURE dbo.dothebackup
AS
BEGIN
  SET NOCOUNT ON;
  EXEC sp_executesql N'backup that fails...';
END
GO

EXEC dbo.dothebackup;
EXEC dbo.spGET_LastErrorMessage;

または2012年以降、これは機能しますが、元のエラーがまだスローされるため、TRY/CATCHの目的を大幅に無効にします。

CREATE PROCEDURE dbo.dothebackup2
AS
BEGIN
  SET NOCOUNT ON;
  BEGIN TRY
    EXEC sp_executesql N'backup that fails...';
  END TRY
  BEGIN CATCH
    THROW;
  END CATCH
END
GO

EXEC dbo.dothebackup2;
EXEC dbo.spGET_LastErrorMessage;

これらのどちらの場合でも、もちろん、エラーはクライアントにスローされます。そのため、それを回避するためにTRY/CATCHを使用している場合は、考えていない抜け穴がない限り、ユーザーにエラーを与えて、それに関する詳細をキャプチャしたり、エラーと実際の理由の両方を抑制したりできます。

13
Aaron Bertrand

まあ、これは古いスレッドであり、私が提案しようとしているのは複雑なハックであることはわかっていますが、誰かを助けることができる場合に備えて、これらのバックアップエラーがログに記録されるため、catchでxp_readerrorlogを使用できますブロックして関連メッセージ(エラーまたは情報)のログを取得します。 xp_readerrorlog paramsを探し回ることができますが、簡単に言うと、この場合に役立つ検索文字列と開始時間フィルターを指定できます。これが再試行ロジックに役立つかどうかはわかりませんが、ログの情報またはエラーをキャプチャするために、私はこのようなものを思いつきました...

IF OBJECT_ID('tempdb.dbo.#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (LogDate datetime,ProcessInfo nvarchar(100),LogText nvarchar(4000))
BEGIN TRY
SELECT @begintime = GETDATE()
EXEC sp_executesql @SQL --your backup statement string
INSERT #Results
EXEC  xp_readerrorlog 0, 1, N'backed up',@databasename,@begintime
SELECT @result = LogText from #Results where ProcessInfo = 'Backup' order by logdate desc
END TRY
BEGIN CATCH
INSERT #Results
EXEC  xp_readerrorlog 0, 1, N'Backup',@databasename,@begintime
SELECT @result = LogText from #Results where ProcessInfo = 'spid'+cast(@@SPID as varchar(6)) order by logdate desc
END CATCH
PRINT @result

HTH

2
Andy McD

エラーの詳細をテーブルに記録できます。ログファイルを作成することもできますが、そのためにはCLRまたはxp_cmdshellが必要になる場合があります。データベースメールを送信することもできますが、これはスパムの問題を引き起こす可能性があり、適切なログではありません。

表は最も単純です。

  1. エラーを格納するためのテーブルを作成する
  2. エラーテーブルに挿入するストアドプロシージャを作成する
  3. キャッチブロックでストアドプロシージャを呼び出す

以下のリンクで提供されているJeremy Kadlecの例をご覧ください。

http://www.mssqltips.com/sqlservertip/1152/standardized-sql-server-error-handling-and-centralized-logging/

0
brian