Blog Post

Backup Deployed Sessions

,

There is a wealth of information within Extended Events. Throughout this series, I have been working on exposing that wealth of information. A good bit of this information happens to be the metadata for Extended Events, and another bit of this information is tied craneto the metadata for deployed Sessions. To dive into what I have done so far with this plenitude of information, you can review the series here.

What is the point in covering all of this information? I like to call it building blocks. Take a concept little by little and build upon it, while working toward a more comprehensive understanding as well as to hopefully be able to use it for a bigger product.

Having just completed several segments on the metadata for deployed sessions, it is time to bring all of that information together and see how it can be used.

Bringing it Together

Having a solid foundation and understanding of what the metadata is and where it is really helps in creating scripts that can be useful in the day to day management of deployed Extended Event Sessions. For me, the ability to recreate a deployed session, without the use of the GUI is pretty essential. Contributing to the need to be able to do this via script and not a GUI is that (without a third party product) there is no GUI in SQL Server 2008.

To demonstrate how to create a script to serve as a backup of a deployed session, I will first return to the “demosession” script that I have used throughout this series.

CREATE EVENT SESSION [demosession2] ON SERVER
ADD EVENT sqlserver.auto_stats ( 
SET collect_database_name = ( 1 )--fields
ACTION (
  package0.event_sequence--actions
, sqlos.cpu_id
, sqlserver.database_id
, sqlserver.database_name 
)
WHERE ( [database_name] = N'AdventureWorks2014' )--events
)
ADD TARGET package0.event_file 
( SET filename = N'demosession'--fields
, max_file_size = ( 50 )--fields
, max_rollover_files = ( 6 )--fields
),
ADD TARGET package0.ring_buffer
(SET max_events_limit=(666)--fields
,max_memory=(65536) --fields --max buffer size
,occurrence_number=(3)--fields
)
WITH ( EVENT_RETENTION_MODE = ALLOW_MULTIPLE_EVENT_LOSS--session
, MAX_DISPATCH_LATENCY = 5 SECONDS--session
, MAX_EVENT_SIZE = 2 MB--session
, MEMORY_PARTITION_MODE = PER_NODE--session
, TRACK_CAUSALITY = ON--session
, STARTUP_STATE = ON--session
);
GO

And if I color-code this script as I have done previously:

session_colorcode_views

In this image, I have separated out the major components by color. The segments that pertain to the session creation and the settings for that session are in grey. Then the target information is in red and so on. I added my notes (to help indicate where the components can be found in metadata) and colored them purple. The wrinkle here is in the SET operations since that is a component that crosses boundaries of the core concepts.

Taking this breakdown, and a serious desire to be able to recreate any session that has been deployed (without the GOOEY), and I have been able to create the following script that will do just that – backup deployed sessions.

SET NOCOUNT ON;
DECLARE @statement VARCHAR(MAX)
,@statement1 VARCHAR(MAX)
,@statement2 VARCHAR(MAX)
,@sessionname VARCHAR(128) = 'system_health'
/* order of events scripted is different 
default order of creation is different than if scripted from the gui
the gui scripts by alpha order of package then event
while original creation has order by event_id only
*/,@eventorder VARCHAR(64) = 'original'; --'original' for order based on original script, --'ssms' for order based on ssms gui scripter 
SELECT @statement = 'CREATE EVENT SESSION [' + ses.name +'] ON SERVER
' 
FROM sys.server_event_sessions ses
WHERE ses.name = @sessionname;
WITH presel AS (
SELECT ses.name AS SessionName
, sese.event_id
, sese.package
, 'ADD EVENT ' + sese.package +'.' + sese.name + ' (' AS EventName
, CASE WHEN ISNULL(sese.predicate,'') = '' THEN ')' ELSE 'WHERE ' + sese.predicate + ' )' END AS SQLPredicate
, CASE WHEN ISNULL(sesf.name,'') = '' THEN '' ELSE 'SET ' + sesf.name + ' = ( ' + CAST(sesf.value AS VARCHAR(10)) + ' )' END AS SETOperation
FROM sys.server_event_sessions ses
INNER JOIN sys.server_event_session_events sese
ON ses.event_session_id = sese.event_session_id
LEFT OUTER JOIN sys.server_event_session_fields sesf
ON sese.event_session_id = sesf.event_session_id
AND sese.event_id = sesf.object_id
WHERE ses.name = @sessionname
), actpresel AS (SELECT ses.name AS SessionName, sesa.event_session_id, sesa.event_id, sesa.package + '.' + sesa.name AS ActPack
FROM sys.server_event_session_events sese
INNER JOIN sys.server_event_session_actions sesa
ON sese.event_session_id = sesa.event_session_id
AND sese.event_id = sesa.event_id
INNER JOIN sys.server_event_sessions ses
ON sesa.event_session_id = ses.event_session_id
WHERE ses.name = @sessionname)
, pstuff AS (SELECT p.SessionName, p.event_id,'ACTION ( 
' + STUFF((SELECT ', ' + pin.ActPack + '
'
FROM actpresel pin
WHERE pin.SessionName = p.SessionName
AND pin.event_id = p.event_id
FOR XML PATH(''),TYPE).value('.','varchar(max)') , 1, 2, '') + '
)' AS ActionPack
FROM actpresel p
GROUP BY p.SessionName, p.event_id
)
SELECT @statement1 = @statement + STUFF(
(SELECT ', ' + CAST(p.EventName + '
' + p.SETOperation + '
' + CASE WHEN ISNULL(ps.ActionPack,'') = '' THEN '' ELSE ps.ActionPack END + '
' + p.SQLPredicate + '
' AS VARCHAR(MAX) ) AS EventStatement
FROM presel p 
LEFT OUTER JOIN pstuff ps
ON p.SessionName = ps.SessionName
AND p.event_id = ps.event_id
ORDER BY p.event_id 
--ORDER BY p.package, p.EventName 
FOR XML PATH(''),TYPE).value('.', 'varchar(max)'), 1, 2, '')
,@statement2 = @statement + STUFF(
(SELECT ', ' + CAST(p.EventName + '
' + p.SETOperation + '
' + CASE WHEN ISNULL(ps.ActionPack,'') = '' THEN '' ELSE ps.ActionPack END + '
' + p.SQLPredicate + '
' AS VARCHAR(MAX) ) AS EventStatement
FROM presel p 
LEFT OUTER JOIN pstuff ps
ON p.SessionName = ps.SessionName
AND p.event_id = ps.event_id
ORDER BY p.package, p.EventName 
FOR XML PATH(''),TYPE).value('.', 'varchar(max)'), 1, 2, '')
IF @eventorder = 'original'
BEGIN
SET @statement = @statement1
END
IF @eventorder = 'ssms'
BEGIN
SET @statement = @statement2
END
SELECT @statement = @statement + STUFF((SELECT ', ' +  '
ADD TARGET ' + sest.package + '.' + sest.name + '
(SET ' + ca.setop + ' )
'
FROM sys.server_event_sessions ses
INNER JOIN sys.server_event_session_targets sest
ON ses.event_session_id = sest.event_session_id
CROSS APPLY (SELECT STUFF((SELECT ', ' + CAST(sesf.name AS VARCHAR(128)) + ' = ' + CASE WHEN ISNUMERIC(CAST(sesf.value AS VARCHAR(128))) = 1 
THEN '( ' + CAST(sesf.value AS VARCHAR(128)) + ' )
'
ELSE 'N''' + CAST(sesf.value AS VARCHAR(128)) + '''
' END AS setop
FROM sys.server_event_session_fields sesf
INNER JOIN sys.server_event_sessions sesi
ON sesi.event_session_id = sesf.event_session_id
INNER JOIN sys.server_event_session_targets sesti
ON sesf.object_id = sesti.target_id
AND sesi.event_session_id = sesti.event_session_id
WHERE sest.target_id = sesti.target_id
AND sest.event_session_id = sesti.event_session_id
FOR XML PATH(''),TYPE).value('.','varchar(max)') , 1, 2, '') ) AS ca(setop)
WHERE ses.name = @sessionname
FOR XML PATH(''),TYPE).value('.','varchar(max)') , 1, 2, '') 
;
SELECT @statement = @statement + 
CAST('WITH ( MAX_MEMORY = ' + CAST(ses.max_memory AS VARCHAR(20)) +' KB
,EVENT_RETENTION_MODE = ' + ses.event_retention_mode_desc +'
, MAX_DISPATCH_LATENCY = ' + CAST(ses.max_dispatch_latency/1000 AS VARCHAR(20)) +' SECONDS
, MAX_EVENT_SIZE = ' + CAST(ses.max_event_size AS VARCHAR(20))+ ' KB
, MEMORY_PARTITION_MODE = '+ ses.memory_partition_mode_desc +'
, TRACK_CAUSALITY = ' + CASE ses.track_causality WHEN 1 THEN 'ON' ELSE 'OFF' END +'
, STARTUP_STATE = ' + CASE ses.startup_state WHEN 1 THEN 'ON' ELSE 'OFF' END +'
);' AS VARCHAR(1024)) 
FROM sys.server_event_sessions ses
WHERE ses.name = @sessionname;
PRINT @statement;

I have tested this script back through SQL Server 2008 and up through SQL Server 2014. The script has been tested against complex sessions as well as simple sessions (e.g. the “demosession” session I have been using throughout the series).

While testing, I did run into an interesting anomaly so I had to add a little bit of awkwardness to the script. When comparing the original script for “system_health” (that can be found in the u_tables.sql script in the Install folder), to what was produced while scripting sessions from the GUI, I noticed that my script was recreating the session in the same fashion that the original script was doing it. But this did not match what the GUI did.

When scripting from SSMS (the GUI), the events in the session are ordered by Package and then by Event name. My script, originally, was ordering the events by Event_id which is the same as can be found in the u_tables.sql script. Due to this, I added a parameter to allow for the different sort methods. This also underscores that when a session is deployed, the order of Events in that first script is the order the Events will be created within the metadata.

I decided to output the results of the script via a print statement. This permits me a chance to see the entire script and review it. Then, I can copy to a new window and execute or I can save the script.

With this script, I can quickly do what is an essential function of a DBA, I can perform targeted backups of my deployed sessions. Another way of viewing it is that I can reverse engineer (without the GOOEY) any user definable session that is deployed to the server.

This is just one of many articles in this series. In this article, I demonstrated how to backup a deployed session and create a script for recovery purposes of a targeted session. To find more useful information about extended events, you can get caught up here.

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating