/// <summary> /// Sets the context of this analytics call. Context contains information about the environment /// such as the app, the user agent, ip, etc .. /// </summary> /// <returns>This Options object for chaining.</returns> /// <param name="context">The visitor's context.</param> public Options SetContext (Context context) { this.Context = context; return this; }
/// <summary> /// Initialized a singleton; after calling this, use Analytics.Track() for each event. /// </summary> /// <param name="apiSecret">The segment.com apiSecret</param> /// <param name="userInfo">Information about the user that you have previous collected</param> /// <param name="propertiesThatGoWithEveryEvent">A set of key-value pairs to send with *every* event</param> /// <param name="allowTracking">If false, this will not do any communication with segment.io</param> public Analytics(string apiSecret, UserInfo userInfo, Dictionary<string, string> propertiesThatGoWithEveryEvent, bool allowTracking = true) { if (_singleton != null) { throw new ApplicationException("You can only construct a single Analytics object."); } _singleton = this; _propertiesThatGoWithEveryEvent = propertiesThatGoWithEveryEvent; _userInfo = userInfo; AllowTracking = allowTracking; //UrlThatReturnsExternalIpAddress is a static and should really be set before this is called, so don't mess with it if the clien has given us a different url to us if (string.IsNullOrEmpty(UrlThatReturnsExternalIpAddress)) UrlThatReturnsExternalIpAddress = "http://icanhazip.com";//went down: "http://ipecho.net/plain"; if (!AllowTracking) return; //bring in settings from any previous version if (AnalyticsSettings.Default.NeedUpgrade) { //see http://stackoverflow.com/questions/3498561/net-applicationsettingsbase-should-i-call-upgrade-every-time-i-load AnalyticsSettings.Default.Upgrade(); AnalyticsSettings.Default.NeedUpgrade = false; AnalyticsSettings.Default.Save(); } const string UserConfigFileName = "user.config"; if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics)) { // Apparently a first-time install. Any chance we can migrate settings from another channel of this app? // We really want to use the same ID if possible to keep our statistics valid. // We need to get the company name and exe name of the main application, without introducing a dependency on // Windows.Forms, so we can't use the Windows.Forms.Application methods. var entryAssembly = Assembly.GetEntryAssembly(); // the main exe assembly var productExe = Path.GetFileNameWithoutExtension(entryAssembly.Location); AssemblyCompanyAttribute companyAttribute = AssemblyCompanyAttribute.GetCustomAttribute(entryAssembly, typeof(AssemblyCompanyAttribute)) as AssemblyCompanyAttribute; if (companyAttribute != null && !string.IsNullOrEmpty(productExe)) { string companyName = companyAttribute.Company; var settingsLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), companyName); // Coincidentally, 5 is a good length for Bloom...better heuristic later? // For example, we could // - look for the last capital letter, and truncate to there. BloomAlpha->Bloom; HearThisAlpha->HearThis; *HearThis->Hear; TEX->?TE; TEXAlpha->TEX; BloomBetaOne->*BloomBeta // - look for the first non-initial capital letter, and truncate from there on. BloomAlpha->Bloom, HearThisAlpha->*Hear; HearThis->*Hear; TEX->*T' TEXAlpha->TEX; BloomBetaOne->Bloom // - look for a non-initial capital letter following at least one LC letter. Similar except TEX->TEX, TEXAlpha->*TEXAlpha. // In general, truncating too much is better than too little; too much just makes us slow, while too little may make us miss useful results. // It's true that truncating too much (like TEX->TE) may cause us to fetch an analytics ID from the wrong program. But even this is harmless, AFAIK. var index = Math.Min(5, productExe.Length); var prefix = productExe.Substring(0, index); var pattern = prefix + "*"; var possibleParentFolders = Directory.GetDirectories(settingsLocation, pattern); var possibleFolders = new List<string>(); foreach (var folder in possibleParentFolders) { possibleFolders.AddRange(Directory.GetDirectories(folder).Where(f => File.Exists(Path.Combine(f, UserConfigFileName)))); } possibleFolders.Sort((first, second) => { if (first == second) return 0; var firstConfigPath = Path.Combine(first, UserConfigFileName); var secondConfigPath = Path.Combine(second, UserConfigFileName); // Reversing the arguments like this means that second comes before first if it has a LARGER mod time. // That is, we end up with the most recently modified user.config first. return new FileInfo(secondConfigPath).LastWriteTimeUtc.CompareTo(new FileInfo(firstConfigPath).LastWriteTimeUtc); }); foreach (var folder in possibleFolders) { try { var doc = XDocument.Load(Path.Combine(folder, UserConfigFileName)); var idSetting = doc.XPathSelectElement( "configuration/userSettings/DesktopAnalytics.AnalyticsSettings/setting[@name='IdForAnalytics']"); if (idSetting == null) continue; string analyticsId = idSetting.Value; if (string.IsNullOrEmpty(analyticsId)) continue; AnalyticsSettings.Default.IdForAnalytics = analyticsId; AnalyticsSettings.Default.FirstName = ExtractSetting(AnalyticsSettings.Default.FirstName, doc, "FirstName"); AnalyticsSettings.Default.LastName = ExtractSetting(AnalyticsSettings.Default.LastName, doc, "LastName"); AnalyticsSettings.Default.LastVersionLaunched = ExtractSetting(AnalyticsSettings.Default.LastVersionLaunched, doc, "LastVersionLaunched"); AnalyticsSettings.Default.Email = ExtractSetting(AnalyticsSettings.Default.Email, doc, "Email"); AnalyticsSettings.Default.Save(); break; } catch (Exception) { // If anything goes wrong we just won't try to get our ID from this source. } } } } Segment.Analytics.Initialize(apiSecret); Segment.Analytics.Client.Failed += Client_Failed; Segment.Analytics.Client.Succeeded += Client_Succeeded; if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics)) { AnalyticsSettings.Default.IdForAnalytics = Guid.NewGuid().ToString(); AnalyticsSettings.Default.Save(); } var context = new Context(); context.Add("language", _userInfo.UILanguageCode); _options = new Options(); _options.SetContext(context); UpdateSegmentIOInformationOnThisUser(); ReportIpAddressOfThisMachineAsync(); //this will take a while and may fail, so just do it when/if we can string versionNumberWithBuild = ""; try { versionNumberWithBuild = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(); } catch (NullReferenceException) { try { // GetEntryAssembly is null for MAF plugins versionNumberWithBuild = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); } catch (NullReferenceException) { // This probably can't happen, but if it does, just roll with it. } } string versionNumber = versionNumberWithBuild.Split('.').Take(2).Aggregate((a, b) => a + "." + b); SetApplicationProperty("Version", versionNumber); SetApplicationProperty("FullVersion", versionNumberWithBuild); SetApplicationProperty("UserName", GetUserNameForEvent()); SetApplicationProperty("Browser", GetOperatingSystemLabel()); if (string.IsNullOrEmpty(AnalyticsSettings.Default.LastVersionLaunched)) { //"Created" is a special property that segment.io understands and coverts to equivalents in various analytics services //So it's not as descriptive for us as "FirstLaunchOnSystem", but it will give the best experience on the analytics sites. TrackWithApplicationProperties("Created"); } else if (AnalyticsSettings.Default.LastVersionLaunched != versionNumberWithBuild) { TrackWithApplicationProperties("Upgrade", new Properties { {"OldVersion", AnalyticsSettings.Default.LastVersionLaunched}, }); } //we want to record the launch event independent of whether we also recorded a special first launch // But that is done after we retrieve (or fail to retrieve) our external ip address. // See http://issues.bloomlibrary.org/youtrack/issue/BL-4011. AnalyticsSettings.Default.LastVersionLaunched = versionNumberWithBuild; AnalyticsSettings.Default.Save(); }
/// <summary> /// Options object that allows the specification of a timestamp, /// an anonymousId, a context, or target integrations. /// </summary> public Options () { this.Integrations = new Dict (); this.Context = new Context (); }
/// <summary> /// Initialized a singleton; after calling this, use Analytics.Track() for each event. /// </summary> /// <param name="apiSecret">The segment.com apiSecret</param> /// <param name="userInfo">Information about the user that you have previous collected</param> /// <param name="propertiesThatGoWithEveryEvent">A set of key-value pairs to send with *every* event</param> /// <param name="allowTracking">If false, this will not do any communication with segment.io</param> public Analytics(string apiSecret, UserInfo userInfo, Dictionary<string, string> propertiesThatGoWithEveryEvent, bool allowTracking = true) { if (_singleton != null) { throw new ApplicationException("You can only construct a single Analytics object."); } _singleton = this; _propertiesThatGoWithEveryEvent = propertiesThatGoWithEveryEvent; _userInfo = userInfo; AllowTracking = allowTracking; //UrlThatReturnsExternalIpAddress is a static and should really be set before this is called, so don't mess with it if the client has given us a different url to us if (string.IsNullOrEmpty(UrlThatReturnsExternalIpAddress)) UrlThatReturnsExternalIpAddress = "http://icanhazip.com"; //went down: "http://ipecho.net/plain"; if (!AllowTracking) return; //bring in settings from any previous version if (AnalyticsSettings.Default.NeedUpgrade) { //see http://stackoverflow.com/questions/3498561/net-applicationsettingsbase-should-i-call-upgrade-every-time-i-load AnalyticsSettings.Default.Upgrade(); AnalyticsSettings.Default.NeedUpgrade = false; AnalyticsSettings.Default.Save(); } if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics)) { // Apparently a first-time install. Any chance we can migrate settings from another channel of this app? // We really want to use the same ID if possible to keep our statistics valid. try { AttemptToGetUserIdSettingsFromDifferentChannel(); } catch (Exception) { // Oh, well, we tried. } } Segment.Analytics.Initialize(apiSecret); Segment.Analytics.Client.Failed += Client_Failed; Segment.Analytics.Client.Succeeded += Client_Succeeded; if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics)) { AnalyticsSettings.Default.IdForAnalytics = Guid.NewGuid().ToString(); AnalyticsSettings.Default.Save(); } var context = new Context(); context.Add("language", _userInfo.UILanguageCode); _options = new Options(); _options.SetContext(context); UpdateSegmentIOInformationOnThisUser(); ReportIpAddressOfThisMachineAsync(); //this will take a while and may fail, so just do it when/if we can string versionNumberWithBuild = ""; try { versionNumberWithBuild = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(); } catch (NullReferenceException) { try { // GetEntryAssembly is null for MAF plugins versionNumberWithBuild = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); } catch (NullReferenceException) { // This probably can't happen, but if it does, just roll with it. } } string versionNumber = versionNumberWithBuild.Split('.').Take(2).Aggregate((a, b) => a + "." + b); SetApplicationProperty("Version", versionNumber); SetApplicationProperty("FullVersion", versionNumberWithBuild); SetApplicationProperty("UserName", GetUserNameForEvent()); SetApplicationProperty("Browser", GetOperatingSystemLabel()); if (string.IsNullOrEmpty(AnalyticsSettings.Default.LastVersionLaunched)) { //"Created" is a special property that segment.io understands and coverts to equivalents in various analytics services //So it's not as descriptive for us as "FirstLaunchOnSystem", but it will give the best experience on the analytics sites. TrackWithApplicationProperties("Created"); } else if (AnalyticsSettings.Default.LastVersionLaunched != versionNumberWithBuild) { TrackWithApplicationProperties("Upgrade", new Properties { {"OldVersion", AnalyticsSettings.Default.LastVersionLaunched}, }); } // We want to record the launch event independent of whether we also recorded a special first launch // But that is done after we retrieve (or fail to retrieve) our external ip address. // See http://issues.bloomlibrary.org/youtrack/issue/BL-4011. AnalyticsSettings.Default.LastVersionLaunched = versionNumberWithBuild; AnalyticsSettings.Default.Save(); }
/// <summary> /// Options object that allows the specification of a timestamp, /// an anonymousId, a context, or target integrations. /// </summary> public Options () { Integrations = new Dict (); Context = new Context (); }
/// <summary> /// Initialized a singleton; after calling this, use Analytics.Track() for each event. /// </summary> /// <param name="apiSecret">The segment.com apiSecret</param> /// <param name="userInfo">Information about the user that you have previous collected</param> /// <param name="propertiesThatGoWithEveryEvent">A set of key-value pairs to send with *every* event</param> /// <param name="allowTracking">If false, this will not do any communication with segment.io</param> /// <param name="retainPii">If false, userInfo will be stripped/hashed/adjusted to prevent communication of /// personally identifiable information to the analytics server.</param> public Analytics(string apiSecret, UserInfo userInfo, Dictionary <string, string> propertiesThatGoWithEveryEvent, bool allowTracking = true, bool retainPii = false) { if (_singleton != null) { throw new ApplicationException("You can only construct a single Analytics object."); } _singleton = this; _propertiesThatGoWithEveryEvent = propertiesThatGoWithEveryEvent; _userInfo = retainPii ? userInfo : userInfo.CreateSanitized(); AllowTracking = allowTracking; // UrlThatReturnsExternalIpAddress is a static and should really be set before this is called, so don't mess with it if the client has given us a different url to us if (string.IsNullOrEmpty(UrlThatReturnsExternalIpAddress)) { UrlThatReturnsGeolocationJson = "http://ip-api.com/json/"; } if (!AllowTracking) { return; } //bring in settings from any previous version if (AnalyticsSettings.Default.NeedUpgrade) { //see http://stackoverflow.com/questions/3498561/net-applicationsettingsbase-should-i-call-upgrade-every-time-i-load AnalyticsSettings.Default.Upgrade(); AnalyticsSettings.Default.NeedUpgrade = false; AnalyticsSettings.Default.Save(); } if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics)) { // Apparently a first-time install. Any chance we can migrate settings from another channel of this app? // We really want to use the same ID if possible to keep our statistics valid. try { AttemptToGetUserIdSettingsFromDifferentChannel(); } catch (Exception) { // Oh, well, we tried. } } Segment.Analytics.Initialize(apiSecret); Segment.Analytics.Client.Failed += Client_Failed; Segment.Analytics.Client.Succeeded += Client_Succeeded; if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics)) { AnalyticsSettings.Default.IdForAnalytics = Guid.NewGuid().ToString(); AnalyticsSettings.Default.Save(); } var context = new Segment.Model.Context(); context.Add("language", _userInfo.UILanguageCode); _options = new Options(); _options.SetContext(context); UpdateSegmentIOInformationOnThisUser(); ReportIpAddressOfThisMachineAsync(); //this will take a while and may fail, so just do it when/if we can string versionNumberWithBuild = ""; try { versionNumberWithBuild = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(); } catch (NullReferenceException) { try { // GetEntryAssembly is null for MAF plugins versionNumberWithBuild = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); } catch (NullReferenceException) { // This probably can't happen, but if it does, just roll with it. } } string versionNumber = versionNumberWithBuild.Split('.').Take(2).Aggregate((a, b) => a + "." + b); SetApplicationProperty("Version", versionNumber); SetApplicationProperty("FullVersion", versionNumberWithBuild); SetApplicationProperty("UserName", GetUserNameForEvent()); SetApplicationProperty("Browser", GetOperatingSystemLabel()); SetApplicationProperty("64bit OS", Environment.Is64BitOperatingSystem.ToString()); SetApplicationProperty("64bit App", Environment.Is64BitProcess.ToString()); if (string.IsNullOrEmpty(AnalyticsSettings.Default.LastVersionLaunched)) { //"Created" is a special property that segment.io understands and coverts to equivalents in various analytics services //So it's not as descriptive for us as "FirstLaunchOnSystem", but it will give the best experience on the analytics sites. TrackWithApplicationProperties("Created"); } else if (AnalyticsSettings.Default.LastVersionLaunched != versionNumberWithBuild) { TrackWithApplicationProperties("Upgrade", new Properties { { "OldVersion", AnalyticsSettings.Default.LastVersionLaunched }, }); } // We want to record the launch event independent of whether we also recorded a special first launch // But that is done after we retrieve (or fail to retrieve) our external ip address. // See http://issues.bloomlibrary.org/youtrack/issue/BL-4011. AnalyticsSettings.Default.LastVersionLaunched = versionNumberWithBuild; AnalyticsSettings.Default.Save(); }
public Analytics(string apiSecret, UserInfo userInfo, bool allowTracking=true) { _userInfo = userInfo; AllowTracking = allowTracking; //UrlThatReturnsExternalIpAddress is a static and should really be set before this is called, so don't mess with it if the clien has given us a different url to us if(string.IsNullOrEmpty(UrlThatReturnsExternalIpAddress)) UrlThatReturnsExternalIpAddress = "http://icanhazip.com";//went down: "http://ipecho.net/plain"; if (!AllowTracking) return; //bring in settings from any previous version if (AnalyticsSettings.Default.NeedUpgrade) { //see http://stackoverflow.com/questions/3498561/net-applicationsettingsbase-should-i-call-upgrade-every-time-i-load AnalyticsSettings.Default.Upgrade(); AnalyticsSettings.Default.NeedUpgrade = false; AnalyticsSettings.Default.Save(); } Segment.Analytics.Initialize(apiSecret); Segment.Analytics.Client.Failed += Client_Failed; Segment.Analytics.Client.Succeeded += Client_Succeeded; if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics)) { AnalyticsSettings.Default.IdForAnalytics = Guid.NewGuid().ToString(); AnalyticsSettings.Default.Save(); } var context = new Context(); context.Add("language", _userInfo.UILanguageCode); _options = new Options(); _options.SetContext(context); UpdateSegmentIOInformationOnThisUser(); ReportIpAddressOfThisMachineAsync(); //this will take a while and may fail, so just do it when/if we can try { _applicationVersion = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(); } catch (NullReferenceException) { try { // GetEntryAssembly is null for MAF plugins _applicationVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); } catch (NullReferenceException) { // This probably can't happen, but if it does, just roll with it. } } if (string.IsNullOrEmpty(AnalyticsSettings.Default.LastVersionLaunched)) { //"Created" is a special property that segment.io understands and coverts to equivalents in various analytics services //So it's not as descriptive for us as "FirstLaunchOnSystem", but it will give the best experience on the analytics sites. TrackWithDefaultProperties("Created"); } else if (AnalyticsSettings.Default.LastVersionLaunched != _applicationVersion) { TrackWithDefaultProperties("Upgrade", new Properties { {"OldVersion", AnalyticsSettings.Default.LastVersionLaunched}, }); } //we want to record the launch event independent of whether we also recorded a special first launch TrackWithDefaultProperties("Launch"); AnalyticsSettings.Default.LastVersionLaunched = _applicationVersion; AnalyticsSettings.Default.Save(); }