mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-02 17:24:50 -05:00
Profiler notifications (#640)
* Initial changes for adding lost event notifications * Handling polling errors by notifying listeners * Restructuring lost events & testing * Minor fixes to tests * Add back in filtering * Changing how lost events are found * Cleaning up tests
This commit is contained in:
committed by
GitHub
parent
f244d307e2
commit
838a7e4fab
@@ -14,6 +14,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler.Contracts
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public List<ProfilerEvent> Events { get; set; }
|
||||
|
||||
public bool EventsLost { get; set; }
|
||||
}
|
||||
|
||||
public class ProfilerEventsAvailableNotification
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// 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 ProfilerSessionStoppedParams
|
||||
{
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
public int SessionId { get; set; }
|
||||
}
|
||||
|
||||
public class ProfilerSessionStoppedNotification
|
||||
{
|
||||
public static readonly
|
||||
EventType<ProfilerSessionStoppedParams> Type =
|
||||
EventType<ProfilerSessionStoppedParams>.Create("profiler/sessionstopped");
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
{
|
||||
public interface IProfilerSessionListener
|
||||
{
|
||||
void EventsAvailable(string sessionId, List<ProfilerEvent> events);
|
||||
void EventsAvailable(string sessionId, List<ProfilerEvent> events, bool eventsLost);
|
||||
|
||||
void SessionStopped(string viewerId, int sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
/// <summary>
|
||||
/// Callback when profiler events are available
|
||||
/// </summary>
|
||||
public void EventsAvailable(string sessionId, List<ProfilerEvent> events)
|
||||
public void EventsAvailable(string sessionId, List<ProfilerEvent> events, bool eventsLost)
|
||||
{
|
||||
// pass the profiler events on to the client
|
||||
this.ServiceHost.SendEvent(
|
||||
@@ -276,7 +276,23 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
new ProfilerEventsAvailableParams()
|
||||
{
|
||||
OwnerUri = sessionId,
|
||||
Events = events
|
||||
Events = events,
|
||||
EventsLost = eventsLost
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback when the XEvent session is closed unexpectedly
|
||||
/// </summary>
|
||||
public void SessionStopped(string viewerId, int sessionId)
|
||||
{
|
||||
// notify the client that their session closed
|
||||
this.ServiceHost.SendEvent(
|
||||
ProfilerSessionStoppedNotification.Type,
|
||||
new ProfilerSessionStoppedParams()
|
||||
{
|
||||
OwnerUri = viewerId,
|
||||
SessionId = sessionId
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
private TimeSpan pollingDelay = DefaultPollingDelay;
|
||||
private ProfilerEvent lastSeenEvent = null;
|
||||
|
||||
private bool eventsLost = false;
|
||||
int lastSeenId = -1;
|
||||
|
||||
public bool pollImmediatly = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -87,6 +90,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Could events have been lost in the last poll
|
||||
/// </summary>
|
||||
public bool EventsLost
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.eventsLost;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if an event was caused by the XEvent polling queries
|
||||
/// </summary>
|
||||
@@ -129,13 +143,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
/// </summary>
|
||||
public void FilterOldEvents(List<ProfilerEvent> events)
|
||||
{
|
||||
if (lastSeenEvent != null)
|
||||
this.eventsLost = false;
|
||||
|
||||
if (lastSeenId != -1)
|
||||
{
|
||||
// find the last event we've previously seen
|
||||
bool foundLastEvent = false;
|
||||
int idx = events.Count;
|
||||
int earliestSeenEventId = int.Parse(events.LastOrDefault().Values["event_sequence"]);
|
||||
while (--idx >= 0)
|
||||
{
|
||||
// update the furthest back event we've found so far
|
||||
earliestSeenEventId = Math.Min(earliestSeenEventId, int.Parse(events[idx].Values["event_sequence"]));
|
||||
|
||||
if (events[idx].Equals(lastSeenEvent))
|
||||
{
|
||||
foundLastEvent = true;
|
||||
@@ -148,11 +168,18 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
{
|
||||
events.RemoveRange(0, idx + 1);
|
||||
}
|
||||
else if(earliestSeenEventId > (lastSeenId + 1))
|
||||
{
|
||||
// if there's a gap between the expected next event sequence
|
||||
// and the furthest back event seen, we know we've lost events
|
||||
this.eventsLost = true;
|
||||
}
|
||||
|
||||
// save the last event so we know where to clean-up the list from next time
|
||||
if (events.Count > 0)
|
||||
{
|
||||
lastSeenEvent = events.LastOrDefault();
|
||||
lastSeenId = int.Parse(lastSeenEvent.Values["event_sequence"]);
|
||||
}
|
||||
}
|
||||
else // first poll at start of session, all data is old
|
||||
@@ -161,6 +188,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
if (events.Count > 0)
|
||||
{
|
||||
lastSeenEvent = events.LastOrDefault();
|
||||
lastSeenId = int.Parse(lastSeenEvent.Values["event_sequence"]);
|
||||
}
|
||||
|
||||
// ignore all events before the session began
|
||||
|
||||
@@ -233,7 +233,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
var events = PollSession(session);
|
||||
if (events.Count > 0)
|
||||
bool eventsLost = session.EventsLost;
|
||||
if (events.Count > 0 || eventsLost)
|
||||
{
|
||||
// notify all viewers for the polled session
|
||||
List<string> viewerIds = this.sessionViewers[session.XEventSession.Id];
|
||||
@@ -241,7 +242,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
{
|
||||
if (allViewers[viewerId].active)
|
||||
{
|
||||
SendEventsToListeners(viewerId, events);
|
||||
SendEventsToListeners(viewerId, events, eventsLost);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,9 +275,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (XEventException)
|
||||
{
|
||||
SendStoppedSessionInfoToListeners(session.XEventSession.Id);
|
||||
ProfilerSession tempSession;
|
||||
RemoveSession(session.XEventSession.Id, out tempSession);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Warning, "Failed to pool session. error: " + ex.Message);
|
||||
Logger.Write(LogLevel.Warning, "Failed to poll session. error: " + ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -288,15 +295,32 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notify listeners when new profiler events are available
|
||||
/// Notify listeners about closed sessions
|
||||
/// </summary>
|
||||
private void SendEventsToListeners(string sessionId, List<ProfilerEvent> events)
|
||||
private void SendStoppedSessionInfoToListeners(int sessionId)
|
||||
{
|
||||
lock (listenersLock)
|
||||
{
|
||||
foreach (var listener in this.listeners)
|
||||
{
|
||||
listener.EventsAvailable(sessionId, events);
|
||||
foreach(string viewerId in sessionViewers[sessionId])
|
||||
{
|
||||
listener.SessionStopped(viewerId, sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notify listeners when new profiler events are available
|
||||
/// </summary>
|
||||
private void SendEventsToListeners(string sessionId, List<ProfilerEvent> events, bool eventsLost)
|
||||
{
|
||||
lock (listenersLock)
|
||||
{
|
||||
foreach (var listener in this.listeners)
|
||||
{
|
||||
listener.EventsAvailable(sessionId, events, eventsLost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user