如何从T-SQL存储过程向GrayLog发送日志?SQLCLR无日志问题排查
问题原因分析
- SQLCLR默认权限不足
SQL Server默认给SQLCLR程序集的权限集是SAFE模式,该模式下禁止所有外部网络访问行为,你调用UDP端口发请求的操作会被直接拦截,这是最常见的原因。
- SQLCLR默认权限不足
- 异常捕获逻辑无效
你内层catch块使用Console.WriteLine输出异常,但SQLCLR运行环境中没有控制台输出,就算抛出了异常你也无法在SSMS中看到,自然误以为没有异常发生。
- 异常捕获逻辑无效
- 服务账号/网络规则限制
SQL Server服务是用独立的系统账号运行的,和你运行WinForm程序的登录账号权限不同,可能存在:
- 服务账号没有网络出站权限
- 本地防火墙仅放通了你当前登录账号的UDP 12201出站请求,未放通SQL Server服务进程的请求
- GrayLog的GELF UDP输入绑定了127.0.0.1,仅接收本地进程请求,而SQLCLR的网络请求被识别为非本地环回请求被拒绝
- 服务账号/网络规则限制
解决方案
步骤1:修复异常捕获逻辑
把内层catch的输出替换为SqlContext.Pipe.Send,先拿到具体的异常信息再定位问题:
catch (Exception xx) { // 替换Console.WriteLine SqlContext.Pipe.Send("***Send Exception:" + xx.Message); }
步骤2:给SQLCLR程序集授予外部访问权限
你可以选择以下两种方式之一配置权限:
方式一(快速配置,适合测试环境)
先在SSMS中执行SQL开启数据库信任配置:
ALTER DATABASE 你的数据库名 SET TRUSTWORTHY ON; GO
创建程序集时指定权限集:
CREATE ASSEMBLY 你的程序集名称 FROM '你的dll物理路径' WITH PERMISSION_SET = EXTERNAL_ACCESS; GO
方式二(证书签名,适合生产环境,更安全)
通过证书对程序集签名,授予对应权限,不需要开启数据库TRUSTWORTHY,避免安全风险。
步骤3:验证网络配置
- 确认SQL Server服务运行账号有出站访问UDP 12201端口的权限
- 检查本地防火墙规则,添加允许SQL Server进程(sqlservr.exe)出站UDP 12201的规则
- 确认GrayLog的GELF UDP输入绑定地址为
0.0.0.0或者SQL Server所在设备的IP,而不是仅绑定127.0.0.1
备选方案(更稳定,推荐生产使用)
如果不想开启SQLCLR的外部访问权限,可以用以下替代方案实现存储过程打日志到GrayLog:
- 存储过程先把日志写入专用的本地日志表,再部署独立的定时同步服务,定期把表中日志推送到GrayLog
- 开启
xp_cmdshell,在存储过程中调用curl等命令行工具直接发送GELF格式的HTTP请求到GrayLog
内容的提问来源于stack exchange,提问作者ZedZip
相关产品推荐
相关产品推荐

