Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions Runtime/BacktraceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,14 @@ public Action<BacktraceReport> OnClientReportLimitReached

private INativeClient _nativeClient;

internal INativeClient NativeClient
{
get
{
return _nativeClient;
}
}

public bool EnablePerformanceStatistics
{
get
Expand Down Expand Up @@ -525,11 +533,6 @@ public void Refresh()
#if !UNITY_WEBGL
EnableMetrics(false);
#endif
var nativeAttachments = _clientReportAttachments.ToList()
.Where(n => !string.IsNullOrEmpty(n))
.OrderBy(System.IO.Path.GetFileName, StringComparer.InvariantCultureIgnoreCase)
.ToList();

string breadcrumbsPath = string.Empty;
if (Configuration.Enabled)
{
Expand All @@ -543,24 +546,17 @@ public void Refresh()
if (_breadcrumbs != null)
{
breadcrumbsPath = _breadcrumbs.GetBreadcrumbLogPath();

}
}
}

// send minidump files generated by unity engine or unity game, not captured by Windows native integration
// this integration should start before native integration and before breadcrumbs integration
// to allow algorithm to send breadcrumbs file - if the breadcrumb file is available
var scopedAttributes = AttributeProvider.GenerateAttributes(false);
#if UNITY_STANDALONE_WIN
if (Configuration.SendUnhandledGameCrashesOnGameStartup && isActiveAndEnabled && Enabled)
{
StartCoroutine(Runtime.Native.Windows.NativeClient.SendUnhandledGameCrashesOnGameStartup(nativeAttachments, breadcrumbsPath, Configuration.GetFullDatabasePath(), BacktraceApi));
}
#endif

if (Database != null)
{
// send minidump files generated by unity engine or unity game, not captured by Windows native integration
// this integration should start before native integration and before breadcrumbs integration
// to allow algorithm to send breadcrumbs file - if the breadcrumb file is available
var scopedAttributes = AttributeProvider.GenerateAttributes(false);

var nativeAttachments = GetNativeAttachments();
// avoid adding breadcurmbs file earlier - to avoid managing breadcrumb file in two places
// in windows managed integration with unity crash handler
// breadcrumb path is required by native integration and will be added just before native integration initialization
Expand Down Expand Up @@ -1318,5 +1314,13 @@ private bool ShouldSkipReport(ReportFilterType type, Exception exception, string
|| (SkipReport != null && SkipReport.Invoke(type, exception, message));

}

internal IList<string> GetNativeAttachments()
{
return _clientReportAttachments
.Where(n => !string.IsNullOrEmpty(n))
.OrderBy(System.IO.Path.GetFileName, StringComparer.InvariantCultureIgnoreCase)
.ToList();
}
}
}
55 changes: 44 additions & 11 deletions Runtime/BacktraceDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Backtrace.Unity.Model.Breadcrumbs;
using Backtrace.Unity.Model.Breadcrumbs.Storage;
using Backtrace.Unity.Model.Database;
using Backtrace.Unity.Runtime.Native;
using Backtrace.Unity.Services;
using Backtrace.Unity.Types;
using System;
Expand All @@ -27,6 +28,7 @@ public class BacktraceDatabase : MonoBehaviour, IBacktraceDatabase

private BacktraceBreadcrumbs _breadcrumbs;

private BacktraceClient _client;
/// <summary>
/// Backtrace Breadcrumbs
/// </summary>
Expand Down Expand Up @@ -167,7 +169,8 @@ public void Reload()
// validate configuration
if (Configuration == null)
{
Configuration = GetComponent<BacktraceClient>().Configuration;
_client = GetComponent<BacktraceClient>();
Configuration = _client.Configuration;
}
if (Instance != null)
{
Expand Down Expand Up @@ -261,10 +264,39 @@ private void Start()
{
return;
}
string breadcrumbPath = string.Empty;
string breadcrumbArchive = string.Empty;

if (Breadcrumbs != null)
{
breadcrumbPath = Breadcrumbs.GetBreadcrumbLogPath();
breadcrumbArchive = Breadcrumbs.Archive();
}
// load reports from hard drive
LoadReports();
LoadReports(breadcrumbPath, breadcrumbArchive);
// remove orphaned files
RemoveOrphaned();

// send minidump files generated by unity engine or unity game, not captured by Windows native integration
// this integration should start before native integration and before breadcrumbs integration
// to allow algorithm to send breadcrumbs file - if the breadcrumb file is available
#if UNITY_STANDALONE_WIN

var isEnabled = Enable && Configuration.SendUnhandledGameCrashesOnGameStartup && isActiveAndEnabled;
var hasNativeConfiguration = _client && _client.NativeClient != null && _client.NativeClient is IStartupMinidumpSender;
if (isEnabled && hasNativeConfiguration)
{
var client = _client.NativeClient as IStartupMinidumpSender;
var attachments = _client.GetNativeAttachments();
if(!string.IsNullOrEmpty(breadcrumbArchive))
{
attachments.Add(breadcrumbArchive);
}
StartCoroutine(client.SendMinidumpOnStartup(
clientAttachments: attachments,
backtraceApi: BacktraceApi));
}
#endif
// enable breadcrumb support after finishing loading reports
EnableBreadcrumbsSupport();
if (DatabaseSettings.AutoSendMode)
Expand Down Expand Up @@ -618,7 +650,7 @@ protected virtual bool InitializeDatabasePaths()
/// <summary>
/// Load all records stored in database path
/// </summary>
protected virtual void LoadReports()
protected virtual void LoadReports(string breadcrumbPath, string breadcrumbArchive)
{
if (!Enable)
{
Expand All @@ -629,15 +661,8 @@ protected virtual void LoadReports()
{
return;
}
string breadcrumbPath = string.Empty;
string breadcrumbArchive = string.Empty;

if (Breadcrumbs != null)
{
breadcrumbPath = Breadcrumbs.GetBreadcrumbLogPath();
breadcrumbArchive = Breadcrumbs.Archive();
}
var shouldUseArchiveBreadcrumbArchive = !string.IsNullOrEmpty(breadcrumbArchive);

foreach (var file in files)
{
var record = BacktraceDatabaseRecord.ReadFromFile(file);
Expand Down Expand Up @@ -751,6 +776,14 @@ private void IncrementBatchRetry()
}
}
}
internal string GetBreadcrumbsPath()
{
if (_breadcrumbs == null)
{
return string.Empty;
}
return _breadcrumbs.GetBreadcrumbLogPath();
}

public bool EnableBreadcrumbsSupport()
{
Expand Down
11 changes: 11 additions & 0 deletions Runtime/Native/IStartupMinidumpSender.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Backtrace.Unity.Interfaces;
using System.Collections;
using System.Collections.Generic;

namespace Backtrace.Unity.Runtime.Native
{
internal interface IStartupMinidumpSender
{
IEnumerator SendMinidumpOnStartup(ICollection<string> clientAttachments, IBacktraceApi backtraceApi);
}
}
11 changes: 11 additions & 0 deletions Runtime/Native/IStartupMinidumpSender.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 2 additions & 51 deletions Runtime/Native/Windows/NativeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Backtrace.Unity.Tests.Runtime")]
namespace Backtrace.Unity.Runtime.Native.Windows
{
internal sealed class NativeClient : NativeClientBase, INativeClient
internal sealed class NativeClient : NativeClientBase, INativeClient, IStartupMinidumpSender
{
[Serializable]
private class ScopedAttributesContainer
Expand Down Expand Up @@ -242,7 +242,7 @@ public void SetAttribute(string key, string value)
/// <summary>
/// Read directory structure in the native crash directory and send new crashes to Backtrace
/// </summary>
public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<string> clientAttachments, string breadcrumbPath, string databasePath, IBacktraceApi backtraceApi)
public IEnumerator SendMinidumpOnStartup(ICollection<string> clientAttachments, IBacktraceApi backtraceApi)
{
// Path to the native crash directory
string nativeCrashesDir = Path.Combine(
Expand All @@ -258,25 +258,6 @@ public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<stri
? new List<string>()
: new List<string>(clientAttachments);

// make sure - when user close game in the middle of sending data, the library won't have a chance to clean up temporary breadcurmb
// file. Becuase of that we prefer to always check if we need to clean something that left in the previous application session

string breadcrumbsCopyName = string.Format("{0}-1", BacktraceStorageLogManager.BreadcrumbLogFilePrefix);
string breadcrumbCopyPath = Path.Combine(databasePath, breadcrumbsCopyName);
if (File.Exists(breadcrumbCopyPath))
{
File.Delete(breadcrumbCopyPath);
}


// determine if handler should create a copy of a breadcrumb file
// on the application startup. This check also prevents a situation when
// algorithm will try to copy a breacrumb file when a breadcrumbs file doesn't exist
// Client prefers to make a copy of a breadcrumb file in the database directory. Otherwise, if database
// for any reason in new session is not available, algorithm shouldn't make a copy.
bool requireBreadcrumbsCopy = string.IsNullOrEmpty(breadcrumbPath) || string.IsNullOrEmpty(databasePath) ? false : true;
bool copiedFile = false;

var crashDirs = Directory.GetDirectories(nativeCrashesDir);

IDictionary<string, string> attributes = GetScopedAttributes();
Expand All @@ -299,23 +280,6 @@ public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<stri
{
continue;
}
if (requireBreadcrumbsCopy)
{
try
{
File.Copy(breadcrumbPath, breadcrumbCopyPath);
attachments.Add(breadcrumbCopyPath);
copiedFile = true;
}
catch (Exception e)
{
Debug.LogWarning(string.Format("Cannot make a copy of the breadcrumb file in the database directory. Reason: {0}", e.Message));
}
finally
{
requireBreadcrumbsCopy = false;
}
}
var dumpAttachment = crashFiles.Concat(attachments).Where(n => n != minidumpPath).ToList();
yield return backtraceApi.SendMinidump(minidumpPath, dumpAttachment, attributes, (BacktraceResult result) =>
{
Expand All @@ -325,19 +289,6 @@ public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<stri
}
});
}
if (copiedFile)
{
try
{
File.Delete(breadcrumbCopyPath);
}
catch (Exception e)
{
// The file will be cleaned on the library startup via database integration
// if native client for any reason won't be able to remove it.
Debug.LogWarning(string.Format("Cannot remove temporary breadcrumb file. Reason: {0}", e.Message));
}
}
}

private string GetPluginDirectoryPath()
Expand Down
2 changes: 1 addition & 1 deletion Tests/Runtime/Mocks/BacktraceDatabaseMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ protected override void RemoveOrphaned()
Debug.Log("Removing old reports");
}

protected override void LoadReports()
protected override void LoadReports(string _, string __)
{
Debug.Log("Loading reports");
}
Expand Down