diff --git a/CHANGELOG.md b/CHANGELOG.md index 6757dce..a1b2ef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] + +## [6.1.0] - 2026-02-27 + +### Added +- [DesktopAnalytics] Made it possible to disable and enable tracking while running the application + +## [6.0.3] - 2026-01-09 + +### Changed +- [DesktopAnalytics] Added DeviceUILanguage application property + +## [6.0.2] - 2025-05-09 + +### Fixed +- [DesktopAnalytics] Prevented crash in constructor if config file cannot be upgraded or saved + ## [6.0.0] - 2024-04-22 ### Changed diff --git a/src/DesktopAnalytics/Analytics.cs b/src/DesktopAnalytics/Analytics.cs index 2c5e5c4..1ad59d2 100644 --- a/src/DesktopAnalytics/Analytics.cs +++ b/src/DesktopAnalytics/Analytics.cs @@ -16,6 +16,9 @@ using JetBrains.Annotations; using Newtonsoft.Json.Linq; using Segment.Serialization; +using static System.Attribute; +using static System.Environment; +using static System.Environment.SpecialFolder; using static System.String; namespace DesktopAnalytics @@ -37,6 +40,7 @@ namespace DesktopAnalytics public class Analytics : IDisposable { private const string kUserConfigFileName = "user.config"; + private const int kMaxExceptionReportsPerRun = 10; /// /// Collection of "location"-specific traits about the user. This information is @@ -51,9 +55,7 @@ public class Analytics : IDisposable private readonly Dictionary _propertiesThatGoWithEveryEvent; private static int s_exceptionCount = 0; - const int MAX_EXCEPTION_REPORTS_PER_RUN = 10; - - private readonly IClient Client; + private readonly IClient _client; /// /// Initialized a singleton; after calling this, use Analytics.Track() for each event. @@ -100,7 +102,7 @@ private void UpdateServerInformationOnThisUser() if (!AllowTracking) return; - Client.Identify(AnalyticsSettings.Default.IdForAnalytics, s_traits, s_locationInfo); + _client.Identify(AnalyticsSettings.Default.IdForAnalytics, s_traits, s_locationInfo); } /// @@ -143,12 +145,12 @@ public Analytics(string apiSecret, UserInfo userInfo, Dictionary> GetLocationPropertiesOfThisMachine() - { - using (var client = new WebClient()) - { - var json = client.DownloadString("http://freegeoip.net/json"); - JObject results = JObject.Parse(json); - yield return new KeyValuePair("Country", (string)results["country_name"]); - yield return new KeyValuePair("City", (string)results["city"]); - } - } + //private IEnumerable> GetLocationPropertiesOfThisMachine() + //{ + // using (var client = new WebClient()) + // { + // var json = client.DownloadString("http://freegeoip.net/json"); + // JObject results = JObject.Parse(json); + // yield return new KeyValuePair("Country", (string)results["country_name"]); + // yield return new KeyValuePair("City", (string)results["city"]); + // } + //} /// /// Records an event @@ -610,12 +614,12 @@ public static void ReportException(Exception e, Dictionary moreP // we had an incident where some problem caused a user to emit hundreds of thousands of exceptions, // in the background, blowing through our Analytics service limits and getting us kicked off. - if (s_exceptionCount > MAX_EXCEPTION_REPORTS_PER_RUN) + if (s_exceptionCount > kMaxExceptionReportsPerRun) { return; } - var props = new JsonObject() + var props = new JsonObject { { "Message", e.Message }, { "Stack Trace", e.StackTrace } @@ -623,9 +627,7 @@ public static void ReportException(Exception e, Dictionary moreP if (moreProperties != null) { foreach (var key in moreProperties.Keys) - { props.Add(key, moreProperties[key]); - } } TrackWithApplicationProperties("Exception", props); } @@ -634,31 +636,24 @@ private static JsonObject MakeSegmentIOProperties(Dictionary pro { var prop = new JsonObject(); foreach (var key in properties.Keys) - { prop.Add(key, properties[key]); - } return prop; } - private static void Client_Succeeded(string action) - { - Debug.WriteLine($"Analytics action succeeded: {action}"); - } - private static void Client_Failed(Exception e) { - Debug.WriteLine($"**** Analytics action Failed: {Environment.NewLine}{e.StackTrace}"); + Debug.WriteLine($"**** Analytics action Failed: {NewLine}{e.StackTrace}"); } public void Dispose() { - Client?.ShutDown(); + _client?.ShutDown(); } /// /// Indicates whether we are tracking or not /// - public static bool AllowTracking { get; private set; } + public static bool AllowTracking { get; set; } #region OSVersion class Version @@ -685,7 +680,7 @@ public bool Match(OperatingSystem os) private static string GetOperatingSystemLabel() { - if (Environment.OSVersion.Platform == PlatformID.Unix) + if (OSVersion.Platform == PlatformID.Unix) { return UnixName == "Linux" ? $"{LinuxVersion} / {LinuxDesktop}" : UnixName; } @@ -705,23 +700,23 @@ private static string GetOperatingSystemLabel() foreach (var version in list) { - if (version.Match(Environment.OSVersion)) - return version.Label + " " + Environment.OSVersion.ServicePack; + if (version.Match(OSVersion)) + return version.Label + " " + OSVersion.ServicePack; } // Handle any as yet unrecognized (possibly unmanifested) versions, or anything that reported its self as Windows 8. - if (Environment.OSVersion.Platform == PlatformID.Win32NT) + if (OSVersion.Platform == PlatformID.Win32NT) { - return GetWindowsVersionInfoFromNetworkAPI() + " " + Environment.OSVersion.ServicePack; + return GetWindowsVersionInfoFromNetworkAPI() + " " + OSVersion.ServicePack; } - return Environment.OSVersion.VersionString; + return OSVersion.VersionString; } private string GetOperatingSystemVersionLabel() { - return Environment.OSVersion.Version.ToString(); + return OSVersion.Version.ToString(); } #region Windows8PlusVersionReportingSupport @@ -786,7 +781,7 @@ private static string UnixName { get { - if (Environment.OSVersion.Platform != PlatformID.Unix) + if (OSVersion.Platform != PlatformID.Unix) return Empty; if (s_unixName == null) { @@ -812,16 +807,16 @@ private static string UnixName } } - private static string _linuxVersion; + private static string s_linuxVersion; private static string LinuxVersion { get { - if (Environment.OSVersion.Platform != PlatformID.Unix) + if (OSVersion.Platform != PlatformID.Unix) return Empty; - if (_linuxVersion == null) + if (s_linuxVersion == null) { - _linuxVersion = Empty; + s_linuxVersion = Empty; if (File.Exists("/etc/wasta-release")) { var versionData = File.ReadAllText("/etc/wasta-release"); @@ -830,7 +825,7 @@ private static string LinuxVersion { if (line.StartsWith("DESCRIPTION=\"")) { - _linuxVersion = line.Substring(13).Trim('"'); + s_linuxVersion = line.Substring(13).Trim('"'); break; } } @@ -843,7 +838,7 @@ private static string LinuxVersion { if (t.StartsWith("DISTRIB_DESCRIPTION=\"")) { - _linuxVersion = t.Substring(21).Trim('"'); + s_linuxVersion = t.Substring(21).Trim('"'); break; } } @@ -851,10 +846,10 @@ private static string LinuxVersion else { // If it's linux, it really should have /etc/lsb-release! - _linuxVersion = Environment.OSVersion.VersionString; + s_linuxVersion = OSVersion.VersionString; } } - return _linuxVersion; + return s_linuxVersion; } } @@ -866,15 +861,15 @@ private static string DesktopEnvironment { get { - if (Environment.OSVersion.Platform != PlatformID.Unix) - return Environment.OSVersion.Platform.ToString(); + if (OSVersion.Platform != PlatformID.Unix) + return OSVersion.Platform.ToString(); // see http://unix.stackexchange.com/a/116694 // and http://askubuntu.com/a/227669 - var currentDesktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP"); + var currentDesktop = GetEnvironmentVariable("XDG_CURRENT_DESKTOP"); if (IsNullOrEmpty(currentDesktop)) { - var dataDirs = Environment.GetEnvironmentVariable("XDG_DATA_DIRS"); + var dataDirs = GetEnvironmentVariable("XDG_DATA_DIRS"); if (dataDirs != null) { dataDirs = dataDirs.ToLowerInvariant(); @@ -886,7 +881,7 @@ private static string DesktopEnvironment currentDesktop = "Gnome"; } if (IsNullOrEmpty(currentDesktop)) - currentDesktop = Environment.GetEnvironmentVariable("GDMSESSION") ?? Empty; + currentDesktop = GetEnvironmentVariable("GDMSESSION") ?? Empty; } return currentDesktop.ToLowerInvariant(); } @@ -900,25 +895,25 @@ private static string LinuxDesktop { get { - if (Environment.OSVersion.Platform != PlatformID.Unix) + if (OSVersion.Platform != PlatformID.Unix) return Empty; if (s_linuxDesktop == null) { // see http://unix.stackexchange.com/a/116694 // and http://askubuntu.com/a/227669 var currentDesktop = DesktopEnvironment; - var mirSession = Environment.GetEnvironmentVariable("MIR_SERVER_NAME"); + var mirSession = GetEnvironmentVariable("MIR_SERVER_NAME"); var additionalInfo = Empty; if (!IsNullOrEmpty(mirSession)) additionalInfo = " [display server: Mir]"; - var gdmSession = Environment.GetEnvironmentVariable("GDMSESSION") ?? "not set"; + var gdmSession = GetEnvironmentVariable("GDMSESSION") ?? "not set"; s_linuxDesktop = $"{currentDesktop} ({gdmSession}{additionalInfo})"; } return s_linuxDesktop; } } - public static Statistics Statistics => s_singleton.Client.Statistics; + public static Statistics Statistics => s_singleton._client.Statistics; /// /// All calls to Client.Track should run through here so we can provide defaults for every event @@ -933,11 +928,10 @@ private static void TrackWithApplicationProperties(string eventName, JsonObject properties = new JsonObject(); foreach (var p in s_singleton._propertiesThatGoWithEveryEvent) { - if (properties.ContainsKey(p.Key)) - properties.Remove(p.Key); + properties.Remove(p.Key); properties.Add(p.Key, p.Value ?? Empty); } - s_singleton.Client.Track(AnalyticsSettings.Default.IdForAnalytics, eventName, properties); + s_singleton._client.Track(AnalyticsSettings.Default.IdForAnalytics, eventName, properties); } /// @@ -951,10 +945,7 @@ public static void SetApplicationProperty(string key, string value) throw new ArgumentNullException(key); if (value == null) value = Empty; - if (s_singleton._propertiesThatGoWithEveryEvent.ContainsKey(key)) - { - s_singleton._propertiesThatGoWithEveryEvent.Remove(key); - } + s_singleton._propertiesThatGoWithEveryEvent.Remove(key); s_singleton._propertiesThatGoWithEveryEvent.Add(key, value); } @@ -967,7 +958,7 @@ private static string GetUserNameForEvent() public static void FlushClient() { - s_singleton.Client.Flush(); + s_singleton._client.Flush(); } } } diff --git a/src/SampleApp/Program.cs b/src/SampleApp/Program.cs index 33c6e87..2957caa 100644 --- a/src/SampleApp/Program.cs +++ b/src/SampleApp/Program.cs @@ -44,7 +44,13 @@ static int Main(string[] args) Debug.WriteLine("Sleeping for 20 seconds to give it all a chance to send an event in the background..."); Thread.Sleep(20000); - Analytics.SetApplicationProperty("TimeSinceLaunch", "23 seconds"); + Analytics.AllowTracking = false; + Analytics.Track("Should not be tracked"); + Debug.WriteLine("Sleeping for 2 seconds just for fun"); + Thread.Sleep(2000); + + Analytics.AllowTracking = true; + Analytics.SetApplicationProperty("TimeSinceLaunch", "25 seconds"); Analytics.Track("SomeEvent", new Dictionary {{"SomeValue", "42"}}); Console.WriteLine("Sleeping for another 20 seconds to give it all a chance to send an event in the background..."); Thread.Sleep(20000);