【问题标题】:Connection Logging连接记录
【发布时间】:2018-06-05 18:44:34
【问题描述】:

我希望 SQL Server 创建一个记录所有(成功)登录/连接到数据库的日志文件。日志应至少包含:

  • 连接客户端的IP地址和端口
  • 客户端的应用程序名称
  • 用户名
  • 数据库名称
  • 连接时间或适用交易时间

看起来像a server trace likely can capture all this information,但微软表示不推荐使用服务器跟踪以支持扩展事件。

所以我试图通过扩展事件收集这些信息。对于我的测试,我使用的是 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,因此无法与 LoginLogout 事件关联。
    • 我的EVENT SESSION 指定了usernameclient_app_nameclient_hostname 的集合,但这些字段/操作都不存在于收集的数据中。 :(
  • connection_accept
    • 收集客户端端口,但不收集客户端IP!!!
    • 有sesstion_id,所以至少可以关联LoginLogout
    • 注意:我还没有在野外捕捉到这个特定的事件,所以我没有更多关于它的信息。

这些事件都没有提供客户端的 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

替代方案

除了扩展事件,"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 的全局操作(字段)似乎与loginlogoutconnection_accept 事件相关。因此,现在可以通过组合login:client_hostnameconnection_accept:port 来找到IP 和端口。我唯一担心的是我找不到task_address 的文档来验证我的观察。

【问题讨论】:

  • 这可能值得在 dba.stackexchange.com 中提出,它更适合该群体。
  • @MJH 我在 dba.stackexchange 上看到六个左右的 dba 介入评论这个问题(其他人已经问过),并且反复出现的反馈是“我没有工作带有扩展事件。”所以我想我会提出这个问题。此外,开发和运营之间的差距不断缩小!

标签: sql-server monitoring network-monitoring extended-events


【解决方案1】:

如果您可以在您的环境中使用触发器,这是一个解决方案。每次“登录”时,都会在 [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

【讨论】:

  • 我认为这并没有达到目的。 client_net_address 属性很好,但需要与不存在的 client_net_port... 匹配。 local_tcp_port 是服务器端端口,我不需要(我已经知道它是 1433)。
  • @BrentArias 该属性的值将是您可以登录到 SQL Server 实例的唯一有效端口。您是否要求您需要知道是否有人尝试连接到不正确的端口,例如 yoursqlserver,5555 而不是 yoursqlserver,1433? (假设 1433 是您的实际端口号)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-24
  • 2017-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多