diff --git a/AppInsights.WindowsDesktop/PersistenceChannel/PersistenceTransmitter.cs b/AppInsights.WindowsDesktop/PersistenceChannel/PersistenceTransmitter.cs index 518e273..ce7cbf0 100644 --- a/AppInsights.WindowsDesktop/PersistenceChannel/PersistenceTransmitter.cs +++ b/AppInsights.WindowsDesktop/PersistenceChannel/PersistenceTransmitter.cs @@ -30,7 +30,7 @@ internal class PersistenceTransmitter : IDisposable /// A list of senders that sends transmissions. /// private List senders = new List(); - + /// /// The storage that is used to persist all the transmissions. /// @@ -71,6 +71,11 @@ internal PersistenceTransmitter(StorageBase storage, int sendersCount, bool crea { this.mutex = new Mutex(initiallyOwned: false, name: this.storage.FolderName); } + // named mutex is not supported in Xamarin Android and iOS, it throws NotSupportedException, so we'll use unnamed mutex instead + catch (NotSupportedException) + { + this.mutex = new Mutex(initiallyOwned: false); + } catch (Exception e) { string errorMsg = string.Format(CultureInfo.InvariantCulture, "PersistenceTransmitter: Failed to construct the mutex: {0}", e); @@ -94,7 +99,7 @@ internal PersistenceTransmitter(StorageBase storage, int sendersCount, bool crea /// Gets a unique folder name. This folder will be used to store the transmission files. /// internal string StorageUniqueFolder - { + { get { return this.storage.FolderName; @@ -203,7 +208,7 @@ private void AcquireMutex(Action action) catch (ObjectDisposedException) { // if mutex or the auto reset event are disposed, just quit. - return; + return; } } } diff --git a/AppInsights.WindowsDesktop/PersistenceChannel/Sender.cs b/AppInsights.WindowsDesktop/PersistenceChannel/Sender.cs index 3f27c62..de3e6e3 100644 --- a/AppInsights.WindowsDesktop/PersistenceChannel/Sender.cs +++ b/AppInsights.WindowsDesktop/PersistenceChannel/Sender.cs @@ -7,6 +7,7 @@ namespace Microsoft.ApplicationInsights.Channel using System; using System.Globalization; using System.Net; + using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing; @@ -144,7 +145,7 @@ internal void ForceSendNow() /// Stops the sender. /// internal Task StopAsync() - { + { // After delayHandler is set, a sending iteration will immidiately start. // Seting stopped to ture, will cause the iteration to skip the actual sending and stop immediately. this.stopped = true; @@ -153,15 +154,15 @@ internal Task StopAsync() // if delayHandler was set while a transmision was being sent, the return task waill wait for it to finsih, for an additional second, // before it will mark the task as completed. return Task.Factory.StartNew(() => + { + try { - try - { - this.stoppedHandler.WaitOne(this.drainingTimeout); - } - catch (ObjectDisposedException) - { - } - }); + this.stoppedHandler.WaitOne(this.drainingTimeout); + } + catch (ObjectDisposedException) + { + } + }); } /// @@ -220,17 +221,26 @@ protected void SendLoop() /// When this value returns it will hold a recommendation for when to start the next sending iteration. /// A boolean value that indicates if there was a retriable error. protected virtual bool Send(StorageTransmission transmission, ref TimeSpan nextSendInterval) - { + { try { if (transmission != null) { transmission.SendAsync().ConfigureAwait(false).GetAwaiter().GetResult(); - + // After a successful sending, try immeidiately to send another transmission. nextSendInterval = this.SendingInterval; } } + // https://github.com/microsoft/ApplicationInsights-dotnet/blob/70e438848915ec163fd7794221b27be34260d3b4/BASE/src/Microsoft.ApplicationInsights/Channel/Transmission.cs#L158 + // HttpClient.SendAsync throws HttpRequestException only on the following scenarios: + // "The request failed due to an underlying issue such as network connectivity, DNS failure, server certificate validation or timeout." + // i.e for Server errors (500 status code), no exception is thrown. + catch (HttpRequestException) + { + nextSendInterval = this.CalculateNextInterval(null, nextSendInterval, this.maxIntervalBetweenRetries); + return true; + } catch (WebException e) { int? statusCode = GetStatusCode(e); @@ -252,7 +262,7 @@ protected virtual bool Send(StorageTransmission transmission, ref TimeSpan nextS /// Logging every interval will just make the log noisy. /// private static void LogInterval(TimeSpan prevSendInterval, TimeSpan nextSendInterval) - { + { if (Math.Abs(nextSendInterval.TotalSeconds - prevSendInterval.TotalSeconds) > 60) { CoreEventSource.Log.LogVerbose("next sending interval: " + nextSendInterval); @@ -263,7 +273,7 @@ private static void LogInterval(TimeSpan prevSendInterval, TimeSpan nextSendInte /// Return the status code from the web exception or null if no such code exists. /// private static int? GetStatusCode(WebException e) - { + { HttpWebResponse httpWebResponse = e.Response as HttpWebResponse; if (httpWebResponse != null) { diff --git a/AppInsights.WindowsDesktop/PersistenceChannel/Storage.cs b/AppInsights.WindowsDesktop/PersistenceChannel/Storage.cs index 313be14..3de4c70 100644 --- a/AppInsights.WindowsDesktop/PersistenceChannel/Storage.cs +++ b/AppInsights.WindowsDesktop/PersistenceChannel/Storage.cs @@ -184,7 +184,7 @@ internal override void Delete(StorageTransmission item) } internal override async Task EnqueueAsync(Transmission transmission) - { + { try { if (this.StorageFolder == null) @@ -294,7 +294,7 @@ private static string GetApplicationIdentity() domainDirecotry = AppDomain.CurrentDomain.BaseDirectory; } catch (AppDomainUnloadedException e) - { + { CoreEventSource.Log.LogVerbose(string.Format("GetApplicationIdentity: Failed to read the domain's base directory. Exception: {0}", e)); } @@ -314,10 +314,10 @@ private static string GetApplicationIdentity() } private static string GetSHA1Hash(string input) - { + { byte[] inputBits = Encoding.Unicode.GetBytes(input); try - { + { byte[] hashBits = new SHA1CryptoServiceProvider().ComputeHash(inputBits); var hashString = new StringBuilder(); foreach (byte b in hashBits) @@ -338,11 +338,15 @@ private DirectoryInfo GetApplicationFolder() { IDictionary environment = Environment.GetEnvironmentVariables(); - var folderOption1 = new { RootPath = environment["LOCALAPPDATA"] as string, AISubFolder = @"Microsoft\ApplicationInsights" }; - var folderOption2 = new { RootPath = environment["TEMP"] as string, AISubFolder = @"Microsoft\ApplicationInsights" }; - var folderOption3 = new { RootPath = environment["ProgramData"] as string, AISubFolder = @"Microsoft ApplicationInsights" }; + var folderOption1 = new { RootPath = environment["LOCALAPPDATA"] as string, AISubFolder = @"Microsoft\ApplicationInsights" }; + var folderOption2 = new { RootPath = environment["TEMP"] as string, AISubFolder = @"Microsoft\ApplicationInsights" }; + var folderOption3 = new { RootPath = environment["ProgramData"] as string, AISubFolder = @"Microsoft ApplicationInsights" }; + // ANDROID + var folderOption4 = new { RootPath = environment["TMPDIR"] as string, AISubFolder = @"Microsoft ApplicationInsights" }; + // iOS + var folderOption5 = new { RootPath = Path.GetTempPath(), AISubFolder = @"Microsoft ApplicationInsights" }; - foreach (var folderOption in new[] { folderOption1, folderOption2, folderOption3 }) + foreach (var folderOption in new[] { folderOption1, folderOption2, folderOption3, folderOption4, folderOption5 }) { try { diff --git a/version.json b/version.json index 04b5ba2..5a7d636 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "2.17", + "version": "2.18", "publicReleaseRefSpec": [ "^refs/heads/main$", // we release out of main "^refs/heads/dev$", // we release out of develop