Cách ghi nhật ký chi tiết lỗi khi sử dụng try / Catch cho các lệnh sao lưu SQL động


10

Khi ban hành lệnh sao lưu trong một thủ tục được lưu trữ sử dụng lệnh thử bắt và sql động, các thông báo lỗi rất chung chung khi so sánh với việc chạy trực tiếp lệnh sao lưu.

Thử / Bắt trong SP:

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

Kết quả trong

50000: usp_Backup: 117: BACKUP DATABASE đang chấm dứt bất thường.

wheareas ban hành lệnh thô:

    backup DATABASE someDb to disk...

Kết quả chi tiết tốt hơn:

Lỗi tra cứu - Lỗi cơ sở dữ liệu máy chủ SQL: Xảy ra lỗi I / O không thể phục hồi trên tệp "H: \ FolderName \ Filename.bak:" 112 (Không có đủ dung lượng trên đĩa.).

Có cách nào để bắt các chi tiết này thành các biến trong thủ tục được lưu trữ (để ghi nhật ký, chuyển lại cho người gọi, để thử lại logic) không? Có vẻ như các chi tiết đang xuất hiện trên kênh tin nhắn nhưng tôi muốn chúng có sẵn trong SP.


Bạn có thể muốn thấy điều này: stackoverflow.com/questions/5966670/
Kẻ

Câu trả lời:


13

Khi BACKUP DATABASEtạo ra một lỗi, nó thực sự tạo ra hai. Thật không may TRY/CATCHlà không có khả năng bắt lỗi đầu tiên; nó chỉ bắt lỗi thứ hai.

Tôi nghi ngờ đặt cược tốt nhất của bạn để nắm bắt được lý do thực sự đằng sau một bản sao lưu thất bại là để tự động sao lưu của bạn thông qua SQLCMD (với -ođể gửi đầu ra vào một tập tin), SSIS, C #, PowerShell vv Tất cả trong số đó sẽ cung cấp cho bạn kiểm soát tốt hơn nhiều so với chụp tất cả của các lỗi.

Câu trả lời SO trong bình luận gợi ý sử dụng DBCC OUTPUTBUFFER- trong khi có thể, điều này dường như không giống như trò chơi trẻ con. Hãy vui vẻ với thủ tục này từ trang web của Erland Sommarskog , nhưng điều này dường như vẫn không hoạt động tốt khi kết hợp với TRY/CATCH.

Cách duy nhất tôi dường như có thể nắm bắt được thông báo lỗi spGET_LastErrorMessagelà nếu lỗi thực tế bị ném. Nếu bạn bọc nó trong một TRY/CATCHlỗi sẽ bị nuốt và quy trình được lưu trữ không làm gì:

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

Trong SQL Server <2012, bạn không thể tự khắc phục lỗi, nhưng bạn có thể trong SQL Server 2012 trở lên. Vì vậy, hai biến thể này hoạt động:

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;

Hoặc trong năm 2012 trở lên, điều này hoạt động, nhưng ở một mức độ lớn đánh bại mục đích TRY/CATCH, vì lỗi ban đầu vẫn bị ném:

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;

Trong cả hai trường hợp này, lỗi vẫn được ném cho khách hàng, tất nhiên. Vì vậy, nếu bạn đang sử dụng TRY/CATCHđể tránh điều đó, trừ khi có một kẽ hở nào đó tôi không nghĩ tới, tôi sợ bạn sẽ phải đưa ra lựa chọn ... hoặc cung cấp cho người dùng lỗi và có thể nắm bắt chi tiết về nó, hoặc ngăn chặn cả lỗi và lý do thực tế.


Vô lý như nó là, cách tiếp cận Sommarskog dường như không có vấn đề nếu tôi chỉ muốn cung cấp một số bối cảnh cho người gọi trong một giao diện. Tốt hơn là bắt đầu một quá trình riêng biệt. Bạn có nói rằng nó sẽ không hoạt động trong TRY / CATCH?
crokusek

@crokusek Tôi đã thử một biến thể và kết quả trở nên trống rỗng. Tôi sẽ cho nó một shot khác ngày hôm nay.
Aaron Bertrand

Trong trường hợp không có lỗi, LastErrorMessage () có nhận được kết quả của bất kỳ lỗi nào trước đó từ phiên không? Sau đó, nếu hai lệnh thực thi cuối cùng được chạy dưới dạng tập lệnh, có lẽ lệnh thực thi đầu tiên có thể được gói trong một lần thử / bắt và trong phạm vi bắt, đặt một biến, sau đó ném lại. Sau đó, LastError chỉ được gọi nếu biến được đặt. Giả sử việc ném lại không bỏ qua cuộc gọi thứ 2 mà tôi nghĩ thường đúng trong bối cảnh kịch bản. Cuối cùng tôi vẫn không thể sử dụng phương pháp này vì tất cả đều không thể được đặt trong SP nếu tôi hiểu đúng. Cảm ơn mặc dù!
crokusek

2

Tôi biết đây là một chủ đề cũ và tôi biết những gì tôi sắp đề xuất là một bản hack phức tạp, nhưng trong trường hợp nó có thể giúp bất cứ ai, thì đây là: Vì những lỗi sao lưu này đã được ghi lại, bạn có thể sử dụng xp_readerrorlog trong phần bắt chặn để cạo nhật ký cho tin nhắn liên quan (lỗi hoặc thông tin). Bạn có thể google xung quanh các thông số xp_readerrorlog nhưng trong ngắn hạn, bạn có thể chỉ định chuỗi tìm kiếm và bộ lọc thời gian bắt đầu hữu ích trong trường hợp này. Không chắc điều này có giúp ích cho việc thử lại logic của bạn không, nhưng để nắm bắt thông tin hoặc lỗi khi đăng nhập, tôi đã nghĩ ra một thứ như thế này ...

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


Điều này hoạt động rất tốt cho một số lỗi phổ biến nhưng có một số lỗi dường như chỉ được ném trực tiếp đến máy khách. Nhật ký sp_readerrorlog sẽ bao gồm một thông báo nói đến "nhật ký ứng dụng", trong đó tôi giả sử bằng "ứng dụng", chúng có nghĩa là quá trình bên ngoài đang phát lệnh. Liên kết SO
crokusek 6/11/2015

0

Bạn có thể đăng nhập các chi tiết lỗi vào một bảng. Bạn cũng có thể tạo một tệp nhật ký, nhưng điều đó có thể yêu cầu CLR hoặc xp_cmdshell để làm. Bạn cũng có thể gửi thư cơ sở dữ liệu, nhưng điều đó có thể gây ra sự cố thư rác và không phải là nhật ký thích hợp.

Bảng là đơn giản nhất.

  1. Tạo một bảng để lưu trữ các lỗi
  2. Tạo một thủ tục được lưu trữ chèn vào bảng lỗi
  3. Gọi thủ tục được lưu trữ trong khối bắt

Xem qua ví dụ của Jeremy Kadlec được cung cấp trong liên kết dưới đây:

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


3
Vấn đề không nằm ở chỗ phải làm gì với các lỗi, mà là thông báo lỗi thích hợp không có sẵn cho một số lệnh bên trong CATCH. Điều này là do chỉ có thông báo lỗi cuối cùng được trả lại trong ERROR_MESSAGE()...
Aaron Bertrand
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.