NB: if you don't dispose of this, your app might not really exit.
Inheritance: IDisposable
Esempio n. 1
0
		/// <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>
		/// 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();

		}
Esempio n. 3
0
        /// <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 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();
        }