سؤال

أنا أستخدم ADO.NET للوصول إلى SQL Server 2005 وأرغب في أن أتمكن من تسجيل الدخول من داخل إجراءات T-SQL المخزنة التي أتصل بها.هل هذا ممكن بطريقة أو بأخرى؟

لا أستطيع رؤية الإخراج من عبارة "الطباعة" عند استخدام ADO.NET وبما أنني أريد استخدام التسجيل فقط لتصحيح الأخطاء، فإن الحل المثالي هو إرسال رسائل إلى DebugView من SysInternals.

هل كانت مفيدة؟

المحلول

لقد قمت بحل هذه المشكلة عن طريق كتابة إجراء SQLCLR كما اقترح Eric Z Beard.يجب أن يتم توقيع التجميع بملف مفتاح ذو اسم واضح.

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 sproc إلى قاعدة البيانات نفسها.يمكن لـ T-SQL الكتابة إلى الملفات ولكنها ليست مصممة حقًا لذلك.

هناك مطبعة الأمر، لكنني أفضل تسجيل الدخول إلى جدول حتى تتمكن من الاستعلام عنه.

يمكنك كتابة صفوف في جدول السجل من داخل الإجراء المخزن.كما أشار الآخرون، يمكنك بذل قصارى جهدك للكتابة على بعض الملفات النصية أو أي سجل آخر باستخدام CLR أو xp_logevent، ولكن يبدو أنك تحتاج إلى حجم أكبر مما قد يكون عمليًا لمثل هذه الاستخدامات.

تحدث الحالات الصعبة (وهي التي تحتاج حقًا إلى السجل الخاص بك لها) عندما تفشل المعاملات.نظرًا لأن أي تسجيل يحدث أثناء هذه المعاملات سيتم التراجع عنه مع المعاملة التي تعد جزءًا منها، فمن الأفضل أن يكون لديك واجهة برمجة تطبيقات للتسجيل يمكن لعملائك استخدامها لتسجيل الأخطاء.يمكن أن يكون هذا DAL بسيطًا يقوم إما بتسجيل الدخول إلى نفس قاعدة البيانات أو إلى قاعدة بيانات مشتركة.

لما يستحق الأمر، وجدت أنه عندما لا أقوم بتعيين معالج InfoMessage إلى SqlConnection الخاص بي:

sqlConnection.InfoMessage += new SqlInfoMessageEventHandler(MySqlConnectionInfoMessageHandler);

حيث يبدو توقيع InfoMessageHandler كما يلي:

MySqlConnectionInfoMessageHandler(object sender, SqlInfoMessageEventArgs e)

ثم لا تظهر بيانات PRINT الخاصة بي في Stored Procs في 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;

يمكنك استخدام riserror لإنشاء الأخطاء المخصصة الخاصة بك باستخدام المعلومات التي تحتاجها والتي ستكون متاحة لك من خلال مجموعة أخطاء SqlException المعتادة في كود ADO الخاص بك:

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

حسنًا، ولكن نعم، لا يمكن أن تساعد في الشعور بالتصحيح فقط وفي حالتك، ما عليك سوى إدراج رسائل varchar في جدول الأخطاء كما اقترح الآخرون وتحديد * منه عند تصحيح الأخطاء.

قد ترغب في التحقق Log4TSQL.يوفر إمكانية تسجيل قاعدة البيانات للإجراءات المخزنة والمشغلات في 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