Extended events - session not capturing information

  • CREATE EVENT SESSION [AL_Alter] ON SERVER 
    ADD EVENT sqlserver.sql_statement_completed(SET collect_statement=(1)
    ACTION(sqlserver.database_name,sqlserver.nt_username,sqlserver.session_nt_username,sqlserver.sql_text)
    WHERE ([sqlserver].[database_name]=N'ABCDEF' AND [sqlserver].[like_i_sql_unicode_string]([sqlserver].[sql_text],N'ALTER')
    AND [sqlserver].[session_nt_user]<>N'ABCD\EFGH'))
    ADD TARGET package0.event_file(SET filename=N'C:\ABCD\ExtendedEvents\AL_Alter',max_file_size=(5),max_rollover_files=(1000))
    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=OFF,STARTUP_STATE=OFF)
    GO

    I am trying capture only ALTER statements which are executed on ABCDEF database and the session_nt_user can be anybody but this user-> ABCD\EFGH.
    So anybody besides ABCD\EFGH who is running ALTER statements should be captured in the AL_Alter session.
    My session_nt_user is ZZZ\DDD. And I excecuted an ALTER table statement which adds some columns to a table TableA.
    But the session is not capturing my ALTER activity.Why is that so?
  • Break it all down into pieces for testing. The easy part is the database name of course. But, next, test that you're capturing only statements with ALTER in them. See how it returns the user names. Test it with the user name you wish to exclude so that you can see the string in order to get the comparison right. Then add that in. Taking it apart and testing each piece separately is the best way to get the filtering right. Same thing I'd do with a query.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • A bit of a hint:

    What strings would the TSQL comparison LIKE 'ALTER' match? 🙂

    Cheers!

  • Are you saying 'alter' works and not 'ALTER' ?

  • I tried to filter starting with one filter as suggested and still does not work.Obviously I am doing this completely wrong.Any suggestions please.I still find rows with AAAA\ZZZZ against nt_username column in the watch live window when they should have be ignored as per the SQL below.

    I tried

    WHERE ([sqlserver].[not_equal_i_sql_unicode_string]([sqlserver].[session_nt_user],N'AAAA\ZZZZ')))

    WHERE ([sqlserver].[not_equal_i_sql_unicode_string]([sqlserver].[nt_user],N'AAAA\ZZZZ')))

    Both filters are not working and I still find data with AAAA\ZZZZ.

    And is nt_user and nt_username the same ?

    Under ACTIONS it is : sqlserver.session_nt_username and sqlserver.nt_username

    But under filters/predicates it is only nt_user and sqlserver.session_nt_username? Id nt_user in filter and nt_username under actions the same field we are referring to ?

    Thanks

    CREATE EVENT SESSION [AuditLogins_Alter] ON SERVER

    ADD EVENT sqlserver.sql_statement_completed(SET collect_statement=(1)

    ACTION(sqlserver.database_name,sqlserver.nt_username,sqlserver.session_nt_username,sqlserver.sql_text)

    WHERE ([sqlserver].[not_equal_i_sql_unicode_string]([sqlserver].[session_nt_user],N'AAAA\ZZZZ'))),

    ADD EVENT sqlserver.sql_statement_starting(

    ACTION(sqlserver.database_name,sqlserver.nt_username,sqlserver.session_nt_username,sqlserver.sql_text)

    WHERE ([sqlserver].[not_equal_i_sql_unicode_string]([sqlserver].[session_nt_user],N'AAAA\ZZZZ')))

    ADD TARGET package0.event_file(SET filename=N'E:\ExtendedEvents\AL_Alter',max_file_size=(5),max_rollover_files=(1000))

    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=OFF,STARTUP_STATE=OFF)

    GO

     

     

  • When I use database_name as the only filter it works well.

    But when I add nt_user /session_nt_username under predicates everything goes for a toss.I get data I do not want to see.

    Rows from other databases show up etc..

    I need to capture activities which happend on a particular database and by any user barrinf AAAA\ZZZZ.

    Cant get this to work.

    I read that predicate order is important and obviously this is giong above my head.

    Responses are appreciated.

    Thanks

  • You can't reference Action values in the predicate. Here are the values on which you can filter:

    -- What Predicates (fields on which we can filter) are available?
    SELECT p.name AS [Package], o.name AS [PredicateField], o.object_type, o.description
    FROM sys.dm_xe_objects o
    JOIN sys.dm_xe_packages p ON o.package_guid = p.guid
    WHERE o.object_type LIKE 'pred_source' AND (o.name LIKE '%domain%' or o.name LIKE '%user%')
    ORDER BY o.name;

    /* results:
    Package PredicateField object_type description
    ------------ -------------------- ------------- ---------------------------------------
    sqlserver nt_domain pred_source Get the current NT domain
    sqlserver nt_user pred_source Get the current NT user
    sqlserver session_nt_domain pred_source Get the current session NT domain
    sqlserver session_nt_user pred_source Get the current session NT user
    sqlserver username pred_source Get the current username */

    Note that there are separate fields for user name and domain name. Here's where you had issues: nt_user and session_nt_user do not contain the domain name. That's what nt_domain and session_nt_domain are for.  I'll use [nt_user] and [nt_domain] for this.

    Also, because you are only looking for ALTER commands, use the Event for that. Review the results of this query:

    -- Is there an Event for ALTER?
    SELECT p.name + '.' + o.name AS [Event], o.description
    FROM sys.dm_xe_objects o
    JOIN sys.dm_xe_packages p ON o.package_guid = p.guid
    WHERE o.object_type = 'event' AND o.name like '%alter%';
    GO

    The Event sqlserver.object_altered looks like a good place to start. Description:

    "Occurs when an object was altered by the ALTER statement. This event is raised

    two times for every ALTER operation. The event is raised when the operation begins and when the

    operation is either rolled back or committed. Add the nt_username or server_principal_name actions

    to this event to determine who altered the object."

    -- Check its columns:
    SELECT * FROM sys.dm_xe_object_columns oc
    WHERE oc.object_name = 'object_altered'
    ORDER BY oc.column_type, oc.column_id;
    GO

    There's a SET column for capturing the database name. Because you are tracing only a specific database, leave this OFF for better performance (you know what the DB name is). Also, filter on database_id instead of the database name.

    SELECT DB_ID('ABCDEF') AS [Filter database_id];
    GO

    Slapping that all together into a Session definition (example uses database_id = 6):

    IF EXISTS(SELECT * FROM sys.dm_xe_sessions WHERE name = 'AlterWatchr')
    DROP EVENT SESSION AlterWatchr ON SERVER;
    GO
    CREATE EVENT SESSION AlterWatchr ON SERVER
    ADD EVENT sqlserver.object_altered (SET collect_database_name = 0
    ACTION (sqlserver.nt_username,sqlserver.session_nt_username, sqlserver.sql_text)
    WHERE (database_id = 6 AND NOT (nt_domain = 'ABCD' AND nt_user = N'EFGH')))
    ADD TARGET package0.ring_buffer
    WITH (MAX_MEMORY=4096 KB, EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS,
    MAX_DISPATCH_LATENCY = 5 SECONDS,MAX_EVENT_SIZE=0 KB, MEMORY_PARTITION_MODE = NONE,
    TRACK_CAUSALITY = OFF, STARTUP_STATE = OFF);
    GO
    ALTER EVENT SESSION AlterWatchr ON SERVER STATE = START;
    GO

    ...with a little XQuery to pull the info out of the trace:

    -- Run from the context of the target database so 
    -- the joins to sys.objects and sys.indexes work
    USE ABCDEF; -- replace with db name
    GO
    WITH
    AlterWatchrEvents(EventSession, LatchEventData) AS
    (SELECT xes.name AS [EventSession], CONVERT(xml, xest.target_data) AS LatchEventData
    FROM sys.dm_xe_session_targets xest
    JOIN sys.dm_xe_sessions xes ON xes.address = xest.event_session_address
    WHERE xest.target_name = 'ring_buffer' AND xes.name = 'AlterWatchr'
    ),
    AlterEventDetails AS (
    SELECT AlterEventNode.LatchEvent.value('(@name)[1]', 'varchar(128)') AS EventType,
    AlterEventNode.LatchEvent.value ('(@timestamp)[1]', 'datetime') AS EventTime,
    AlterEventNode.LatchEvent.value ('(data[@name="database_id"]/value)[1]', 'smallint') AS [database_id],
    DB_NAME(AlterEventNode.LatchEvent.value ('(data[@name="database_id"]/value)[1]', 'smallint')) AS [database_name],
    AlterEventNode.LatchEvent.value ('(data[@name="object_id"]/value)[1]', 'bigint') AS [target_object_id],
    AlterEventNode.LatchEvent.value ('(data[@name="object_type"]/text)[1]', 'nvarchar(32)') AS [target_object_type],
    AlterEventNode.LatchEvent.value ('(data[@name="index_id"]/value)[1]', 'int') AS [target_index_id],
    AlterEventNode.LatchEvent.value ('(data[@name="related_object_id"]/value)[1]', 'bigint') AS [related_object_id],
    AlterEventNode.LatchEvent.value ('(data[@name="ddl_phase"]/text)[1]', 'varchar(16)') AS [ddl_phase],
    AlterEventNode.LatchEvent.value ('(data[@name="transaction_id"]/value)[1]', 'bigint') AS [transaction_id],
    AlterEventNode.LatchEvent.value ('(data[@name="object_name"]/value)[1]', 'nvarchar(256)') AS [object_name],
    AlterEventNode.LatchEvent.value ('(action[@name="sql_text"]/value)[1]', 'nvarchar(max)') AS [SQLText],
    AlterEventNode.LatchEvent.value ('(action[@name="session_nt_username"]/value)[1]', 'nvarchar(256)') AS [session_nt_username],
    AlterEventNode.LatchEvent.value ('(action[@name="nt_username"]/value)[1]', 'nvarchar(256)') AS [nt_username]
    FROM AlterWatchrEvents
    CROSS APPLY LatchEventData.nodes('//RingBufferTarget/event') AS AlterEventNode(LatchEvent)
    )
    SELECT EventTime, database_name, target_object_type, N'[' + s.name + N'].[' + object_name + N']' AS target_object,
    IsNull(i.name, '') AS [target_index], aed.target_object_id, aed.target_index_id, related_object_id, ddl_phase, SQLText, session_nt_username, nt_username
    FROM AlterEventDetails aed
    -- LEFT JOIN the object tables because this Event also captures ALTER DATABASE commands
    LEFT JOIN sys.objects o ON o.object_id = aed.target_object_id
    LEFT JOIN sys.schemas s ON s.schema_id = o.schema_id
    LEFT JOIN sys.indexes i ON aed.target_index_id != 0 AND aed.target_index_id = i.index_id
    ORDER BY 2;

    This should get you on your way.

    -Eddie

    • This reply was modified 4 years, 4 months ago by  Eddie Wuerch. Reason: Changed all JOINs in the final query to LEFT JOIN due to ALTER DATABASE commands being captured by the trace

    Eddie Wuerch
    MCM: SQL

  • Thanks for the elaborate reply but looks like I still cannot get this to work.

    My Query:

    CREATE EVENT SESSION [AlterExtendedEvent] ON SERVER

    ADD EVENT sqlserver.object_altered(SET collect_database_name=(0)

    ACTION(sqlserver.database_name,sqlserver.nt_username,sqlserver.session_nt_username,sqlserver.sql_text)

    WHERE ([database_name]='AAAAAA' AND NOT ([nt_domain]='ABC' AND [nt_user]=N'DEF')))

    ADD TARGET package0.event_file(SET filename=N'E:\ExtendedEvents\AletExtendedEvent.xel',max_file_size=(5),max_rollover_files=(1000))

    WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)

    GO

    Under database AAAAAA I created a table A with 2 columns.Then I executed the alter statement to add columns to this table.But the alter table was not captured in the extended event window.Any thoughts.I presume that if i run any kind of alter statement (alter indexes ,alter table etc...)it should be captured here. But that does not seem to the case.

    Thanks

  • Please ignore my previous comment.

    Thanks for the response

  • I'm glad you seem to have gotten this working with Eddie's solution.

    For the record, my hint about the original session's capturing zero events was not related to the case of the string.

    Without wildcards, TSQL's LIKE and XE's like_i_sql_unicode_string evaluate TRUE for exact matches only, so your original filter would match only completed statements that contained nothing more than the single word 'ALTER', which would naturally be 0 events.

    Cheers!

     

Viewing 10 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic. Login to reply