diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs index 86380e86..4242ac25 100755 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs @@ -4559,9 +4559,9 @@ namespace Microsoft.SqlTools.ServiceLayer return Keys.GetString(Keys.EditDataIncorrectTable, tableName); } - public static string StopSessionFailed(String error) + public static string CreateSessionFailed(String error) { - return Keys.GetString(Keys.StopSessionFailed, error); + return Keys.GetString(Keys.CreateSessionFailed, error); } public static string StartSessionFailed(String error) @@ -4569,6 +4569,21 @@ namespace Microsoft.SqlTools.ServiceLayer return Keys.GetString(Keys.StartSessionFailed, error); } + public static string PauseSessionFailed(String error) + { + return Keys.GetString(Keys.PauseSessionFailed, error); + } + + public static string StopSessionFailed(String error) + { + return Keys.GetString(Keys.StopSessionFailed, error); + } + + public static string SessionAlreadyExists(String sessionName) + { + return Keys.GetString(Keys.SessionAlreadyExists, sessionName); + } + public static string EnableAlertsTitle(String serverName) { return Keys.GetString(Keys.EnableAlertsTitle, serverName); @@ -6176,15 +6191,24 @@ namespace Microsoft.SqlTools.ServiceLayer public const string AzureSystemDbProfilingError = "AzureSystemDbProfilingError"; - public const string StopSessionFailed = "StopSessionFailed"; + public const string CreateSessionFailed = "CreateSessionFailed"; public const string StartSessionFailed = "StartSessionFailed"; + public const string PauseSessionFailed = "PauseSessionFailed"; + + + public const string StopSessionFailed = "StopSessionFailed"; + + public const string SessionNotFound = "SessionNotFound"; + public const string SessionAlreadyExists = "SessionAlreadyExists"; + + public const string EnableAlertsTitle = "EnableAlertsTitle"; diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx index 67b36ecd..a8e68a33 100755 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx @@ -2027,20 +2027,35 @@ Cannot profile Azure system databases - - Failed to stop session: {0} + + Failed to create session: {0} . Parameters: 0 - error (String) Failed to start session: {0} . + Parameters: 0 - error (String) + + + Failed to pause session: {0} + . + Parameters: 0 - error (String) + + + Failed to stop session: {0} + . Parameters: 0 - error (String) Cannot find requested XEvent session + + An XEvent session named {0} already exists + . + Parameters: 0 - sessionName (String) + Enable Alerts - {0} . diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings index deb95e41..a3c49b8c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings @@ -888,9 +888,12 @@ InvalidPathError = Cannot access the specified path on the server: {0} # Profiler ProfilerConnectionNotFound = Connection not found AzureSystemDbProfilingError = Cannot profile Azure system databases -StopSessionFailed(String error) = Failed to stop session: {0} +CreateSessionFailed(String error) = Failed to create session: {0} StartSessionFailed(String error) = Failed to start session: {0} +PauseSessionFailed(String error) = Failed to pause session: {0} +StopSessionFailed(String error) = Failed to stop session: {0} SessionNotFound = Cannot find requested XEvent session +SessionAlreadyExists(String sessionName) = An XEvent session named {0} already exists ############################################################################# # SQL Agent diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf index 576b7b98..b531bc1e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf @@ -3112,6 +3112,24 @@ . Parameters: 0 - error (String) + + Failed to create session: {0} + Failed to create session: {0} + . + Parameters: 0 - error (String) + + + Failed to pause session: {0} + Failed to pause session: {0} + . + Parameters: 0 - error (String) + + + An XEvent session named {0} already exists + An XEvent session named {0} already exists + . + Parameters: 0 - sessionName (String) + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/CreateXEventSessionRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/CreateXEventSessionRequest.cs new file mode 100644 index 00000000..3d0c29c3 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/CreateXEventSessionRequest.cs @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts +{ + /// + /// Start Profiling request parameters + /// + public class CreateXEventSessionParams : GeneralRequestDetails + { + public string OwnerUri { get; set; } + + public string SessionName { get; set; } + + public ProfilerSessionTemplate Template { get; set; } + } + + public class CreateXEventSessionResult{} + + /// + /// Start Profile request type + /// + public class CreateXEventSessionRequest + { + /// + /// Request definition + /// + public static readonly + RequestType Type = + RequestType.Create("profiler/createsession"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/GetXEventSessionsRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/GetXEventSessionsRequest.cs new file mode 100644 index 00000000..4f082be9 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/GetXEventSessionsRequest.cs @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts +{ + /// + /// Start Profiling request parameters + /// + public class GetXEventSessionsParams : GeneralRequestDetails + { + public string OwnerUri { get; set; } + } + + public class GetXEventSessionsResult + { + /// + /// Session ID that was started + /// + public List Sessions { get; set; } + } + + /// + /// Start Profile request type + /// + public class GetXEventSessionsRequest + { + /// + /// Request definition + /// + public static readonly + RequestType Type = + RequestType.Create("profiler/getsessions"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/ProfilerSessionCreatedNotification.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/ProfilerSessionCreatedNotification.cs new file mode 100644 index 00000000..83146a78 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/ProfilerSessionCreatedNotification.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts +{ + public class ProfilerSessionCreatedParams + { + public string OwnerUri { get; set; } + + public string SessionName { get; set; } + + public string TemplateName { get; set; } + } + + public class ProfilerSessionCreatedNotification + { + public static readonly + EventType Type = + EventType.Create("profiler/sessioncreated"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/ProfilerSessionTemplate.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/ProfilerSessionTemplate.cs new file mode 100644 index 00000000..94c4ec01 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/ProfilerSessionTemplate.cs @@ -0,0 +1,56 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts +{ + /// + /// Class that contains data for a single profile event + /// + public class ProfilerSessionTemplate + { + /// + /// Initialize a new ProfilerEvent with required parameters + /// + public ProfilerSessionTemplate(string name, string defaultView, string createStatement) + { + this.Name = name; + this.DefaultView = defaultView; + this.CreateStatement = createStatement; + } + + /// + /// Profiler event name + /// + public string Name { get; private set; } + + /// + /// Profiler event timestamp + /// + public string DefaultView { get; private set; } + + /// + /// Profiler event timestamp + /// + public string CreateStatement { get; private set; } + + /// + /// Equals method + /// + public bool Equals(ProfilerSessionTemplate t) + { + // if parameter is null return false: + if ((object)t == null) + { + return false; + } + + return this.Name == t.Name + && this.DefaultView == t.DefaultView + && this.CreateStatement == t.CreateStatement; + } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/StartProfilingRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/StartProfilingRequest.cs index 64d40527..14125cdf 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/StartProfilingRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/Contracts/StartProfilingRequest.cs @@ -16,30 +16,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts { public string OwnerUri { get; set; } - public string TemplateName - { - get - { - return GetOptionValue("templateName"); - } - set - { - SetOptionValue("templateName", value); - } - } + public string SessionName { get; set; } } - public class StartProfilingResult - { - /// - /// Session ID that was started - /// - public string SessionId { get; set; } - - public bool Succeeded { get; set; } - - public string ErrorMessage { get; set; } - } + public class StartProfilingResult{} /// /// Start Profile request type diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/IXEventSessionFactory.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/IXEventSessionFactory.cs index 36bb7b82..a7918326 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/IXEventSessionFactory.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/IXEventSessionFactory.cs @@ -16,8 +16,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler public interface IXEventSessionFactory { /// - /// Gets or creates an XEvent session with the given template + /// Gets an XEvent session with the given name /// - IXEventSession GetOrCreateXEventSession(string template, ConnectionInfo connInfo); + IXEventSession GetXEventSession(string sessionName, ConnectionInfo connInfo); + + /// + /// Creates an XEvent session with the given create statement and name + /// + IXEventSession CreateXEventSession(string createStatement, string sessionName, ConnectionInfo connInfo); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerService.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerService.cs index 33a92e3b..3a46ab2f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerService.cs @@ -110,13 +110,57 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler public void InitializeService(ServiceHost serviceHost) { this.ServiceHost = serviceHost; + this.ServiceHost.SetRequestHandler(CreateXEventSessionRequest.Type, HandleCreateXEventSessionRequest); this.ServiceHost.SetRequestHandler(StartProfilingRequest.Type, HandleStartProfilingRequest); this.ServiceHost.SetRequestHandler(StopProfilingRequest.Type, HandleStopProfilingRequest); this.ServiceHost.SetRequestHandler(PauseProfilingRequest.Type, HandlePauseProfilingRequest); + this.ServiceHost.SetRequestHandler(GetXEventSessionsRequest.Type, HandleGetXEventSessionsRequest); this.SessionMonitor.AddSessionListener(this); } + /// + /// Handle request to start a profiling session + /// + internal async Task HandleCreateXEventSessionRequest(CreateXEventSessionParams parameters, RequestContext requestContext) + { + try + { + ConnectionInfo connInfo; + ConnectionServiceInstance.TryFindConnection( + parameters.OwnerUri, + out connInfo); + if (connInfo == null) + { + throw new Exception(SR.ProfilerConnectionNotFound); + } + else if (parameters.SessionName == null) + { + throw new ArgumentNullException("SessionName"); + } + else if (parameters.Template == null) + { + throw new ArgumentNullException("Template"); + } + else + { + // create a new XEvent session and Profiler session + var xeSession = this.XEventSessionFactory.CreateXEventSession(parameters.Template.CreateStatement, parameters.SessionName, connInfo); + // start monitoring the profiler session + monitor.StartMonitoringSession(parameters.OwnerUri, xeSession); + + var result = new CreateXEventSessionResult(); + await requestContext.SendResult(result); + + SessionCreatedNotification(parameters.OwnerUri, parameters.SessionName, parameters.Template.Name); + } + } + catch (Exception e) + { + await requestContext.SendError(new Exception(SR.CreateSessionFailed(e.Message))); + } + } + /// /// Handle request to start a profiling session /// @@ -124,25 +168,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler { try { - var result = new StartProfilingResult(); ConnectionInfo connInfo; ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); - if (connInfo != null) { - int xEventSessionId = StartSession(parameters.OwnerUri, parameters.TemplateName, connInfo); - result.SessionId = xEventSessionId.ToString(); - result.Succeeded = true; + // create a new XEvent session and Profiler session + var xeSession = this.XEventSessionFactory.GetXEventSession(parameters.SessionName, connInfo); + // start monitoring the profiler session + monitor.StartMonitoringSession(parameters.OwnerUri, xeSession); + + var result = new StartProfilingResult(); + await requestContext.SendResult(result); } else { - result.Succeeded = false; - result.ErrorMessage = SR.ProfilerConnectionNotFound; + throw new Exception(SR.ProfilerConnectionNotFound); } - - await requestContext.SendResult(result); } catch (Exception e) { @@ -160,13 +203,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler ProfilerSession session; monitor.StopMonitoringSession(parameters.OwnerUri, out session); - if (session == null) + if (session != null) + { + session.XEventSession.Stop(); + await requestContext.SendResult(new StopProfilingResult{}); + } + else { throw new Exception(SR.SessionNotFound); } - - session.XEventSession.Stop(); - await requestContext.SendResult(new StopProfilingResult{}); } catch (Exception e) { @@ -187,26 +232,58 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler } catch (Exception e) { - await requestContext.SendError(e); + await requestContext.SendError(new Exception(SR.PauseSessionFailed(e.Message))); } } /// - /// Starts a new profiler session or connects to an existing session - /// for the provided connection and template info + /// Handle request to pause a profiling session + /// + internal async Task HandleGetXEventSessionsRequest(GetXEventSessionsParams parameters, RequestContext requestContext) + { + try + { + var result = new GetXEventSessionsResult(); + ConnectionInfo connInfo; + ConnectionServiceInstance.TryFindConnection( + parameters.OwnerUri, + out connInfo); + if (connInfo == null) + { + await requestContext.SendError(new Exception(SR.ProfilerConnectionNotFound)); + } + else + { + List sessions = GetXEventSessionList(parameters.OwnerUri, connInfo); + result.Sessions = sessions; + await requestContext.SendResult(result); + } + } + catch (Exception e) + { + await requestContext.SendError(e); + } + } + + /// + /// Gets a list of all running XEvent Sessions /// /// - /// The XEvent Session Id that was started + /// A list of the names of all running XEvent sessions /// - internal int StartSession(string ownerUri, string template, ConnectionInfo connInfo) + internal List GetXEventSessionList(string ownerUri, ConnectionInfo connInfo) { - // create a new XEvent session and Profiler session - var xeSession = this.XEventSessionFactory.GetOrCreateXEventSession(template, connInfo); + var sqlConnection = ConnectionService.OpenSqlConnection(connInfo); + SqlStoreConnection connection = new SqlStoreConnection(sqlConnection); + BaseXEStore store = CreateXEventStore(connInfo, connection); - // start monitoring the profiler session - monitor.StartMonitoringSession(ownerUri, xeSession); + // get session names from the session list + List results = store.Sessions.Aggregate(new List(), (result, next) => { + result.Add(next.Name); + return result; + } ); - return xeSession.Id; + return results; } private static BaseXEStore CreateXEventStore(ConnectionInfo connInfo, SqlStoreConnection connection) @@ -228,13 +305,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler } /// - /// Gets or creates an XEvent session with the given template per the IXEventSessionFactory contract + /// Gets an XEvent session with the given name per the IXEventSessionFactory contract /// Also starts the session if it isn't currently running /// - public IXEventSession GetOrCreateXEventSession(string template, ConnectionInfo connInfo) + public IXEventSession GetXEventSession(string sessionName, ConnectionInfo connInfo) { - string sessionName = "Profiler"; - var sqlConnection = ConnectionService.OpenSqlConnection(connInfo); SqlStoreConnection connection = new SqlStoreConnection(sqlConnection); BaseXEStore store = CreateXEventStore(connInfo, connection); @@ -243,7 +318,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler // start the session if it isn't already running if (session == null) { - session = CreateSession(connInfo, connection, sessionName); + throw new Exception(SR.SessionNotFound); } if (session != null && !session.IsRunning) @@ -258,60 +333,39 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler }; } - private static Session CreateSession(ConnectionInfo connInfo, SqlStoreConnection connection, string sessionName) - { - string createSessionSql = - @" - CREATE EVENT SESSION [Profiler] ON SERVER - ADD EVENT sqlserver.attention( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.nt_username,sqlserver.query_hash,sqlserver.server_principal_name,sqlserver.session_id) - WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))), - ADD EVENT sqlserver.existing_connection(SET collect_options_text=(1) - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_id)), - ADD EVENT sqlserver.login(SET collect_options_text=(1) - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_id)), - ADD EVENT sqlserver.logout( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_id)), - ADD EVENT sqlserver.rpc_completed( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.nt_username,sqlserver.query_hash,sqlserver.server_principal_name,sqlserver.session_id) - WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))), - ADD EVENT sqlserver.sql_batch_completed( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.nt_username,sqlserver.query_hash,sqlserver.server_principal_name,sqlserver.session_id) - WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))), - ADD EVENT sqlserver.sql_batch_starting( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.nt_username,sqlserver.query_hash,sqlserver.server_principal_name,sqlserver.session_id) - WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))) - ADD TARGET package0.ring_buffer(SET max_events_limit=(1000),max_memory=(51200)) - WITH (MAX_MEMORY=8192 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=PER_CPU,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)"; - - string createAzureSessionSql = - @" - CREATE EVENT SESSION [Profiler] ON DATABASE - ADD EVENT sqlserver.attention( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.username,sqlserver.query_hash,sqlserver.session_id) - WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))), - ADD EVENT sqlserver.existing_connection(SET collect_options_text=(1) - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.username,sqlserver.session_id)), - ADD EVENT sqlserver.login(SET collect_options_text=(1) - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.username,sqlserver.session_id)), - ADD EVENT sqlserver.logout( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.username,sqlserver.session_id)), - ADD EVENT sqlserver.rpc_completed( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.username,sqlserver.query_hash,sqlserver.session_id) - WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))), - ADD EVENT sqlserver.sql_batch_completed( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.username,sqlserver.query_hash,sqlserver.session_id) - WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))), - ADD EVENT sqlserver.sql_batch_starting( - ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.username,sqlserver.query_hash,sqlserver.session_id) - WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))) - ADD TARGET package0.ring_buffer(SET max_events_limit=(1000),max_memory=(51200)) - WITH (MAX_MEMORY=8192 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=PER_CPU,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)"; - - string createStatement = connInfo.IsCloud ? createAzureSessionSql : createSessionSql; - connection.ServerConnection.ExecuteNonQuery(createStatement); + /// + /// Creates and starts an XEvent session with the given name and create statement per the IXEventSessionFactory contract + /// + public IXEventSession CreateXEventSession(string createStatement, string sessionName, ConnectionInfo connInfo) + { + var sqlConnection = ConnectionService.OpenSqlConnection(connInfo); + SqlStoreConnection connection = new SqlStoreConnection(sqlConnection); BaseXEStore store = CreateXEventStore(connInfo, connection); - return store.Sessions[sessionName]; + Session session = store.Sessions[sessionName]; + + // session shouldn't already exist + if (session != null) + { + throw new Exception(SR.SessionAlreadyExists(sessionName)); + } + + var statement = createStatement.Replace("{sessionName}",sessionName); + connection.ServerConnection.ExecuteNonQuery(statement); + store.Refresh(); + session = store.Sessions[sessionName]; + if (session == null){ + throw new Exception(SR.SessionNotFound); + } + if (!session.IsRunning) + { + session.Start(); + } + + // create xevent session wrapper + return new XEventSession() + { + Session = store.Sessions[sessionName] + }; } /// @@ -345,6 +399,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler }); } + /// + /// Callback when a new session is created + /// + public void SessionCreatedNotification(string viewerId, string sessionName, string templateName) + { + // pass the profiler events on to the client + this.ServiceHost.SendEvent( + ProfilerSessionCreatedNotification.Type, + new ProfilerSessionCreatedParams() + { + OwnerUri = viewerId, + SessionName = sessionName, + TemplateName = templateName + }); + } + /// /// Disposes the Profiler Service /// diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Profiler/ProfilerServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Profiler/ProfilerServiceTests.cs index f0a730d8..a52650c9 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Profiler/ProfilerServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Profiler/ProfilerServiceTests.cs @@ -39,7 +39,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Profiler // start a new session var startParams = new StartProfilingParams(); startParams.OwnerUri = connectionResult.ConnectionInfo.OwnerUri; - startParams.TemplateName = "Standard"; + startParams.SessionName = "Standard"; string sessionId = null; var startContext = new Mock>(); @@ -47,7 +47,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Profiler .Returns((result) => { // capture the session id for sending the stop message - sessionId = result.SessionId; return Task.FromResult(0); }); @@ -82,7 +81,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Profiler { var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo("master"); ProfilerService profilerService = new ProfilerService(); - IXEventSession xeSession = profilerService.GetOrCreateXEventSession("Profiler", liveConnection.ConnectionInfo); + IXEventSession xeSession = profilerService.GetXEventSession("Profiler", liveConnection.ConnectionInfo); Assert.NotNull(xeSession); Assert.NotNull(xeSession.GetTargetXml()); } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs index 46963953..d359d611 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs @@ -40,7 +40,6 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler .Returns((result) => { // capture the session id for sending the stop message - sessionId = result.SessionId; return Task.FromResult(0); }); @@ -60,7 +59,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler var requestParams = new StartProfilingParams(); requestParams.OwnerUri = testUri; - requestParams.TemplateName = "Standard"; + requestParams.SessionName = "Standard"; // start profiling session await profilerService.HandleStartProfilingRequest(requestParams, requestContext.Object); diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerTestObjects.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerTestObjects.cs index b69010cd..96a51947 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerTestObjects.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerTestObjects.cs @@ -400,7 +400,21 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler public class TestXEventSessionFactory : IXEventSessionFactory { private int sessionNum = 1; - public IXEventSession GetOrCreateXEventSession(string template, ConnectionInfo connInfo) + public IXEventSession GetXEventSession(string sessionName, ConnectionInfo connInfo) + { + if(sessionNum == 1) + { + sessionNum = 2; + return new TestXEventSession1(); + } + else + { + sessionNum = 1; + return new TestXEventSession2(); + } + } + + public IXEventSession CreateXEventSession(string createStatement, string sessionName, ConnectionInfo connInfo) { if(sessionNum == 1) {