コード例 #1
0
 /// <summary>
 /// Create new instance of database record
 /// </summary>
 /// <param name="data">Diagnostic data</param>
 /// <param name="path">database path</param>
 public BacktraceDatabaseRecord(BacktraceData data, string path)
 {
     Id           = data.Uuid;
     Record       = data;
     _path        = path;
     RecordWriter = new BacktraceDatabaseRecordWriter(path);
 }
コード例 #2
0
        /// <summary>
        /// Send a report to Backtrace API
        /// </summary>
        /// <param name="report">Report to send</param>
        public virtual void Send(BacktraceReportBase <T> report)
        {
            //check rate limiting
            bool watcherValidation = _reportWatcher.WatchReport(report);

            if (!watcherValidation)
            {
                OnClientReportLimitReached?.Invoke();
                return;
            }
            //generate minidump and add minidump to report
            string minidumpPath = _database.GenerateMiniDump(report, MiniDumpType);

            if (!string.IsNullOrEmpty(minidumpPath))
            {
                report._attachmentPaths.Add(minidumpPath);
            }
            //create a JSON payload instance
            var data = new BacktraceData <T>(report, Attributes);

            //valid user custom events
            data = BeforeSend?.Invoke(data) ?? data;
            _backtraceApi.Send(data);

            //clear minidumps generated by app
            _database.ClearMiniDump(minidumpPath);
        }
コード例 #3
0
        /// <summary>
        /// Get path to Unity player logs.
        /// </summary>
        /// <returns>Path to unity player log</returns>
        private string GetUnityPlayerLogFile(BacktraceData backtraceData, string dataPrefix)
        {
            if (!_settings.AddUnityLogToReport)
            {
                return(string.Empty);
            }
            var playerLogPath =
#if UNITY_STANDALONE_LINUX
                string.Format("~/.config/unity3d/{0}/{1}/Player.log", Application.companyName, Application.productName);
#elif UNITY_STANDALONE_OSX
                string.Format("~/Library/Logs/{0}/{1}/Player.log", Application.companyName, Application.productName);
#elif UNITY_STANDALONE_WIN
                Path.Combine(
                    Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)).FullName,
                    "LocalLow",
                    Application.companyName,
                    Application.productName,
                    "Player.log");
#else
                string.Empty;
#endif
            if (string.IsNullOrEmpty(playerLogPath) || !File.Exists(playerLogPath))
            {
                return(string.Empty);
            }
            var databaseLogPath = Path.Combine(_settings.DatabasePath, string.Format("{0}-lg.log", dataPrefix));
            File.Copy(playerLogPath, databaseLogPath);
            return(databaseLogPath);
        }
コード例 #4
0
        /// <summary>
        /// Sending a diagnostic report data to server API.
        /// </summary>
        /// <param name="data">Diagnostic data</param>
        /// <returns>Server response</returns>
        public IEnumerator Send(BacktraceData data, Action <BacktraceResult> callback = null)
        {
            //check rate limiting
            bool watcherValidation = reportLimitWatcher.WatchReport(data.Report);

            if (!watcherValidation)
            {
                yield return(BacktraceResult.OnLimitReached(data.Report));
            }
            if (data == null)
            {
                yield return(new BacktraceResult()
                {
                    Status = Types.BacktraceResultStatus.LimitReached
                });
            }
            string json = data.ToJson();

            if (string.IsNullOrEmpty(json))
            {
                yield return(BacktraceResult.OnLimitReached(data.Report));
            }

            yield return(Send(json, data.Attachments, data.Report, callback));
        }
コード例 #5
0
        /// <summary>
        /// Sending a diagnostic report data to server API.
        /// </summary>
        /// <param name="data">Diagnostic data</param>
        /// <returns>False if operation fail or true if API return OK</returns>
        public async Task <BacktraceServerResponse> Send(BacktraceData <T> data)
        {
            var json        = JsonConvert.SerializeObject(data, SerializerSettings);
            var attachments = data.Attachments;

            var requestId = Guid.NewGuid().ToString("N");
            var request   = new HttpRequestMessage(HttpMethod.Post, _serverurl);
            var content   = new MultipartFormDataContent(requestId);

            const string jsonName = "upload_file";

            content.Add(new StringContent(json), jsonName, jsonName);

            foreach (var attachmentPath in attachments)
            {
                if (!File.Exists(attachmentPath))
                {
                    continue;
                }

                var name = "attachment_" + Path.GetFileName(attachmentPath);
                content.Add(new StreamContent(File.OpenRead(attachmentPath)), name, name);
            }

            request.Content = content;

            var response = await _http.SendAsync(request);

            var fullResponse = await response.Content.ReadAsStringAsync();

            var serverResponse = JsonConvert.DeserializeObject <BacktraceServerResponse>(fullResponse, SerializerSettings);

            return(serverResponse);
        }
コード例 #6
0
        private string GetMinidumpPath(BacktraceData backtraceData, string dataPrefix)
        {
            if (_settings.MinidumpType == MiniDumpType.None)
            {
                return(string.Empty);
            }
            //note that every minidump file generated by app ends with .dmp extension
            //its important information if you want to clear minidump file
            string minidumpDestinationPath = Path.Combine(_settings.DatabasePath, string.Format("{0}-dump.dmp", dataPrefix));
            var    backtraceReport         = backtraceData.Report;

            if (backtraceReport == null)
            {
                return(string.Empty);
            }
            MinidumpException minidumpExceptionType = backtraceReport.ExceptionTypeReport
                ? MinidumpException.Present
                : MinidumpException.None;

            bool minidumpSaved = MinidumpHelper.Write(
                filePath: minidumpDestinationPath,
                options: _settings.MinidumpType,
                exceptionType: minidumpExceptionType);

            return(minidumpSaved
                ? minidumpDestinationPath
                : string.Empty);
        }
コード例 #7
0
        public bool SaveReport(BacktraceData <T> backtraceReport)
        {
            if (!_enable)
            {
                return(true);
            }

            string json = JsonConvert.SerializeObject(backtraceReport);

            byte[] file     = Encoding.UTF8.GetBytes(json);
            string filename = $"Backtrace_{backtraceReport.Timestamp}";
            string filePath = Path.Combine(_directoryPath, filename);

            try
            {
                using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                {
                    fs.Write(file, 0, file.Length);
                }
            }
            catch (Exception)
            {
                return(false);
            }
            return(true);
        }
コード例 #8
0
        public IEnumerator TesClientAttributes_ReportShouldntExtendClientAttributes_ClientAttributesWontStoreReportAttributes()
        {
            var key   = "foo";
            var value = "bar";

            BacktraceClient[key] = value;
            var           numberOfKeysBeforeSendRequest = BacktraceClient.GetAttributesCount();
            BacktraceData data = null;

            BacktraceClient.BeforeSend = (BacktraceData reportData) =>
            {
                data = reportData;
                return(null);
            };
            var exceptionsMessage = new string[] { "foo", "bar" };

            foreach (var exceptionMessage in exceptionsMessage)
            {
                BacktraceClient.Send(new Exception(exceptionMessage));
                yield return(new WaitForEndOfFrame());
            }

            Assert.AreEqual(data.Attributes.Attributes[key], value);
            Assert.AreEqual(numberOfKeysBeforeSendRequest, BacktraceClient.GetAttributesCount());
            yield return(null);
        }
コード例 #9
0
        public IEnumerator TestSourceCodeAssignment_DisabledLogManagerWithMultipleLogMessageAndMessageReport_SourceCodeAvailable()
        {
            BacktraceData lastData = null;

            BacktraceClient.BeforeSend = (BacktraceData data) =>
            {
                lastData = data;
                return(data);
            };
            //fake messages
            var fakeLogMessage = "log";

            BacktraceClient.HandleUnityMessage(fakeLogMessage, string.Empty, UnityEngine.LogType.Log);
            var fakeWarningMessage = "warning message";

            BacktraceClient.HandleUnityMessage(fakeWarningMessage, string.Empty, UnityEngine.LogType.Warning);

            // real exception
            var expectedExceptionMessage = "Exception message";

            BacktraceClient.Send(expectedExceptionMessage);
            yield return(new WaitForEndOfFrame());

            Assert.IsNotNull(lastData.SourceCode);

            var generatedText = lastData.SourceCode.Text;

            Assert.IsTrue(generatedText.Contains(expectedExceptionMessage));
            Assert.IsFalse(generatedText.Contains(fakeLogMessage));
            Assert.IsFalse(generatedText.Contains(fakeWarningMessage));
        }
コード例 #10
0
 /// <summary>
 /// Create new instance of database record
 /// </summary>
 /// <param name="data">Diagnostic data</param>
 /// <param name="path">database path</param>
 public BacktraceDatabaseRecord(BacktraceData data, string path)
 {
     Id          = data.Uuid;
     Record      = data;
     _path       = path;
     Attachments = data.Attachments;
 }
コード例 #11
0
 protected override BacktraceDatabaseRecord ConvertToRecord(BacktraceData backtraceData, string hash)
 {
     //create new record and return it to AVOID storing data on hard drive
     return(new BacktraceDatabaseRecord(backtraceData, _settings.DatabasePath)
     {
         Hash = hash
     });
 }
コード例 #12
0
        public IEnumerator TestDataSerialization_ValidStringReport_ShouldGenerateValidJsonReport()
        {
            var report = new BacktraceReport("string");
            var data   = new BacktraceData(report, new Dictionary <string, string>(), 0);

            Assert.DoesNotThrow(() => data.ToJson());
            yield return(null);
        }
コード例 #13
0
 public IEnumerable <string> GetReportAttachments(BacktraceData data)
 {
     return(new List <string>()
     {
         GetScreenshotPath(data),
         GetUnityPlayerLogFile(data),
         GetMinidumpPath(data)
     });
 }
コード例 #14
0
        public IEnumerator TestDataSerialization_ValidReport_DataSerializeAndDeserialize()
        {
            var report           = new BacktraceReport(new Exception("test"));
            var data             = new BacktraceData(report, null);
            var json             = data.ToJson();
            var deserializedData = BacktraceData.Deserialize(json);

            Assert.IsTrue(deserializedData.Timestamp == data.Timestamp);
            yield return(null);
        }
コード例 #15
0
        public IEnumerator TestAttributes_ValidReport_AttributesExists()
        {
            var report           = new BacktraceReport(new Exception("test"));
            var data             = new BacktraceData(report, null);
            var json             = data.Attributes.ToJson();
            var deserializedData = BacktraceAttributes.Deserialize(json);

            Assert.IsTrue(deserializedData.Attributes.Count == data.Attributes.Attributes.Count);
            yield return(null);
        }
コード例 #16
0
        public IEnumerator TestAnnotations_ValidReport_AnnotationExists()
        {
            var report           = new BacktraceReport(new Exception("test"));
            var data             = new BacktraceData(report, null);
            var json             = data.Annotation.ToJson();
            var deserializedData = Annotations.Deserialize(json);

            Assert.IsTrue(deserializedData.EnvironmentVariables.Count == data.Annotation.EnvironmentVariables.Count);
            yield return(null);
        }
コード例 #17
0
        public IEnumerable <string> GetReportAttachments(BacktraceData data)
        {
            var attachmentPrefix = data.UuidString;

            var result = new List <string>();

            AddIfPathIsNotEmpty(result, GetScreenshotPath(attachmentPrefix));
            AddIfPathIsNotEmpty(result, GetUnityPlayerLogFile(data, attachmentPrefix));
            AddIfPathIsNotEmpty(result, GetMinidumpPath(data, attachmentPrefix));
            return(result);
        }
コード例 #18
0
        /// <summary>
        /// Convert Backtrace data to Backtrace record and save it.
        /// </summary>
        /// <param name="backtraceData">Backtrace data</param>
        /// <param name="hash">deduplicaiton hash</param>
        /// <returns></returns>
        protected virtual BacktraceDatabaseRecord ConvertToRecord(BacktraceData backtraceData, string hash)
        {
            //create new record and save it on hard drive
            var record = new BacktraceDatabaseRecord(backtraceData, _path)
            {
                Hash = hash
            };

            record.Save();
            return(record);
        }
コード例 #19
0
        public void MissingStackTraceReport_GenerateNotFaultingStackTrace_ReportShouldntHaveFaultingThread()
        {
            var message = "message";
            // in this case BacktraceUnhandledException should generate environment stack trace
            var unhandledException = new BacktraceUnhandledException(message, string.Empty);

            Assert.IsNotEmpty(unhandledException.StackFrames);
            var report = new BacktraceReport(unhandledException);
            var data   = new BacktraceData(report, null);

            Assert.IsFalse(data.ThreadData.ThreadInformations.First().Value.Fault);
        }
コード例 #20
0
 public IEnumerator Send(BacktraceData data, Action <BacktraceResult> callback = null)
 {
     LastData = data;
     if (callback != null)
     {
         callback.Invoke(new BacktraceResult()
         {
             Status = Types.BacktraceResultStatus.Ok
         });
     }
     yield return(null);
 }
コード例 #21
0
    private BacktraceData AddAttributes(BacktraceData data)
    {
#if UNITY_EDITOR
        bool isEditor = true;
#else
        bool isEditor = false;
#endif
        data.Attributes.Add("IsEditor", isEditor);
        data.Attributes.Add("BuildJob", "buildjob 123");
        data.Attributes.Add("ChangeSetId", 12345);
        data.Attributes.Add("OnlineBackend", "Backend type X");
        return(data);
    }
コード例 #22
0
        /// <summary>
        /// Add new record to database
        /// </summary>
        /// <param name="backtraceData">Diagnostic data that should be stored in database</param>
        /// <returns>New instance of DatabaseRecordy</returns>
        public BacktraceDatabaseRecord Add(BacktraceData backtraceData)
        {
            if (backtraceData == null)
            {
                throw new NullReferenceException(nameof(backtraceData));
            }
            //create new record and save it on hard drive
            var record = new BacktraceDatabaseRecord(backtraceData, _path);

            record.Save();
            //add record to database context
            return(Add(record));
        }
コード例 #23
0
        /// <summary>
        /// Send a report to Backtrace API after first type of report validation rules
        /// </summary>
        /// <param name="report">Backtrace report</param>
        /// <param name="sendCallback">send callback</param>
        private void SendReport(BacktraceReport report, Action <BacktraceResult> sendCallback = null)
        {
            var record = Database != null?Database.Add(report, Attributes, MiniDumpType) : null;

            //create a JSON payload instance
            BacktraceData data = null;

            data = (record != null ? record.BacktraceData : null) ?? report.ToBacktraceData(Attributes);
            //valid user custom events
            data = (BeforeSend != null ? BeforeSend.Invoke(data) : null) ?? data;

            if (BacktraceApi == null)
            {
                if (record != null)
                {
                    record.Dispose();
                }

                Debug.LogWarning("Backtrace API doesn't exist. Please validate client token or server url!");
                return;
            }
            StartCoroutine(BacktraceApi.Send(data, (BacktraceResult result) =>
            {
                if (record != null)
                {
                    record.Dispose();
                    //Database?.IncrementRecordRetryLimit(record);
                }
                if (result != null)
                {
                    if (result.Status == BacktraceResultStatus.Ok)
                    {
                        if (Database != null)
                        {
                            Database.Delete(record);
                        }
                    }
                }
                //check if there is more errors to send
                //handle inner exception
                HandleInnerException(report, (BacktraceResult innerResult) =>
                {
                    result.InnerExceptionResult = innerResult;
                });

                if (sendCallback != null)
                {
                    sendCallback.Invoke(result);
                }
            }));
        }
コード例 #24
0
        /// <summary>
        /// Sending a diagnostic report data to server API.
        /// </summary>
        /// <param name="data">Diagnostic data</param>
        /// <returns>Server response</returns>
        public IEnumerator Send(BacktraceData data, Action <BacktraceResult> callback = null)
        {
#pragma warning disable CS0618 // Type or member is obsolete
            if (RequestHandler != null)
            {
                yield return(RequestHandler.Invoke(ServerUrl, data));
            }
            else if (data != null)
            {
                var json = data.ToJson();
                yield return(Send(json, data.Attachments, data.Deduplication, callback));
            }
#pragma warning restore CS0618 // Type or member is obsolete
        }
        public void TestShaComparision_Fingerprintavailable_DeduplicationReturnsFingerprint()
        {
            string fingerprint = "12345";
            var    exception   = new Exception("test message");
            var    report      = new BacktraceReport(exception)
            {
                Fingerprint = fingerprint
            };
            var data = new BacktraceData(report, null);
            var deduplicationModel = new DeduplicationModel(data, DeduplicationStrategy.Default);
            var sha = deduplicationModel.GetSha();

            Assert.AreEqual(sha, fingerprint);
        }
コード例 #26
0
        public void TestShaComparision_OnlyEmptyStackTrace_ReportWithFactorGenerateDifferentSha()
        {
            var report           = new BacktraceReport(new Exception("test message"));
            var reportWithFactor = new BacktraceReport(new Exception("test message"))
            {
                Factor = "12345"
            };

            var data               = new BacktraceData(report, null);
            var dataWithFactor     = new BacktraceData(reportWithFactor, null);
            var deduplicationModel = new DeduplicationModel(data, DeduplicationStrategy.Default);
            var comparer           = new DeduplicationModel(dataWithFactor, DeduplicationStrategy.Default);

            Assert.AreNotEqual(deduplicationModel.GetSha(), comparer.GetSha());
        }
        public void TestShaComparisionWithMultipleOptionsAndReports_MultipleOptions_DeduplicationReturnsFingerprint(DeduplicationStrategy strategy)
        {
            var fingerprint = "12345";
            var exception   = new Exception("testMessage");
            var report      = new BacktraceReport(exception)
            {
                Fingerprint = fingerprint
            };

            var data = new BacktraceData(report, null);
            var deduplicationModel = new DeduplicationModel(data, strategy);
            var sha = deduplicationModel.GetSha();

            Assert.AreEqual(sha, fingerprint);
        }
コード例 #28
0
        public IEnumerator TestSourceCodeAssignment_DisabledUnhandledException_ShouldStoreUnhandledExceptionInfo()
        {
            BacktraceClient.Configuration.HandleUnhandledExceptions = false;

            BacktraceData lastData = null;

            BacktraceClient.BeforeSend = (BacktraceData data) =>
            {
                lastData = data;
                return(data);
            };

            //fake messages
            var fakeLogMessage = "log";

            BacktraceClient.HandleUnityMessage(fakeLogMessage, string.Empty, LogType.Log);
            yield return(new WaitForEndOfFrame());

            var fakeWarningMessage = "warning message";

            BacktraceClient.HandleUnityMessage(fakeWarningMessage, string.Empty, LogType.Warning);
            yield return(new WaitForEndOfFrame());

            // real exception
            var expectedExceptionMessage = "Exception message";

            BacktraceClient.HandleUnityMessage(expectedExceptionMessage, string.Empty, LogType.Exception);
            yield return(new WaitForEndOfFrame());

            Assert.IsNull(api.LastData);

            var expectedReportMessage = "Report message";
            var report = new BacktraceReport(new Exception(expectedReportMessage));

            BacktraceClient.Send(report);
            yield return(new WaitForEndOfFrame());

            Assert.IsNotNull(lastData.SourceCode);

            var generatedText = lastData.SourceCode.Text;

            Assert.IsTrue(generatedText.Contains(expectedExceptionMessage));
            Assert.IsTrue(generatedText.Contains(fakeLogMessage));
            Assert.IsTrue(generatedText.Contains(fakeWarningMessage));
            Assert.IsTrue(generatedText.Contains(expectedReportMessage));
        }
コード例 #29
0
        /// <summary>
        /// Generate hash for current diagnostic data
        /// </summary>
        /// <param name="backtraceData">Diagnostic data </param>
        /// <returns>hash for current backtrace data</returns>
        private string GetHash(BacktraceData backtraceData)
        {
            var fingerprint = backtraceData == null ? string.Empty : backtraceData.Report.Fingerprint ?? string.Empty;

            if (!string.IsNullOrEmpty(fingerprint))
            {
                return(fingerprint);
            }
            if (DeduplicationStrategy == DeduplicationStrategy.None)
            {
                return(string.Empty);
            }

            var deduplicationModel = new DeduplicationModel(backtraceData, DeduplicationStrategy);

            return(deduplicationModel.GetSha());
        }
コード例 #30
0
        /// <summary>
        /// Get new database record
        /// </summary>
        /// <returns>Database record mock</returns>
        protected BacktraceDatabaseRecord GetRecord()
        {
            //mock single record
            var mockRecord = new Mock <BacktraceDatabaseRecord>();

            mockRecord.Setup(n => n.Delete());
            mockRecord.Setup(n => n.BacktraceData)
            .Returns(new BacktraceData(It.IsAny <BacktraceReport>(), It.IsAny <Dictionary <string, object> >()));
            mockRecord.Setup(n => n.Valid())
            .Returns(true);

            var data = new BacktraceData(null, new Dictionary <string, object>());

            mockRecord.SetupProperty(n => n.Record, data);

            mockRecord.Object.RecordWriter = new MockBacktraceDatabaseWriter();
            return(mockRecord.Object);
        }