Bugs fixes so XEvent profiler isn't broken (#577)

* Fix a few issues with profiler method handlers

* Filter out profiler polling events

* Add a unit test for profiler events

* Add method comment headers
This commit is contained in:
Karl Burtram
2018-01-17 18:21:40 -08:00
committed by GitHub
parent 7b1a88f842
commit 0121531bf6
7 changed files with 110 additions and 12 deletions

View File

@@ -11,7 +11,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts
{ {
public class ProfilerEventsAvailableParams public class ProfilerEventsAvailableParams
{ {
public string SessionId { get; set; } public string OwnerUri { get; set; }
public List<ProfilerEvent> Events { get; set; } public List<ProfilerEvent> Events { get; set; }
} }
@@ -23,5 +23,3 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts
EventType<ProfilerEventsAvailableParams>.Create("profiler/eventsavailable"); EventType<ProfilerEventsAvailableParams>.Create("profiler/eventsavailable");
} }
} }

View File

@@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts
/// </summary> /// </summary>
public class StopProfilingParams public class StopProfilingParams
{ {
public string SessionId { get; set; } public string OwnerUri { get; set; }
} }
public class StopProfilingResult public class StopProfilingResult

View File

@@ -129,7 +129,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
if (connInfo != null) if (connInfo != null)
{ {
ProfilerSession session = StartSession(connInfo); ProfilerSession session = StartSession(parameters.OwnerUri, connInfo);
result.SessionId = session.SessionId; result.SessionId = session.SessionId;
result.Succeeded = true; result.Succeeded = true;
} }
@@ -154,7 +154,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
{ {
try try
{ {
monitor.StopMonitoringSession(parameters.SessionId); monitor.StopMonitoringSession(parameters.OwnerUri);
await requestContext.SendResult(new StopProfilingResult await requestContext.SendResult(new StopProfilingResult
{ {
Succeeded = true Succeeded = true
@@ -169,13 +169,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
/// <summary> /// <summary>
/// Starts a new profiler session for the provided connection /// Starts a new profiler session for the provided connection
/// </summary> /// </summary>
internal ProfilerSession StartSession(ConnectionInfo connInfo) internal ProfilerSession StartSession(string sessionId, ConnectionInfo connInfo)
{ {
// create a new XEvent session and Profiler session // create a new XEvent session and Profiler session
var xeSession = this.XEventSessionFactory.CreateXEventSession(connInfo); var xeSession = this.XEventSessionFactory.CreateXEventSession(connInfo);
var profilerSession = new ProfilerSession() var profilerSession = new ProfilerSession()
{ {
SessionId = Guid.NewGuid().ToString(), SessionId = sessionId,
XEventSession = xeSession XEventSession = xeSession
}; };
@@ -208,8 +208,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
private static Session GetOrCreateSession(SqlStoreConnection connection, string sessionName) private static Session GetOrCreateSession(SqlStoreConnection connection, string sessionName)
{ {
XEStore store = new XEStore(connection); XEStore store = new XEStore(connection);
Session session = store.Sessions["Profiler"]; Session session = store.Sessions[sessionName];
// start the session if it isn't already running // start the session if it isn't already running
if (session == null)
{
session = CreateSession(connection, sessionName);
}
if (session != null && !session.IsRunning) if (session != null && !session.IsRunning)
{ {
session.Start(); session.Start();
@@ -217,6 +222,38 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
return session; return session;
} }
private static Session CreateSession(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)";
connection.ServerConnection.ExecuteNonQuery(createSessionSql);
XEStore store = new XEStore(connection);
return store.Sessions[sessionName];
}
/// <summary> /// <summary>
/// Callback when profiler events are available /// Callback when profiler events are available
/// </summary> /// </summary>
@@ -227,7 +264,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
ProfilerEventsAvailableNotification.Type, ProfilerEventsAvailableNotification.Type,
new ProfilerEventsAvailableParams() new ProfilerEventsAvailableParams()
{ {
SessionId = sessionId, OwnerUri = sessionId,
Events = events Events = events
}); });
} }

View File

@@ -89,6 +89,42 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
} }
} }
/// <summary>
/// Determine if an event was caused by the XEvent polling queries
/// </summary>
private bool IsProfilerEvent(ProfilerEvent currentEvent)
{
if (string.IsNullOrWhiteSpace(currentEvent.Name) || currentEvent.Values == null)
{
return false;
}
if ((currentEvent.Name.Equals("sql_batch_completed")
|| currentEvent.Name.Equals("sql_batch_starting"))
&& currentEvent.Values.ContainsKey("batch_text"))
{
return currentEvent.Values["batch_text"].Contains("SELECT target_data FROM sys.dm_xe_session_targets");
}
return false;
}
/// <summary>
/// Removed profiler polling events from event list
/// </summary>
public List<ProfilerEvent> FilterProfilerEvents(List<ProfilerEvent> events)
{
int idx = events.Count;
while (--idx >= 0)
{
if (IsProfilerEvent(events[idx]))
{
events.RemoveAt(idx);
}
}
return events;
}
/// <summary> /// <summary>
/// Filter the event list to not include previously seen events /// Filter the event list to not include previously seen events
/// </summary> /// </summary>

View File

@@ -160,7 +160,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
session.IsPolling = false; session.IsPolling = false;
} }
return session.FilterOldEvents(events); return session.FilterProfilerEvents(
session.FilterOldEvents(events)
);
} }
/// <summary> /// <summary>

View File

@@ -104,7 +104,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile)) if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile))
{ {
if (IsUntitled(resolvedFile.FilePath) if (IsUntitled(resolvedFile.FilePath)
|| !resolvedFile.CanReadFromDisk) || !resolvedFile.CanReadFromDisk
|| !File.Exists(resolvedFile.FilePath))
{ {
// It's either not a registered untitled file, or not a valid file on disk // It's either not a registered untitled file, or not a valid file on disk
// so any attempt to read from disk will fail. // so any attempt to read from disk will fail.

View File

@@ -48,6 +48,30 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler
Assert.Equal(newProfilerEvents.Count, 0); Assert.Equal(newProfilerEvents.Count, 0);
} }
/// <summary>
/// Test the FilterProfilerEvents method
/// </summary>
[Fact]
public void TestFilterProfilerEvents()
{
// create a profiler session and get some test events
var profilerSession = new ProfilerSession();
var profilerEvents = ProfilerTestObjects.TestProfilerEvents;
int expectedEventCount = profilerEvents.Count;
// add a new "Profiler Polling" event
var newEvent = new ProfilerEvent("sql_batch_completed", "1/1/2017");
newEvent.Values.Add("batch_text", "SELECT target_data FROM sys.dm_xe_session_targets");
profilerEvents.Add(newEvent);
// verify that the polling event is removed
Assert.Equal(profilerEvents.Count, expectedEventCount + 1);
var newProfilerEvents = profilerSession.FilterProfilerEvents(profilerEvents);
Assert.Equal(newProfilerEvents.Count, expectedEventCount);
}
/// <summary> /// <summary>
/// Test the TryEnterPolling method /// Test the TryEnterPolling method
/// </summary> /// </summary>