我正在使用 ADO.NET 访问 SQL Server 2005,并且希望能够从我正在调用的 T-SQL 存储过程内部进行日志记录。这有可能吗?
使用 ADO.NET 时,我无法看到“打印”语句的输出,因为我只想使用日志记录来调试理想的解决方案是从 SysInternals 向 DebugView 发出消息。
我正在使用 ADO.NET 访问 SQL Server 2005,并且希望能够从我正在调用的 T-SQL 存储过程内部进行日志记录。这有可能吗?
使用 ADO.NET 时,我无法看到“打印”语句的输出,因为我只想使用日志记录来调试理想的解决方案是从 SysInternals 向 DebugView 发出消息。
我认为写入日志表将是我的偏好。
或者,当您使用 2005 时,您可以编写一个简单的 SQLCLR 过程来包装 EventLog。
或者,如果您想写入 SQL 日志,可以使用xp_logevent
我按照 Eric Z Beard 的建议通过编写 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'
您可以通过简单地插入新行来登录到表,也可以实现 CLR 存储过程来写入文件。
写入表时要小心,因为如果操作发生在事务中并且事务回滚,您的日志条目将消失。
从 SQL 存储过程中记录日志最好对数据库本身进行。T-SQL 可以写入文件,但它并不是真正为它设计的。
有PRINT命令,但我更喜欢登录到表中以便您可以查询它。
您可以从存储过程中将行写入日志表。正如其他人所指出的那样,您可以使用 CLR 或 xp_logevent 不遗余力地写入某些文本文件或其他日志,但您似乎需要比此类用途实际更多的容量。
当事务失败时,就会出现棘手的情况(正是这些情况您真正需要您的日志)。由于在这些事务期间发生的任何日志记录都将与它们所属的事务一起回滚,因此最好有一个日志记录 API,您的客户端可以使用它来记录错误。这可以是一个简单的 DAL,既可以记录到同一个数据库,也可以记录到共享数据库。
对于它的价值,我发现当我没有为我的 SqlConnection 分配 InfoMessage 处理程序时:
sqlConnection.InfoMessage += new SqlInfoMessageEventHandler(MySqlConnectionInfoMessageHandler);
InfoMessageHandler 的签名如下所示:
MySqlConnectionInfoMessageHandler(object sender, SqlInfoMessageEventArgs e)
然后我的存储过程中的 PRINT 语句不会出现在 DbgView 中。
您可以使用输出变量来传回消息,但这依赖于 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 使用您需要的信息创建您自己的自定义错误,这些信息将通过您的 ADO 代码中的常用 SqlException Errors 集合提供给您:
RAISERROR('X is Foo', 10, 1)
嗯,但是是的,不禁感觉只是为了调试,在你的情况下,只需像其他人建议的那样将 varchar 消息插入错误表,并在调试时从中选择 *。
您可能需要检查Log4TSQL。它为 SQL Server 2005 - 2008 中的存储过程和触发器提供数据库日志记录。您可以在每个过程/触发器的基础上设置单独的、独立的日志级别。
通过 cmdshell 使用 cmd 命令
我在寻找这个问题的答案时发现了这一点。 https://www.databasejournal.com/features/mssql/article.php/1467601/A-general-logging-t-sql-process-to-write-to-txt-files.htm
select @cmdtxt = "echo " + @logEntry + " >> drive:\path\filename.txt"
exec master..xp_cmdshell @cmdtxt
我一直在寻找一种方法来做到这一点,因为我正在尝试调试一些复杂的、链接的、存储的过程,所有这些都由外部 API 调用,并且在事务的上下文中运行。
我一直在将诊断消息写入日志文件,但如果事务回滚,新的日志条目会随着回滚而消失。我找到了一个方法!而且效果很好。它已经为我节省了很多很多小时的调试时间。
使用登录名的安全上下文创建指向同一 SQL 实例的链接服务器。就我而言,最简单的方法是使用 localhost 循环地址 127.0.0.1
将链接服务器设置为启用 RPC,而不是“启用分布式事务的提升”。这意味着通过该服务器的调用将在您的事务上下文之外进行。
在您的日志记录过程中,(我在下面摘录了一个示例)如果您处于事务中,则使用该过程通过环回链接服务器写入日志表。如果你不是,你可以用通常的方式写信给它。通过链接服务器写入比直接 DML 慢得多。
瞧!我的进程内日志记录在回滚中幸存下来,当事情向南时,我可以找出内部正在发生的事情。
想到这一点,我不能说是功劳——我在 Google 工作了一段时间后找到了这种方法,但我对结果感到非常满意,我觉得我必须分享它。
USE TX
GO
CREATE PROCEDURE dbo.LogError(@errorSource Varchar(32), @msg Varchar(400))
AS BEGIN
SET NOCOUNT ON
IF @@TRANCOUNT > 0
EXEC [127.0.0.1].TX.dbo.LogError @errorSource, @msg
ELSE
INSERT INTO TX.dbo.ErrorLog(source_module, message)
SELECT @errorSource, @msg
END
GO