我希望SQL Server创建一个记录所有(成功)登录/数据库连接的日志文件。日志应该包含最低限度:
它看起来像a server trace likely can capture all this information,但微软表示不推荐使用服务器跟踪来支持扩展事件。
所以我试图通过扩展事件收集这些信息。对于我的测试,我使用的是SQL Server 2017 Developer Edition(在Windows 10上的Docker容器中运行)和SSMS v17.7。我在创建或查看扩展事件时以“sa”身份登录。
到目前为止,我已经能够通过扩展事件收集大部分此类信息。问题是收集客户端IP和端口。我可以孤立地获得任何一部分,但不能同时获得两部分。我正在使用的XEvents如下所示。 connection_accept
被列入两次这一事实并非错误。 SQL Server实际上有两个具有完全相同名称的不同事件(!!!)。
Login
:没有收集客户端IP或端口的选项(字段或操作)。至少它确实提供client_hostname
!Logout
:没有收集客户端IP或端口的选项(字段或操作)。这也捕获了client_hostname
。connection_accept
:
收集客户端IP,但它掩盖了最低的八位字节(例如192.168.1.XX)!
收集客户端端口!好!
不收集session_id,因此无法与Login
或Logout
事件相关联。
我的EVENT SESSION
指定了username
,client_app_name
和client_hostname
的集合,但这些字段/操作中没有一个存在于收集的数据中。 :(connection_accept
:
收集客户端端口,但不收集客户端IP!
有sesstion_id,所以至少它可以与Login
和Logout
相关联
注意:我还没有在野外发现这个特殊事件,所以我没有进一步的评论。这些事件都不提供客户端的IP地址,但我会接受客户端主机名作为合理的替代品。但是,获得端口号是一个真正的问题。端口号仅在connection_accept
事件中找到,并且没有明显的方法将其与具有主机名的login
事件相关联。简而言之,似乎扩展事件根本无法提供此基本客户端IP端口配对。我想相信我错了,因为它是如此基本的数据。任何有关我所忽视的帮助或建议将不胜感激。
这是我测试过的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
除了扩展事件,"security audits" is another mechanism没有被弃用。所以我想我也试一试:
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和端口,我也对collecting SQL Server network traffic volume感兴趣。但是,我还没有看到任何方法。提示赞赏!我只看到vaguely related posts。
我注意到一个名为task_address
的全球行动(场)似乎与login
,logout
和connection_accept
事件有关。因此,现在可以通过组合login:client_hostname
和connection_accept:port
找到IP和端口。我唯一担心的是我找不到task_address
的文档来验证我的观察结果。
如果您可以在您的环境中使用触发器,这是一个解决方案。每次有“登录”时,都会在[master]中插入一行。[dbo]。[TRACETABLE]。
CREATE TABLE [master].[dbo].[TRACETABLE] (
[EVENTDATE] DATETIME NOT NULL,
[DBNAME] NVARCHAR(128) NULL,
[CURRENTUSER] NVARCHAR(128) NULL,
[HOSTNAME] NVARCHAR(128) NULL,
[APPLICATIONNAME] NVARCHAR(128) NULL,
[PROCEDURENAME] NVARCHAR(128) NULL,
[USERID] SMALLINT NULL,
[USERNAME] NVARCHAR(128) NULL,
[SUSERID] INT NULL,
[SUSERNAME] NVARCHAR(128) NULL,
[IS_SERVERADMIN_SYSADMIN] INT NULL,
[IS_DB_OWNER] INT NULL,
[IS_DDL_ADMIN] INT NULL,
[IS_DB_DATAREADER] INT NULL,
[ORIGINAL_LOGIN] NVARCHAR(4000) NULL,
[NET_TRANSPORT] SQL_VARIANT NULL,
[PROTOCOL_TYPE] SQL_VARIANT NULL,
[AUTH_SCHEME] SQL_VARIANT NULL,
[LOCAL_NET_ADDRESS] SQL_VARIANT NULL,
[LOCAL_TCP_PORT] SQL_VARIANT NULL,
[CLIENT_NET_ADDRESS] SQL_VARIANT NULL,
[PHYSICAL_NET_TRANSPORT] SQL_VARIANT NULL)
GO
GRANT INSERT ON [master].[dbo].[TRACETABLE] TO PUBLIC
GRANT SELECT on [master].[sys].[dm_exec_connections] TO PUBLIC
GO
CREATE TRIGGER Logon_Trigger_Track_IP
ON ALL SERVER FOR LOGON
AS
BEGIN
INSERT INTO [master].[dbo].[TRACETABLE]
--the auditing snippet below works fine in a
--login trigger,
--database trigger
--or any stored procedure.
SELECT
getdate() AS EventDate,
DB_NAME() AS DBName,
CURRENT_USER AS CurrentUser,
HOST_NAME() AS HostName,
APP_NAME() AS ApplicationName,
OBJECT_NAME(@@PROCID) AS ProcedureName,
USER_ID() AS Userid,
USER_NAME() AS UserName,
SUSER_ID() AS sUserid,
SUSER_SNAME() AS sUserName,
IS_SRVROLEMEMBER ('sysadmin') AS [Is_ServerAdmin_Sysadmin],
IS_MEMBER('db_owner') AS [Is_DB_owner],
IS_MEMBER('db_ddladmin') AS [Is_DDL_Admin],
IS_MEMBER('db_datareader') AS [Is_DB_Datareader],
ORIGINAL_LOGIN() AS [ORIGINAL_LOGIN],
ConnectionProperty('net_transport') AS 'net_transport',
ConnectionProperty('protocol_type') AS 'protocol_type',
ConnectionProperty('auth_scheme') AS 'auth_scheme',
ConnectionProperty('local_net_address') AS 'local_net_address',
ConnectionProperty('local_tcp_port') AS 'local_tcp_port',
ConnectionProperty('client_net_address') AS 'client_net_address',
ConnectionProperty('physical_net_transport') AS 'physical_net_transport'
END
GO
ENABLE TRIGGER [Logon_Trigger_Track_IP] ON ALL SERVER