// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.Collections.Generic; using System.Linq; using Microsoft.SqlServer.Management.XEvent; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Profiler.Contracts; namespace Microsoft.SqlTools.ServiceLayer.Profiler { /// /// Profiler session class /// public class ProfilerSession { private static readonly TimeSpan DefaultPollingDelay = TimeSpan.FromSeconds(1); private object pollingLock = new object(); private bool isPolling = false; private DateTime lastPollTime = DateTime.Now.Subtract(DefaultPollingDelay); private TimeSpan pollingDelay = DefaultPollingDelay; private ProfilerEvent lastSeenEvent = null; /// /// Unique ID for the session /// public string SessionId { get; set; } /// /// Connection to use for the session /// public ConnectionInfo ConnectionInfo { get; set; } /// /// Underlying XEvent session wrapper /// public IXEventSession XEventSession { get; set; } /// /// Try to set the session into polling mode if criteria is meet /// /// True if session set to polling mode, False otherwise public bool TryEnterPolling() { lock (this.pollingLock) { if (!this.isPolling && DateTime.Now.Subtract(this.lastPollTime) >= pollingDelay) { this.isPolling = true; this.lastPollTime = DateTime.Now; return true; } else { return false; } } } /// /// Is the session currently being polled /// public bool IsPolling { get { return this.isPolling; } set { lock (this.pollingLock) { this.isPolling = value; } } } /// /// The delay between session polls /// public TimeSpan PollingDelay { get { return pollingDelay; } } /// /// Determine if an event was caused by the XEvent polling queries /// 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; } /// /// Removed profiler polling events from event list /// public List FilterProfilerEvents(List events) { int idx = events.Count; while (--idx >= 0) { if (IsProfilerEvent(events[idx])) { events.RemoveAt(idx); } } return events; } /// /// Filter the event list to not include previously seen events /// public List FilterOldEvents(List events) { if (lastSeenEvent != null) { // find the last event we've previously seen bool foundLastEvent = false; int idx = events.Count; while (--idx >= 0) { if (events[idx].Equals(lastSeenEvent)) { foundLastEvent = true; break; } } // remove all the events we've seen before if (foundLastEvent) { events.RemoveRange(0, idx + 1); } } // save the last event so we know where to clean-up the list from next time if (events.Count > 0) { lastSeenEvent = events.LastOrDefault(); } return events; } } }