Skip to content

Commit 80e993b

Browse files
authored
Breadcrumbs support for windows after the app restart/crash (#161)
* WiP * Finished breadcrumbs multi session support * override file if the breadcrumb file exists * breadcrumbs archive support for Windows - simplify the breadcrumb archive flow * Code review adjustements
1 parent 7545596 commit 80e993b

File tree

6 files changed

+91
-81
lines changed

6 files changed

+91
-81
lines changed

Runtime/BacktraceClient.cs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,14 @@ public Action<BacktraceReport> OnClientReportLimitReached
320320

321321
private INativeClient _nativeClient;
322322

323+
internal INativeClient NativeClient
324+
{
325+
get
326+
{
327+
return _nativeClient;
328+
}
329+
}
330+
323331
public bool EnablePerformanceStatistics
324332
{
325333
get
@@ -525,11 +533,6 @@ public void Refresh()
525533
#if !UNITY_WEBGL
526534
EnableMetrics(false);
527535
#endif
528-
var nativeAttachments = _clientReportAttachments.ToList()
529-
.Where(n => !string.IsNullOrEmpty(n))
530-
.OrderBy(System.IO.Path.GetFileName, StringComparer.InvariantCultureIgnoreCase)
531-
.ToList();
532-
533536
string breadcrumbsPath = string.Empty;
534537
if (Configuration.Enabled)
535538
{
@@ -543,24 +546,17 @@ public void Refresh()
543546
if (_breadcrumbs != null)
544547
{
545548
breadcrumbsPath = _breadcrumbs.GetBreadcrumbLogPath();
546-
547549
}
548550
}
549551
}
550-
551-
// send minidump files generated by unity engine or unity game, not captured by Windows native integration
552-
// this integration should start before native integration and before breadcrumbs integration
553-
// to allow algorithm to send breadcrumbs file - if the breadcrumb file is available
554-
var scopedAttributes = AttributeProvider.GenerateAttributes(false);
555-
#if UNITY_STANDALONE_WIN
556-
if (Configuration.SendUnhandledGameCrashesOnGameStartup && isActiveAndEnabled && Enabled)
557-
{
558-
StartCoroutine(Runtime.Native.Windows.NativeClient.SendUnhandledGameCrashesOnGameStartup(nativeAttachments, breadcrumbsPath, Configuration.GetFullDatabasePath(), BacktraceApi));
559-
}
560-
#endif
561-
562552
if (Database != null)
563553
{
554+
// send minidump files generated by unity engine or unity game, not captured by Windows native integration
555+
// this integration should start before native integration and before breadcrumbs integration
556+
// to allow algorithm to send breadcrumbs file - if the breadcrumb file is available
557+
var scopedAttributes = AttributeProvider.GenerateAttributes(false);
558+
559+
var nativeAttachments = GetNativeAttachments();
564560
// avoid adding breadcurmbs file earlier - to avoid managing breadcrumb file in two places
565561
// in windows managed integration with unity crash handler
566562
// breadcrumb path is required by native integration and will be added just before native integration initialization
@@ -1318,5 +1314,13 @@ private bool ShouldSkipReport(ReportFilterType type, Exception exception, string
13181314
|| (SkipReport != null && SkipReport.Invoke(type, exception, message));
13191315

13201316
}
1317+
1318+
internal IList<string> GetNativeAttachments()
1319+
{
1320+
return _clientReportAttachments
1321+
.Where(n => !string.IsNullOrEmpty(n))
1322+
.OrderBy(System.IO.Path.GetFileName, StringComparer.InvariantCultureIgnoreCase)
1323+
.ToList();
1324+
}
13211325
}
13221326
}

Runtime/BacktraceDatabase.cs

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Backtrace.Unity.Model.Breadcrumbs;
55
using Backtrace.Unity.Model.Breadcrumbs.Storage;
66
using Backtrace.Unity.Model.Database;
7+
using Backtrace.Unity.Runtime.Native;
78
using Backtrace.Unity.Services;
89
using Backtrace.Unity.Types;
910
using System;
@@ -27,6 +28,7 @@ public class BacktraceDatabase : MonoBehaviour, IBacktraceDatabase
2728

2829
private BacktraceBreadcrumbs _breadcrumbs;
2930

31+
private BacktraceClient _client;
3032
/// <summary>
3133
/// Backtrace Breadcrumbs
3234
/// </summary>
@@ -167,7 +169,8 @@ public void Reload()
167169
// validate configuration
168170
if (Configuration == null)
169171
{
170-
Configuration = GetComponent<BacktraceClient>().Configuration;
172+
_client = GetComponent<BacktraceClient>();
173+
Configuration = _client.Configuration;
171174
}
172175
if (Instance != null)
173176
{
@@ -261,10 +264,39 @@ private void Start()
261264
{
262265
return;
263266
}
267+
string breadcrumbPath = string.Empty;
268+
string breadcrumbArchive = string.Empty;
269+
270+
if (Breadcrumbs != null)
271+
{
272+
breadcrumbPath = Breadcrumbs.GetBreadcrumbLogPath();
273+
breadcrumbArchive = Breadcrumbs.Archive();
274+
}
264275
// load reports from hard drive
265-
LoadReports();
276+
LoadReports(breadcrumbPath, breadcrumbArchive);
266277
// remove orphaned files
267278
RemoveOrphaned();
279+
280+
// send minidump files generated by unity engine or unity game, not captured by Windows native integration
281+
// this integration should start before native integration and before breadcrumbs integration
282+
// to allow algorithm to send breadcrumbs file - if the breadcrumb file is available
283+
#if UNITY_STANDALONE_WIN
284+
285+
var isEnabled = Enable && Configuration.SendUnhandledGameCrashesOnGameStartup && isActiveAndEnabled;
286+
var hasNativeConfiguration = _client && _client.NativeClient != null && _client.NativeClient is IStartupMinidumpSender;
287+
if (isEnabled && hasNativeConfiguration)
288+
{
289+
var client = _client.NativeClient as IStartupMinidumpSender;
290+
var attachments = _client.GetNativeAttachments();
291+
if(!string.IsNullOrEmpty(breadcrumbArchive))
292+
{
293+
attachments.Add(breadcrumbArchive);
294+
}
295+
StartCoroutine(client.SendMinidumpOnStartup(
296+
clientAttachments: attachments,
297+
backtraceApi: BacktraceApi));
298+
}
299+
#endif
268300
// enable breadcrumb support after finishing loading reports
269301
EnableBreadcrumbsSupport();
270302
if (DatabaseSettings.AutoSendMode)
@@ -618,7 +650,7 @@ protected virtual bool InitializeDatabasePaths()
618650
/// <summary>
619651
/// Load all records stored in database path
620652
/// </summary>
621-
protected virtual void LoadReports()
653+
protected virtual void LoadReports(string breadcrumbPath, string breadcrumbArchive)
622654
{
623655
if (!Enable)
624656
{
@@ -629,15 +661,8 @@ protected virtual void LoadReports()
629661
{
630662
return;
631663
}
632-
string breadcrumbPath = string.Empty;
633-
string breadcrumbArchive = string.Empty;
634-
635-
if (Breadcrumbs != null)
636-
{
637-
breadcrumbPath = Breadcrumbs.GetBreadcrumbLogPath();
638-
breadcrumbArchive = Breadcrumbs.Archive();
639-
}
640664
var shouldUseArchiveBreadcrumbArchive = !string.IsNullOrEmpty(breadcrumbArchive);
665+
641666
foreach (var file in files)
642667
{
643668
var record = BacktraceDatabaseRecord.ReadFromFile(file);
@@ -751,6 +776,14 @@ private void IncrementBatchRetry()
751776
}
752777
}
753778
}
779+
internal string GetBreadcrumbsPath()
780+
{
781+
if (_breadcrumbs == null)
782+
{
783+
return string.Empty;
784+
}
785+
return _breadcrumbs.GetBreadcrumbLogPath();
786+
}
754787

755788
public bool EnableBreadcrumbsSupport()
756789
{
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Backtrace.Unity.Interfaces;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
5+
namespace Backtrace.Unity.Runtime.Native
6+
{
7+
internal interface IStartupMinidumpSender
8+
{
9+
IEnumerator SendMinidumpOnStartup(ICollection<string> clientAttachments, IBacktraceApi backtraceApi);
10+
}
11+
}

Runtime/Native/IStartupMinidumpSender.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Native/Windows/NativeClient.cs

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Backtrace.Unity.Tests.Runtime")]
2020
namespace Backtrace.Unity.Runtime.Native.Windows
2121
{
22-
internal sealed class NativeClient : NativeClientBase, INativeClient
22+
internal sealed class NativeClient : NativeClientBase, INativeClient, IStartupMinidumpSender
2323
{
2424
[Serializable]
2525
private class ScopedAttributesContainer
@@ -242,7 +242,7 @@ public void SetAttribute(string key, string value)
242242
/// <summary>
243243
/// Read directory structure in the native crash directory and send new crashes to Backtrace
244244
/// </summary>
245-
public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<string> clientAttachments, string breadcrumbPath, string databasePath, IBacktraceApi backtraceApi)
245+
public IEnumerator SendMinidumpOnStartup(ICollection<string> clientAttachments, IBacktraceApi backtraceApi)
246246
{
247247
// Path to the native crash directory
248248
string nativeCrashesDir = Path.Combine(
@@ -258,25 +258,6 @@ public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<stri
258258
? new List<string>()
259259
: new List<string>(clientAttachments);
260260

261-
// make sure - when user close game in the middle of sending data, the library won't have a chance to clean up temporary breadcurmb
262-
// file. Becuase of that we prefer to always check if we need to clean something that left in the previous application session
263-
264-
string breadcrumbsCopyName = string.Format("{0}-1", BacktraceStorageLogManager.BreadcrumbLogFilePrefix);
265-
string breadcrumbCopyPath = Path.Combine(databasePath, breadcrumbsCopyName);
266-
if (File.Exists(breadcrumbCopyPath))
267-
{
268-
File.Delete(breadcrumbCopyPath);
269-
}
270-
271-
272-
// determine if handler should create a copy of a breadcrumb file
273-
// on the application startup. This check also prevents a situation when
274-
// algorithm will try to copy a breacrumb file when a breadcrumbs file doesn't exist
275-
// Client prefers to make a copy of a breadcrumb file in the database directory. Otherwise, if database
276-
// for any reason in new session is not available, algorithm shouldn't make a copy.
277-
bool requireBreadcrumbsCopy = string.IsNullOrEmpty(breadcrumbPath) || string.IsNullOrEmpty(databasePath) ? false : true;
278-
bool copiedFile = false;
279-
280261
var crashDirs = Directory.GetDirectories(nativeCrashesDir);
281262

282263
IDictionary<string, string> attributes = GetScopedAttributes();
@@ -299,23 +280,6 @@ public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<stri
299280
{
300281
continue;
301282
}
302-
if (requireBreadcrumbsCopy)
303-
{
304-
try
305-
{
306-
File.Copy(breadcrumbPath, breadcrumbCopyPath);
307-
attachments.Add(breadcrumbCopyPath);
308-
copiedFile = true;
309-
}
310-
catch (Exception e)
311-
{
312-
Debug.LogWarning(string.Format("Cannot make a copy of the breadcrumb file in the database directory. Reason: {0}", e.Message));
313-
}
314-
finally
315-
{
316-
requireBreadcrumbsCopy = false;
317-
}
318-
}
319283
var dumpAttachment = crashFiles.Concat(attachments).Where(n => n != minidumpPath).ToList();
320284
yield return backtraceApi.SendMinidump(minidumpPath, dumpAttachment, attributes, (BacktraceResult result) =>
321285
{
@@ -325,19 +289,6 @@ public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<stri
325289
}
326290
});
327291
}
328-
if (copiedFile)
329-
{
330-
try
331-
{
332-
File.Delete(breadcrumbCopyPath);
333-
}
334-
catch (Exception e)
335-
{
336-
// The file will be cleaned on the library startup via database integration
337-
// if native client for any reason won't be able to remove it.
338-
Debug.LogWarning(string.Format("Cannot remove temporary breadcrumb file. Reason: {0}", e.Message));
339-
}
340-
}
341292
}
342293

343294
private string GetPluginDirectoryPath()

Tests/Runtime/Mocks/BacktraceDatabaseMock.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ protected override void RemoveOrphaned()
1212
Debug.Log("Removing old reports");
1313
}
1414

15-
protected override void LoadReports()
15+
protected override void LoadReports(string _, string __)
1616
{
1717
Debug.Log("Loading reports");
1818
}

0 commit comments

Comments
 (0)