Вопрос

Я использую ADO.NET для доступа к SQL Server 2005 и хотел бы иметь возможность регистрироваться внутри хранимых процедур T-SQL, которые я вызываю.Это как-то возможно?

Я не могу видеть вывод оператора print при использовании ADO.NET, и поскольку я хочу использовать ведение журнала только для отладки, идеальным решением было бы отправлять сообщения в DebugView из SysInternals.

Это было полезно?

Решение

Я решил эту проблему, написав процедуру SQLCLR, как предложил Эрик З. Бирд.Сборка должна быть подписана с помощью файла ключа строгого имени.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static int Debug(string s)
    {
        System.Diagnostics.Debug.WriteLine(s);
            return 0;
        }
    }
}

Создал ключ и логин:

USE [master]
CREATE ASYMMETRIC KEY DebugProcKey FROM EXECUTABLE FILE =
'C:\..\SqlServerProject1\bin\Debug\SqlServerProject1.dll'

CREATE LOGIN DebugProcLogin FROM ASYMMETRIC KEY DebugProcKey 

GRANT UNSAFE ASSEMBLY TO DebugProcLogin  

Импортировал его в SQL Server:

USE [mydb]
CREATE ASSEMBLY SqlServerProject1 FROM
'C:\..\SqlServerProject1\bin\Debug\SqlServerProject1.dll' 
WITH PERMISSION_SET = unsafe

CREATE FUNCTION dbo.Debug( @message as nvarchar(200) )
RETURNS int
AS EXTERNAL NAME SqlServerProject1.[StoredProcedures].Debug

Затем я смог войти в процедуры T-SQL, используя

exec Debug @message = 'Hello World'

Другие советы

Я думаю, что запись в таблицу журнала была бы моим предпочтением.

В качестве альтернативы, поскольку вы используете 2005, вы можете написать простую процедуру SQLCLR для переноса журнала событий.

Или вы можете использовать xp_logevent если вы хотите записать в журнал SQL

Вы можете либо войти в таблицу, просто вставив новую строку, либо реализовать хранимую процедуру CLR для записи в файл.

Будьте осторожны с записью в таблицу, потому что если действие произойдет в транзакции и транзакция будет отменена, ваша запись в журнале исчезнет.

Ведение журнала изнутри процедуры SQL лучше выполнять в самой базе данных.T-SQL может записывать в файлы, но на самом деле он не предназначен для этого.

Вот РАСПЕЧАТАТЬ команду, но я предпочитаю войти в таблицу, чтобы вы могли запросить ее.

Вы можете записывать строки в таблицу журнала из хранимой процедуры.Как указывали другие, вы могли бы изо всех сил писать в какой-либо текстовый файл или другой журнал с помощью CLR или xp_logevent, но похоже, что вам нужен больший объем, чем было бы практично для такого использования.

Сложные случаи возникают (и именно для них вам действительно нужен журнал), когда транзакции терпят неудачу.Поскольку любое ведение журнала, происходящее во время этих транзакций, будет отменено вместе с транзакцией, частью которой они являются, лучше всего иметь API ведения журнала, который ваши клиенты смогут использовать для регистрации ошибок.Это может быть простой DAL, который регистрируется либо в той же базе данных, либо в общей базе данных.

Как бы то ни было, я обнаружил, что, когда я не назначаю обработчик InfoMessage своему SqlConnection:

sqlConnection.InfoMessage += new SqlInfoMessageEventHandler(MySqlConnectionInfoMessageHandler);

где подпись InfoMessageHandler выглядит следующим образом:

MySqlConnectionInfoMessageHandler(object sender, SqlInfoMessageEventArgs e)

тогда мои операторы PRINT в моих сохраненных процедурах не отображаются в DbgView.

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

create procedure usp_LoggableProc 

@log varchar(max) OUTPUT 

as

-- T-SQL statement here ...

select @log = @log + 'X is foo'

И затем в вашем коде ADO где-то:

string log = (string)SqlCommand.Parameters["@log"].Value;

Вы можете использовать raiserror для создания собственных ошибок с необходимой информацией, которая будет доступна вам через обычную коллекцию ошибок SqlException в вашем коде ADO:

RAISERROR('X is Foo', 10, 1)

Хммм, но да, я не могу избавиться от ощущения, что это просто отладка, и в вашей ситуации просто вставьте сообщения varchar в таблицу ошибок, как предлагали другие, и выберите * из нее во время отладки.

Вы можете проверить Лог4TSQL.Он обеспечивает ведение журнала базы данных для хранимых процедур и триггеров в SQL Server 2005–2008.У вас есть возможность установить отдельные независимые уровни журналирования для каждой процедуры/триггера.

- Следующий DDL SQL создаст вам таблицу для хранения использования данных журнала [DB] GO

/****** Object:  Table [dbo].[tbData_Debug]    Script Date: 02/12/2009 22:30:03 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[tbData_Debug](
    [colTimeStamp] [timestamp] NULL,
    [colNiceTime] [varchar](200) NULL,
    [colDomain_User] [varchar](200) NULL,
    [colMsg] [varchar](4000) NULL,
    [colDebugLevel] [int] NULL,
    [colDebugMsg] [varchar](4000) NULL,
    [colPageName] [varchar](200) NULL,
    [colClassName] [varchar](200) NULL,
    [colMethodName] [varchar](200) NULL,
    [colMethodNameGui] [varchar](4000) NULL,
    [colRet] [int] NULL,
    [colLineNumber] [int] NULL,
    [colLineNumberGui] [int] NULL,
    [colProcedureName] [varchar](200) NULL,
    [colProcedureStep] [varchar](4000) NULL
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO




-- This stored procedure does write to the log table

USE [db]
GO
/****** Object:  StoredProcedure [dbo].[procUtils_AppDebug]    Script Date: 02/12/2009 22:29:24 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[procUtils_AppDebug] (                  

@ret int = null OUT,     
@msgIn varchar(4000) = null ,   -- the msg which the user has seen   
@msgOut varchar(4000) = null OUT ,   -- the msg which the user has seen   
@domain_user varchar(200) = null ,                 -- the domain user echoing the message  
@debugMsgIn varchar(4000) = null  ,   -- the debug msg for internal use  
@debugMsgOut varchar(4000) = null  OUT,   -- the debug msg for internal use  
@pageName varchar(200) = null ,   -- the pageName originator of error  
@className varchar(200) = null ,   -- the class Name orinator of error  
@methodName varchar(200) = null ,   -- the methodName where the last error occured  
@methodNameGui varchar(4000) = null ,   -- the methodNameOfTheGui where the last error occured  
@lineNumber int = null ,  -- the line number of the line issueing the error  
@lineNumberGui int = null,   -- the line number of the line issueing the error               
@procedureName varchar(200) = null , -- the procedureName currently envoked
@procedureStep varchar(4000)  = null -- the steps of the procedure concatenated
)    

AS                  
BEGIN -- proc start                
 SET NOCOUNT ON;                

BEGIN TRY        --begin try      

declare @debugLevel int     
select @debugLevel =  Debug_Level from User_tb where Domain_Name = @domain_user  

/*                  
select * from tbData_Debug    order by 1 desc              
delete from tbData_Debug              
*/    


insert into tbData_Debug ( colNiceTime , colDomain_User , colMsg , colDebugLevel ,   
colDebugMsg , colPageName , colClassName , colMethodName , colMethodNameGui ,   
colRet , colLineNumber , colLineNumberGui , colProcedureName , colProcedureStep) values (
 dbo.funcGetNiceTime() , @domain_user  , @msgIn , @debugLevel ,@debugMsgIn , 
 @pageName , @className , @methodName  ,@MethodNameGui , @ret , 
 @lineNumber , @lineNumberGui , @procedureName , @procedureStep)     

set @debugMsgOut = @debugMsgIn  
set @msgOut = 'Action Registered'  
set @ret = @@ERROR     
return @ret                



END TRY        --end try      

BEGIN CATCH            
 PRINT 'In CATCH block.             
 Error number: ' + CAST(ERROR_NUMBER() AS varchar(10)) + '            
 Error message: ' + ERROR_MESSAGE() + '            
 Error severity: ' + CAST(ERROR_SEVERITY() AS varchar(10)) + '            
 Error state: ' + CAST(ERROR_STATE() AS varchar(10)) + '            
 XACT_STATE: ' + CAST(XACT_STATE() AS varchar(10));            

 set  @debugMsgOut = 'error at [procUtils_AppDebug]--- Error number: ' + CAST(ERROR_NUMBER() AS varchar(10)) + 'Error message: ' + ERROR_MESSAGE() + 'Error severity: ' +   
CAST(ERROR_SEVERITY() AS varchar(10)) + 'Error state: ' + CAST(ERROR_STATE() AS varchar(10)) + 'XACT_STATE: ' + CAST(XACT_STATE() AS varchar(10))            
set @msgIn= 'error while saving application error info into database'  
insert into tbData_Debug ( colMsg ) values ( @msgIn )     

set @debugMsgOut = @debugMsgIn +  @debugMsgOut  
set @msgOut = 'Action Registration failed'  
set @ret = 1           

END CATCH            


return  @ret                       
END --procedure end                 

/*       
<procedureDocumentation>      

<procedurename>procUtils_AppDebug<procedurename>      
<procedureDescription> Records events from the Application Layer </procedureDescription>    
<created>20090121</created>      
<createdby>Yordan Georgiev</createdby>      
<change>      

<changewhen><changewhen>      
<changeDescription></changeDescription>      
<changedBy></changedBy>      
</change>      


<testUsage>    

USE [db]    
GO    

DECLARE @return_value int,    
  @ret int,    
  @msgIn varchar(max),    
  @debugmsg varchar(4000)    

SELECT @ret = 1    
SELECT @msgIn = N'msg'    
SELECT @debugmsg = N'before'    

EXEC @return_value = [dbo].[procUtils_AppDebug]    
  @ret = @ret OUTPUT,    
  @msgIn = @msgIn OUTPUT,    
  @domain_user = N'domain_user',    
  @debugmsg = @debugmsg OUTPUT,    

  @methodName = N'methodName'    

SELECT @ret as N'@ret',    
  @msgIn as N'@msgIn',    
  @debugmsg as N'@debugmsg'    

SELECT 'Return Value' = @return_value    
select * from tbData_Debug order by 1 desc    
GO    

</testUsage>      
</procedureDocumentation>      
*/  
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top