Как войти в T-SQL
Я использую ADO.NET для доступа к SQL Server 2005 и хочу иметь возможность регистрироваться из хранимых процедур T-SQL, которые я вызываю. Это возможно?
Я не могу видеть вывод из инструкции "print" при использовании ADO.NET, и поскольку я хочу использовать ведение журнала только для отладки идеального решения, было бы отправлять сообщения DebugView из SysInternals.
Ответы
Ответ 1
Я решил это, написав 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'
Ответ 2
Я думаю, что писать в таблицу журналов я бы предпочел.
В качестве альтернативы, поскольку вы используете 2005, вы можете написать простую процедуру SQLCLR для обтекания EventLog.
Или вы можете использовать xp_logevent, если хотите записать в журнал SQL
Ответ 3
Вы можете либо войти в таблицу, просто вставив новую строку, либо вы можете реализовать хранимую процедуру CLR для записи в файл.
Будьте осторожны с записью в таблицу, потому что, если действие происходит в транзакции и транзакция откатется, ваша запись в журнале исчезнет.
Ответ 4
Запись изнутри SQL sproc будет лучше сделана для самой базы данных. T-SQL может записывать файлы, но не предназначен для этого.
Ответ 5
Здесь PRINT, но я предпочитаю войти в таблицу, чтобы вы могли ее запросить.
Ответ 6
Вы можете записывать строки в таблицу журналов из хранимой процедуры. Как указывали другие, вы могли бы отказаться от своего способа писать в текстовый файл или другой журнал с помощью CLR или xp_logevent, но кажется, что вам нужно больше объема, чем это было бы практично для таких целей.
В случае неудачных транзакций возникают тяжелые случаи (и вам это действительно нужен ваш журнал). Поскольку любое ведение журнала, которое происходит во время этих транзакций, будет откат вместе с транзакцией, частью которой они являются, лучше всего иметь API протоколирования, который ваши клиенты могут использовать для регистрации ошибок. Это может быть простой DAL, который либо записывается в одну базу данных, либо в общий.
Ответ 7
Для чего это стоит, я обнаружил, что, когда я не назначаю обработчик InfoMessage для моего SqlConnection:
sqlConnection.InfoMessage += new SqlInfoMessageEventHandler(MySqlConnectionInfoMessageHandler);
где подпись InfoMessageHandler выглядит так:
MySqlConnectionInfoMessageHandler(object sender, SqlInfoMessageEventArgs e)
то мои инструкции PRINT в моих хранимых пробах не отображаются в DbgView.
Ответ 8
Вы можете использовать выходные переменные для передачи обратных сообщений, но это зависит от выполнения proc без ошибок.
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 в таблицу ошибок, как и другие, предложили и выберите * из нее, когда вы отлаживаете.
Ответ 9
Вы можете проверить Log4TSQL. Он обеспечивает ведение журнала базы данных для хранимых процедур и триггеров в SQL Server 2005-2008. У вас есть возможность установить отдельные независимые уровни регистрации в каждой процедуре/триггере.
Ответ 10
- Следующий DDL-код создаст вам таблицу для хранения данных журнала USE [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>
*/