我希望 SQL Server 创建一个记录所有(成功)登录/连接到数据库的日志文件。日志应至少包含:
- 连接客户端的 IP 地址和端口
- 客户端的应用程序名称
- 用户名
- 数据库名称
- 连接时间或适用交易
看起来服务器跟踪可能可以捕获所有这些信息,但微软表示不推荐使用服务器跟踪以支持扩展事件。
所以我试图用扩展事件收集这些信息。对于我的测试,我使用的是 SQL Server 2017 Developer Edition(在 Windows 10 上的 Docker 容器中运行)和 SSMS v17.7。当我创建或查看扩展事件时,我以“sa”身份登录。
到目前为止,我已经能够通过扩展事件收集大部分信息。问题是收集客户端 IP 和端口。我可以单独获得任何一部分,但不能同时获得两者。下面列出了我正在使用的 XEvent。两次列出的事实connection_accept
并不是一个错误。SQL Server 实际上有两个具有完全相同名称的不同事件(!!!)。
Login
:没有选项(字段或操作)来收集客户端 IP 或端口。至少它确实提供client_hostname
!Logout
:没有选项(字段或操作)来收集客户端 IP 或端口。这也捕捉到了client_hostname
。connection_accept
:- 收集客户端 IP,但它掩盖了最低八位字节(例如 192.168.1.XX)!!!
- 收集客户端端口!好的!
- 不收集 session_id,因此无法与
Login
或Logout
事件关联。 - My指定和
EVENT SESSION
的集合username
,但这些字段/操作都不存在于收集的数据中。:(client_app_name
client_hostname
connection_accept
:- 收集客户端端口,但不收集客户端IP!!!
- 有 sesstion_id,所以至少它可以与
Login
和相关联Logout
- 注意:我还没有在野外捕捉到这个特定的事件,所以我没有进一步的评论。
这些事件都没有提供客户端的 IP 地址,但我会接受客户端主机名作为合理的替代。但是,获得端口号是一个真正的问题。端口号仅在connection_accept
事件中找到,没有明显的方法可以将其与login
具有主机名的事件相关联。简而言之,扩展事件似乎根本无法提供这种基本的客户端 IP 和端口配对。我想相信我错了,因为它是如此基本的数据。对于我所忽略的任何帮助或建议将不胜感激。
扩展事件 DDL
这是EVENT SESSION
我一直在测试的 DDL:
CREATE EVENT SESSION [Connections] ON SERVER
ADD EVENT SQLSatellite.connection_accept(
ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.nt_username,sqlserver.request_id,sqlserver.server_instance_name,sqlserver.server_principal_name,sqlserver.session_id,sqlserver.transaction_id,sqlserver.username)
WHERE ([sqlserver].[not_equal_i_sql_unicode_string]([sqlserver].[client_app_name],N'SQLServerCEIP'))),
ADD EVENT sqlserver.connection_accept(
ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.context_info,sqlserver.database_name,sqlserver.nt_username,sqlserver.request_id,sqlserver.server_instance_name,sqlserver.server_principal_name,sqlserver.session_id,sqlserver.transaction_id,sqlserver.username)
WHERE ([sqlserver].[not_equal_i_sql_unicode_string]([sqlserver].[client_app_name],N'SQLServerCEIP'))),
ADD EVENT sqlserver.connectivity_ring_buffer_recorded(
ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.server_principal_name,sqlserver.session_id,sqlserver.session_nt_username,sqlserver.transaction_id,sqlserver.username)
WHERE ([sqlserver].[client_app_name]<>N'SQLServerCEIP')),
ADD EVENT sqlserver.login(SET collect_options_text=(1)
ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.server_principal_name,sqlserver.session_id,sqlserver.session_nt_username,sqlserver.transaction_id,sqlserver.username)
WHERE ([sqlserver].[client_app_name]<>N'SQLServerCEIP')),
ADD EVENT sqlserver.logout(
ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_instance_name,sqlserver.server_principal_name,sqlserver.session_id,sqlserver.session_nt_username,sqlserver.transaction_id,sqlserver.username)
WHERE ([sqlserver].[client_app_name]<>N'SQLServerCEIP'))
ADD TARGET package0.event_file(SET filename=N'c:\xevents\connections')
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)
GO
备择方案
除了扩展事件之外,“安全审计”是另一种未被弃用的机制。所以我想我也试试这个:
USE [master]
GO
CREATE SERVER AUDIT [AuditTest]
TO FILE
( FILEPATH = N'C:\xevents\'
,MAXSIZE = 2 MB
,MAX_FILES = 5
,RESERVE_DISK_SPACE = OFF
)
WITH
( QUEUE_DELAY = 1000
,ON_FAILURE = CONTINUE
)
CREATE SERVER AUDIT SPECIFICATION [Connections]
FOR SERVER AUDIT [AuditTest]
ADD (SUCCESSFUL_LOGIN_GROUP),
ADD (LOGOUT_GROUP)
GO
提供的字段包括“客户端应用程序”、“客户端 IP”、“会话 ID”和用户名(即“服务器主体名称”)。但是,无法将其与connection_accept
XEvent 关联起来。所以没有办法提取我想要的两条信息:客户端IP和端口号。:(
奖金
除了收集客户端 IP 和端口,我还对收集 SQL Server 网络流量感兴趣。但是,我还没有看到任何方法可以做到这一点。提示赞赏!我只看到模糊相关的帖子。
更新
我注意到一个名为的全局动作(字段)task_address
似乎与login
,logout
和connection_accept
事件相关。因此,现在可以通过组合login:client_hostname
和来找到 IP 和端口connection_accept:port
。我唯一担心的是我找不到文档task_address
来验证我的观察结果。