예제 #1
0
 /// <summary>
 /// Accesses the instance.
 /// </summary>
 public static FRepository Get(CrashRepository Crashes, BuggRepository Buggs)
 {
     return(new FRepository()
     {
         _Crashes = Crashes, _Buggs = Buggs
     });
 }
예제 #2
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public EntitySet <Crash> GetCrashes()
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                int CrashCount = Crashes.Count;
                if (NumberOfCrashes != CrashCount)
                {
                    NumberOfCrashes = CrashCount;

                    if (NumberOfCrashes > 0)
                    {
                        BuggRepository LocalBuggRepository = new BuggRepository();
                        LocalBuggRepository.UpdateBuggData(this, Crashes);
                    }
                }

                // Just fill the CallStackContainers
                foreach (Crash CurrentCrash in Crashes)
                {
                    if (CurrentCrash.CallStackContainer == null)
                    {
                        CurrentCrash.CallStackContainer = CurrentCrash.GetCallStack();
                    }

                    if (SourceContext == null)
                    {
                        SourceContext = CurrentCrash.SourceContext;
                    }
                }

                return(Crashes);
            }
        }
예제 #3
0
        /// <summary>
        /// Return the top lines of a callstack.
        /// </summary>
        /// <param name="Max">The number of lines to return.</param>
        /// <returns>A list of callstack entries.</returns>
        public List <string> GetFunctionCalls(int Max)
        {
            BuggRepository LocalBuggRepository = new BuggRepository();
            List <string>  Results             = LocalBuggRepository.GetFunctionCalls(Pattern);

            return(Results);
        }
예제 #4
0
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public EntitySet<Crash> GetCrashes()
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
            {
                int CrashCount = Crashes.Count;
                if( NumberOfCrashes != CrashCount )
                {
                    NumberOfCrashes = CrashCount;

                    if( NumberOfCrashes > 0 )
                    {
                        BuggRepository LocalBuggRepository = new BuggRepository();
                        LocalBuggRepository.UpdateBuggData( this, Crashes );
                    }
                }

                // Just fill the CallStackContainers
                foreach( Crash CurrentCrash in Crashes )
                {
                    if( CurrentCrash.CallStackContainer == null )
                    {
                        CurrentCrash.CallStackContainer = CurrentCrash.GetCallStack();
                    }

                    if( SourceContext == null )
                    {
                        SourceContext = CurrentCrash.SourceContext;
                    }
                }

                return Crashes;
            }
        }
예제 #5
0
        /// <summary>
        /// Adds the bugg as a new JIRA ticket
        /// </summary>
        public void CopyToJira()
        {
            var jc = JiraConnection.Get();
            Dictionary <string, object> issueFields;

            if (BranchesFoundIn.Any(data => data.ToLower().Contains("//fort")))
            {
                issueFields = CreateFortniteIssue(jc);
            }
            //else if (BranchesFoundIn.Any(data => data.ToLower().Contains("//orion")))
            //{
            //    issueFields = CreateOrionIssue();
            //}
            else
            {
                issueFields = CreateGeneralIssue(jc);
            }

            if (jc.CanBeUsed() && string.IsNullOrEmpty(this.Jira))
            {
                // Additional Info URL / Link to Crash/Bugg
                string Key = jc.AddJiraTicket(issueFields);
                if (!string.IsNullOrEmpty(Key))
                {
                    Jira = Key;
                    var buggs = new BuggRepository();
                    buggs.SetJIRAForBuggAndCrashes(Key, Id);
                }
            }
        }
예제 #6
0
 /// <summary>
 /// Accesses the instance.
 /// </summary>
 public static FRepository Get(BuggRepository Buggs)
 {
     return(new FRepository()
     {
         _Buggs = Buggs
     });
 }
예제 #7
0
 /// <summary>
 /// Return the top lines of a callstack.
 /// </summary>
 /// <returns>A list of callstack entries.</returns>
 public List <string> GetFunctionCalls()
 {
     using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Id=" + this.Id + ")"))
     {
         BuggRepository LocalBuggRepository = new BuggRepository();
         List <string>  Results             = LocalBuggRepository.GetFunctionCalls(Pattern);
         return(Results);
     }
 }
예제 #8
0
        /// <summary>
        /// Adds the bugg as a new JIRA ticket
        /// </summary>
        public void CopyToJira()
        {
            var JC = JiraConnection.Get();

            if (JC.CanBeUsed() && string.IsNullOrEmpty(this.TTPID))
            {
                Dictionary <string, object> Fields = new Dictionary <string, object>();
                Fields.Add("project", new Dictionary <string, object> {
                    { "id", 11205 }
                });                                                                                             // UE
                Fields.Add("summary", "[CrashReport] " + ToJiraSummary);                                        // Call Stack, Line 1
                Fields.Add("description", "____________");                                                      // Description
                Fields.Add("issuetype", new Dictionary <string, object> {
                    { "id", "1" }
                });                                                                                             // Bug
                Fields.Add("labels", new string[] { "crash" });                                                 // <label>crash</label>
                Fields.Add("customfield_11500", ToJiraFirstCLAffected);                                         // Changelist # / Found Changelist
                Fields.Add("environment", LatestOSAffected);                                                    // Platform

                // Components
                var SupportComponent = JC.GetNameToComponents()["Support"];
                Fields.Add("components", new object[] { SupportComponent });

                // ToJiraVersions
                Fields.Add("versions", ToJiraVersions);

                // ToJiraBranches
                Fields.Add("customfield_11201", ToJiraBranches);

                // ToJiraPlatforms
                Fields.Add("customfield_11203", ToJiraPlatforms);

                // Callstack customfield_11807
                var    Callstack     = GetFunctionCalls();
                string JiraCallstack = string.Join("\r\n", Callstack);
                Fields.Add("customfield_11807", JiraCallstack);                                                                                 // Callstack

                string Key = JC.AddJiraTicket(Fields);
                if (!string.IsNullOrEmpty(Key))
                {
                    TTPID = Key;
                    BuggRepository.SetJIRAForBuggAndCrashes(Key, Id);

                    // Update the JIRA in the bugg.
                    Dictionary <string, object> FieldsToUpdate = new Dictionary <string, object>();
                    string BuggLink = "http://crashreporter/Buggs/Show/" + Id;
                    FieldsToUpdate.Add("customfield_11205", BuggLink);                                                                                          // Additional Info URL / Link to Crash/Bugg
                    JC.UpdateJiraTicket(Key, FieldsToUpdate);
                }
            }
        }
        /// <summary>
        /// Adds the bugg as a new JIRA ticket
        /// </summary>
        public void CopyToJira()
        {
            var JC = JiraConnection.Get();

            if (JC.CanBeUsed() && string.IsNullOrEmpty(this.Jira))
            {
                Dictionary <string, object> Fields = new Dictionary <string, object>();
                Fields.Add("project", new Dictionary <string, object> {
                    { "id", 11205 }
                });                                                                                             // UE
                Fields.Add("summary", "[CrashReport] " + ToJiraSummary);                                        // Call Stack, Line 1
                Fields.Add("description", string.Join("\r\n", ToJiraDescriptions));                             // Description
                Fields.Add("issuetype", new Dictionary <string, object> {
                    { "id", "1" }
                });                                                                                             // Bug
                Fields.Add("labels", new string[] { "crash", "liveissue" });                                    // <label>crash, live issue</label>
                Fields.Add("customfield_11500", ToJiraFirstCLAffected);                                         // Changelist # / Found Changelist
                Fields.Add("environment", LatestOSAffected);                                                    // Platform

                // Components
                var SupportComponent = JC.GetNameToComponents()["Support"];
                Fields.Add("components", new object[] { SupportComponent });

                // ToJiraVersions
                Fields.Add("versions", ToJiraVersions);

                // ToJiraBranches
                Fields.Add("customfield_12402", ToJiraBranches.ToList());                                                               // NewBranchFoundIn

                // ToJiraPlatforms
                Fields.Add("customfield_11203", ToJiraPlatforms);

                // Callstack customfield_11807
                string JiraCallstack = "{noformat}" + string.Join("\r\n", ToJiraFunctionCalls) + "{noformat}";
                Fields.Add("customfield_11807", JiraCallstack);                                                                                 // Callstack

                string BuggLink = "http://crashreporter/Buggs/Show/" + Id;
                Fields.Add("customfield_11205", BuggLink);                                                                                      // Additional Info URL / Link to Crash/Bugg

                string Key = JC.AddJiraTicket(Fields);
                if (!string.IsNullOrEmpty(Key))
                {
                    Jira = Key;
                    BuggRepository Buggs = new BuggRepository();
                    Buggs.SetJIRAForBuggAndCrashes(Key, Id);
                }
            }
        }
예제 #10
0
        /*
        /// <summary>
        /// The empty view of the buggs page.
        /// </summary>
        ///
        public ActionResult Index()
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ))
            {
                BuggsViewModel Results = new BuggsViewModel();
                Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
                return View( "Index", Results );
            }
        }*/
        /// <summary>
        /// The Index action.
        /// </summary>
        /// <param name="BuggsForm">The form of user data passed up from the client.</param>
        /// <returns>The view to display a list of Buggs on the client.</returns>
        public ActionResult Index( FormCollection BuggsForm )
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ))
            {
                BuggRepository Buggs = new BuggRepository();

                FormHelper FormData = new FormHelper( Request, BuggsForm, "CrashesInTimeFrameGroup" );
                BuggsViewModel Results = Buggs.GetResults( FormData );
                foreach (var Bugg in Results.Results)
                {
                    // Populate function calls.
                    Bugg.GetFunctionCalls();
                }
                Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
                return View( "Index", Results );
            }
        }
        /// <summary>
        /// Return a view model containing a sorted list of crashes based on the user input.
        /// </summary>
        /// <param name="FormData">The user input from the client.</param>
        /// <returns>A view model to use to display a list of crashes.</returns>
        /// <remarks>The filtering mechanism works by generating a fluent query to describe the set of crashes we wish to view. Basically, 'Select.Where().Where().Where().Where()' etc.
        /// The filtering is applied in the following order:
        /// 1. Get all crashes.
        /// 2. Filter between the start and end dates.
        /// 3. Apply the search query.
        /// 4. Filter by the branch.
        /// 5. Filter by the game name.
        /// 6. Filter by the type of reports to view.
        /// 7. Filter by the user group.
        /// 8. Sort the results by the sort term.
        /// 9. Take one page of results.</remarks>
        public CrashesViewModel GetResults(FormHelper FormData)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                UsersMapping UniqueUser = null;

                IEnumerable <Crash> Results = null;
                int Skip = (FormData.Page - 1) * FormData.PageSize;
                int Take = FormData.PageSize;

                var ResultsAll = ConstructQueryForFiltering(FormData);

                // Filter by data and get as enumerable.
                Results = FilterByDate(ResultsAll, FormData.DateFrom, FormData.DateTo);

                // Filter by BuggId
                if (!string.IsNullOrEmpty(FormData.BuggId))
                {
                    int  BuggId = 0;
                    bool bValid = int.TryParse(FormData.BuggId, out BuggId);

                    if (bValid)
                    {
                        BuggRepository Buggs   = new BuggRepository();
                        Bugg           NewBugg = Buggs.GetBugg(BuggId);

                        if (NewBugg != null)
                        {
                            List <Crash> Crashes   = NewBugg.GetCrashes();
                            var          NewResult = Results.Intersect(Crashes, new CrashComparer());
                            Results = NewResult;
                        }
                    }
                }

                // Get UserGroup ResultCounts
                Dictionary <string, int> GroupCounts = GetCountsByGroupFromCrashes(Results);

                // Filter by user group if present
                int UserGroupId;
                if (!string.IsNullOrEmpty(FormData.UserGroup))
                {
                    UserGroupId = FRepository.Get(this).FindOrAddGroup(FormData.UserGroup);
                }
                else
                {
                    UserGroupId = 1;
                }

                HashSet <int> UserIdsForGroup = FRepository.Get(this).GetUserIdsFromUserGroupId(UserGroupId);

                using (FScopedLogTimer LogTimer3 = new FScopedLogTimer("CrashRepository.Results.Users"))
                {
                    List <Crash> NewResults = new List <Crash>();
                    foreach (Crash Crash in Results)
                    {
                        if (UserIdsForGroup.Contains(Crash.UserNameId.Value))
                        {
                            NewResults.Add(Crash);
                        }
                    }

                    Results = NewResults;
                }

                // Pass in the results and return them sorted properly
                Results = GetSortedResults(Results, FormData.SortTerm, (FormData.SortOrder == "Descending"));

                // Get the Count for pagination
                int ResultCount = 0;
                using (FScopedLogTimer LogTimer3 = new FScopedLogTimer("CrashRepository.Results.Users"))
                {
                    ResultCount = Results.Count();
                }


                // Grab just the results we want to display on this page
                Results = Results.Skip(Skip).Take(Take);

                using (FScopedLogTimer LogTimer3 = new FScopedLogTimer("CrashRepository.GetResults.GetCallstacks"))
                {
                    // Process call stack for display
                    foreach (Crash CrashInstance in Results)
                    {
                        // Put callstacks into an list so we can access them line by line in the view
                        CrashInstance.CallStackContainer = GetCallStack(CrashInstance);
                    }
                }

                return(new CrashesViewModel
                {
                    Results = Results,
                    PagingInfo = new PagingInfo {
                        CurrentPage = FormData.Page, PageSize = FormData.PageSize, TotalResults = ResultCount
                    },
                    SortOrder = FormData.SortOrder,
                    SortTerm = FormData.SortTerm,
                    UserGroup = FormData.UserGroup,
                    CrashType = FormData.CrashType,
                    SearchQuery = FormData.SearchQuery,
                    UsernameQuery = FormData.UsernameQuery,
                    EpicIdOrMachineQuery = FormData.EpicIdOrMachineQuery,
                    MessageQuery = FormData.MessageQuery,
                    BuiltFromCL = FormData.BuiltFromCL,
                    BuggId = FormData.BuggId,
                    JiraQuery = FormData.JiraQuery,
                    DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                    BranchName = FormData.BranchName,
                    VersionName = FormData.VersionName,
                    PlatformName = FormData.PlatformName,
                    GameName = FormData.GameName,
                    GroupCounts = GroupCounts,
                    RealUserName = UniqueUser != null?UniqueUser.ToString() : null,
                });
            }
        }
예제 #12
0
 /// <summary>
 /// Link the Http context cache to a Bugg repository.
 /// </summary>
 /// <param name="InCache">The current Http context cache.</param>
 /// <param name="InBuggRepository">The repository to associate the cache with.</param>
 public CachedDataService(Cache InCache, BuggRepository InBuggRepository)
 {
     CacheInstance          = InCache;
     BuggRepositoryInstance = InBuggRepository;
 }
예제 #13
0
		/// <summary>
		/// Return the top lines of a callstack.
		/// </summary>
		/// <returns>A list of callstack entries.</returns>
		public List<string> GetFunctionCalls()
		{
			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(Id=" + this.Id + ")" ) )
			{
				BuggRepository LocalBuggRepository = new BuggRepository();
				List<string> Results = LocalBuggRepository.GetFunctionCalls( Pattern );
				return Results;
			}
		}
예제 #14
0
파일: Repository.cs 프로젝트: mymei/UE4
 /// <summary>
 /// Accesses the instance.
 /// </summary>
 public static FRepository Get( BuggRepository Buggs )
 {
     return new FRepository() { _Buggs = Buggs };
 }
예제 #15
0
파일: Repository.cs 프로젝트: mymei/UE4
 /// <summary>
 /// Accesses the instance.
 /// </summary>
 public static FRepository Get( CrashRepository Crashes, BuggRepository Buggs )
 {
     return new FRepository() { _Crashes = Crashes, _Buggs = Buggs };
 }
예제 #16
0
 /// <summary>
 /// Link the Http context cache to a Bugg repository.
 /// </summary>
 /// <param name="InCache">The current Http context cache.</param>
 /// <param name="InBuggRepository">The repository to associate the cache with.</param>
 public CachedDataService( Cache InCache, BuggRepository InBuggRepository )
 {
     CacheInstance = InCache;
     Buggs = InBuggRepository;
 }
예제 #17
0
        //static readonly int MinNumberOfCrashes = 2;
        /// <summary>
        /// Retrieve all Buggs matching the search criteria.
        /// </summary>
        /// <param name="FormData">The incoming form of search criteria from the client.</param>
        /// <returns>A view to display the filtered Buggs.</returns>
        public CSV_ViewModel GetResults( FormHelper FormData )
        {
            BuggRepository BuggsRepo = new BuggRepository();
            CrashRepository CrashRepo = new CrashRepository();

            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
            {
                string AnonymousGroup = "Anonymous";
                //List<String> Users = FRepository.Get().GetUserNamesFromGroupName( AnonumousGroup );
                int AnonymousGroupID = FRepository.Get( BuggsRepo ).FindOrAddGroup( AnonymousGroup );
                HashSet<int> AnonumousIDs = FRepository.Get( BuggsRepo ).GetUserIdsFromUserGroup( AnonymousGroup );
                int AnonymousID = AnonumousIDs.First();
                HashSet<string> UserNamesForUserGroup = FRepository.Get( BuggsRepo ).GetUserNamesFromGroupName( AnonymousGroup );

                // Enable to narrow results and improve debugging performance.
                //FormData.DateFrom = FormData.DateTo.AddDays( -1 );
                FormData.DateTo = FormData.DateTo.AddDays( 1 );

                var FilteringQueryJoin = CrashRepo
                    .ListAll()
                    .Where( c => c.EpicAccountId != "" )
                    // Only crashes and asserts
                    .Where( c => c.CrashType == 1 || c.CrashType == 2 )
                    // Only anonymous user
                    .Where( c => c.UserNameId == AnonymousID )
                    // Filter be date
                    .Where( c => c.TimeOfCrash > FormData.DateFrom && c.TimeOfCrash < FormData.DateTo )
                    .Join
                    (
                        CrashRepo.Context.Buggs_Crashes,
                        c => c,
                        bc => bc.Crash,
                        ( c, bc ) => new
                        {
                            GameName = c.GameName,
                            TimeOfCrash = c.TimeOfCrash.Value,
                            BuiltFromCL = c.BuiltFromCL,
                            PlatformName = c.PlatformName,
                            EngineMode = c.EngineMode,
                            MachineId = c.MachineId,
                            Module = c.Module,
                            BuildVersion = c.BuildVersion,
                            Jira = c.Jira,
                            Branch = c.Branch,
                            CrashType = c.CrashType.Value,
                            EpicId = c.EpicAccountId,
                            BuggId = bc.BuggId,
                        }
                    );

                var FilteringQueryCrashes = CrashRepo
                    .ListAll()
                    .Where( c => c.EpicAccountId != "" )
                    // Only crashes and asserts
                    .Where( c => c.CrashType == 1 || c.CrashType == 2 )
                    // Only anonymous user
                    .Where( c => c.UserNameId == AnonymousID );

                int TotalCrashes = CrashRepo
                    .ListAll()
                    .Count();

                int TotalCrashesYearToDate = CrashRepo
                    .ListAll()
                    // Year to date
                    .Where( c => c.TimeOfCrash > new DateTime( DateTime.UtcNow.Year, 1, 1 ) )
                    .Count();

                var CrashesFilteredWithDateQuery = FilteringQueryCrashes
                    // Filter be date
                    .Where( c => c.TimeOfCrash > FormData.DateFrom && c.TimeOfCrash < FormData.DateTo );

                int CrashesFilteredWithDate = CrashesFilteredWithDateQuery
                    .Count();

                int CrashesYearToDateFiltered = FilteringQueryCrashes
                    // Year to date
                    .Where( c => c.TimeOfCrash > new DateTime( DateTime.UtcNow.Year, 1, 1 ) )
                    .Count();

                int AffectedUsersFiltered = FilteringQueryCrashes
                    .Select( c => c.EpicAccountId )
                    .Distinct()
                    .Count();

                int UniqueCrashesFiltered = FilteringQueryCrashes
                    .Select( c => c.Pattern )
                    .Distinct()
                    .Count();

                int NumCrashes = FilteringQueryJoin.Count();

                // Get all users
                // SLOW
                //var Users = FRepository.Get( BuggsRepo ).GetAnalyticsUsers().ToDictionary( X => X.EpicAccountId, Y => Y );

                // Export data to the file.
                string CSVPathname = Path.Combine( Settings.Default.CrashReporterCSV, DateTime.UtcNow.ToString( "yyyy-MM-dd.HH-mm-ss" ) );
                CSVPathname += string
                    .Format( "__[{0}---{1}]__{2}",
                    FormData.DateFrom.ToString( "yyyy-MM-dd" ),
                    FormData.DateTo.ToString( "yyyy-MM-dd" ),
                    NumCrashes )
                    + ".csv";

                string ServerPath = Server.MapPath( CSVPathname );
                var CSVFile = new StreamWriter( ServerPath, true, Encoding.UTF8 );

                using (FAutoScopedLogTimer ExportToCSVTimer = new FAutoScopedLogTimer( "ExportToCSV" ))
                {
                    var RowType = FilteringQueryJoin.FirstOrDefault().GetType();

                    string AllProperties = "";
                    foreach( var Property in RowType.GetProperties() )
                    {
                        AllProperties += Property.Name;
                        AllProperties += "; ";
                    }

                    // Write header
                    CSVFile.WriteLine( AllProperties );

                    foreach (var Row in FilteringQueryJoin)
                    {
                        var BVParts = Row.BuildVersion.Split( new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries );
                        if (BVParts.Length > 2 && BVParts[0] != "0")
                        {
                            string CleanEngineVersion = string.Format( "{0}.{1}.{2}", BVParts[0], BVParts[1], BVParts[2] );

                            string[] RowProperties = new string[]
                            {
                                Row.GameName,
                                Row.TimeOfCrash.ToString(),
                                Row.BuiltFromCL,
                                Row.PlatformName,
                                Row.EngineMode,
                                Row.MachineId,
                                Row.Module,
                                CleanEngineVersion,
                                Row.Jira,
                                Row.Branch,
                                Row.CrashType == 1 ? "Crash" : "Assert",
                                Row.EpicId,
                                Row.BuggId.ToString()
                            };

                            string JoinedLine = string.Join( "; ", RowProperties );
                            JoinedLine += "; ";

                            CSVFile.WriteLine( JoinedLine );
                        }
                    }

                    CSVFile.Flush();
                    CSVFile.Close();
                    CSVFile = null;
                }

                List<FCSVRow> CSVRows = FilteringQueryJoin
                    .OrderByDescending( X => X.TimeOfCrash )
                    .Take( 32 )
                    .Select( c => new FCSVRow
                    {
                        GameName = c.GameName,
                        TimeOfCrash = c.TimeOfCrash,
                        BuiltFromCL = c.BuiltFromCL,
                        PlatformName = c.PlatformName,
                        EngineMode = c.EngineMode,
                        MachineId = c.MachineId,
                        Module = c.Module,
                        BuildVersion = c.BuildVersion,
                        Jira = c.Jira,
                        Branch = c.Branch,
                        CrashType = c.CrashType,
                        EpicId = c.EpicId,
                        BuggId = c.BuggId,
                    } )
                    .ToList();

                return new CSV_ViewModel
                {
                    CSVRows = CSVRows,
                    CSVPathname = CSVPathname,
                    DateFrom = (long)( FormData.DateFrom - CrashesViewModel.Epoch ).TotalMilliseconds,
                    DateTo = (long)( FormData.DateTo - CrashesViewModel.Epoch ).TotalMilliseconds,
                    DateTimeFrom = FormData.DateFrom,
                    DateTimeTo = FormData.DateTo,
                    AffectedUsersFiltered = AffectedUsersFiltered,
                    UniqueCrashesFiltered = UniqueCrashesFiltered,
                    CrashesFilteredWithDate = CrashesFilteredWithDate,
                    TotalCrashes = TotalCrashes,
                    TotalCrashesYearToDate = TotalCrashesYearToDate,
                };
            }
        }
예제 #18
0
		/// <summary>
		/// Retrieve all Buggs matching the search criteria.
		/// </summary>
		/// <param name="FormData">The incoming form of search criteria from the client.</param>
		/// <param name="BuggIDToBeAddedToJira">ID of the bugg that will be added to JIRA</param>
		/// <returns>A view to display the filtered Buggs.</returns>
		public ReportsViewModel GetResults( FormHelper FormData, int BuggIDToBeAddedToJira )
		{
			BuggRepository BuggsRepo = new BuggRepository();
			CrashRepository CrashRepo = new CrashRepository();

			// @TODO yrx 2015-02-17 BuggIDToBeAddedToJira replace with List<int> based on check box and Submit?
			// It would be great to have a CSV export of this as well with buggs ID being the key I can then use to join them :)
			// 
			// Enumerate JIRA projects if needed.
			// https://jira.ol.epicgames.net//rest/api/2/project
			var JC = JiraConnection.Get();
			var JiraComponents = JC.GetNameToComponents();
			var JiraVersions = JC.GetNameToVersions();

			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
			{
				string AnonumousGroup = "Anonymous";
				//List<String> Users = FRepository.Get().GetUserNamesFromGroupName( AnonumousGroup );
				int AnonymousGroupID = FRepository.Get( BuggsRepo ).FindOrAddGroup( AnonumousGroup );
				HashSet<int> AnonumousIDs = FRepository.Get( BuggsRepo ).GetUserIdsFromUserGroup( AnonumousGroup );
				int AnonymousID = AnonumousIDs.First();

				var Crashes = CrashRepo
					.FilterByDate( CrashRepo.ListAll(), FormData.DateFrom, FormData.DateTo )
					// Only crashes and asserts
					.Where( Crash => Crash.CrashType == 1 || Crash.CrashType == 2 )
					// Only anonymous user
					.Where( Crash => Crash.UserNameId.Value == AnonymousID )
					.Select( Crash => new
					{
						ID = Crash.Id,
						TimeOfCrash = Crash.TimeOfCrash.Value,
						//UserID = Crash.UserNameId.Value, 
						BuildVersion = Crash.BuildVersion,
						JIRA = Crash.Jira,
						Platform = Crash.PlatformName,
						FixCL = Crash.FixedChangeList,
						BuiltFromCL = Crash.BuiltFromCL,
						Pattern = Crash.Pattern,
						MachineID = Crash.MachineId,
						Branch = Crash.Branch,
						Description = Crash.Description,
						RawCallStack = Crash.RawCallStack,
					} )
					.ToList();
				int NumCrashes = Crashes.Count;

				/*
				// Build patterns for crashes where patters is null.
				var CrashesWithoutPattern = FRepository.Get().Crashes
					.FilterByDate( FRepository.Get().Crashes.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays( 1 ) )
					// Only crashes and asserts
					.Where( Crash => Crash.Pattern == null || Crash.Pattern == "" )
					.Select( Crash => Crash )
					.ToList();

				foreach( var Crash in CrashesWithoutPattern )
				{
					Crash.BuildPattern();
				}
				*/

				// Total # of ALL (Anonymous) crashes in timeframe
				int TotalAnonymousCrashes = NumCrashes;

				// Total # of UNIQUE (Anonymous) crashes in timeframe
				HashSet<string> UniquePatterns = new HashSet<string>();
				HashSet<string> UniqueMachines = new HashSet<string>();
				Dictionary<string, int> PatternToCount = new Dictionary<string, int>();

				//List<int> CrashesWithoutPattern = new List<int>();
				//List<DateTime> CrashesWithoutPatternDT = new List<DateTime>();

				foreach( var Crash in Crashes )
				{
					if( string.IsNullOrEmpty( Crash.Pattern ) )
					{
						//CrashesWithoutPattern.Add( Crash.ID );
						//CrashesWithoutPatternDT.Add( Crash.TimeOfCrash );
						continue;
					}

					UniquePatterns.Add( Crash.Pattern );
					UniqueMachines.Add( Crash.MachineID );

					bool bAdd = !PatternToCount.ContainsKey( Crash.Pattern );
					if( bAdd )
					{
						PatternToCount.Add( Crash.Pattern, 1 );
					}
					else
					{
						PatternToCount[Crash.Pattern]++;
					}
				}
				var PatternToCountOrdered = PatternToCount.OrderByDescending( X => X.Value ).ToList();
				const int NumTopRecords = 200;
				var PatternAndCount = PatternToCountOrdered.Take( NumTopRecords ).ToDictionary( X => X.Key, Y => Y.Value );

				int TotalUniqueAnonymousCrashes = UniquePatterns.Count;

				// Total # of AFFECTED USERS (Anonymous) in timeframe
				int TotalAffectedUsers = UniqueMachines.Count;

				var RealBuggs = BuggsRepo.Context.Buggs.Where( Bugg => PatternAndCount.Keys.Contains( Bugg.Pattern ) ).ToList();

				// Build search string.
				HashSet<string> FoundJiras = new HashSet<string>();
				Dictionary<string, List<Bugg>> JiraIDtoBugg = new Dictionary<string, List<Bugg>>();

				List<Bugg> Buggs = new List<Bugg>( NumTopRecords );
				foreach( var Top in PatternAndCount )
				{
					Bugg NewBugg = RealBuggs.Where( X => X.Pattern == Top.Key ).FirstOrDefault();
					if( NewBugg != null )
					{
						using( FAutoScopedLogTimer TopTimer = new FAutoScopedLogTimer( string.Format( "{0}:{1}", Buggs.Count + 1, NewBugg.Id ) ) )
						{
							var CrashesForBugg = Crashes.Where( Crash => Crash.Pattern == Top.Key ).ToList();

							// Convert anonymous to full type;
							var FullCrashesForBugg = new List<Crash>( CrashesForBugg.Count );
							foreach( var Anon in CrashesForBugg )
							{
								FullCrashesForBugg.Add( new Crash()
								{
									ID = Anon.ID,
									TimeOfCrash = Anon.TimeOfCrash,
									BuildVersion = Anon.BuildVersion,
									Jira = Anon.JIRA,
									Platform = Anon.Platform,
									FixCL = Anon.FixCL,
									BuiltFromCL = Anon.BuiltFromCL,
									Pattern = Anon.Pattern,
									MachineId = Anon.MachineID,
									Branch = Anon.Branch,
									Description = Anon.Description,
									RawCallStack = Anon.RawCallStack,
								} );
							}

							NewBugg.PrepareBuggForJira( FullCrashesForBugg );

							// Verify valid JiraID, this may be still a TTP 
							if( !string.IsNullOrEmpty( NewBugg.Jira ) )
							{
								int TTPID = 0;
								int.TryParse( NewBugg.Jira, out TTPID );

								if( TTPID == 0 )
								{
									AddBuggJiraMapping(NewBugg, ref FoundJiras, ref JiraIDtoBugg);						
								}
							}

							Buggs.Add( NewBugg );
						}
					}
					else
					{
						FLogger.Global.WriteEvent( "Bugg for pattern " + Top.Key + " not found" );
					}
				}

				if( BuggIDToBeAddedToJira > 0 )
				{
					var Bugg = Buggs.Where( X => X.Id == BuggIDToBeAddedToJira ).FirstOrDefault();
					if( Bugg != null )
					{
						Bugg.CopyToJira();
						AddBuggJiraMapping( Bugg, ref FoundJiras, ref JiraIDtoBugg );
					}
				}

				if( JC.CanBeUsed() )
				{
					var BuggsCopy = new List<Bugg>( Buggs );

					HashSet<string> InvalidJiras = new HashSet<string>();

					// Simple verification of JIRA
					foreach (var Value in FoundJiras)
					{
						if( Value.Length < 3 || !Value.Contains('-') )
						{
							InvalidJiras.Add(Value);
						}
					}

					foreach (var InvalidJira in InvalidJiras)
					{
						FoundJiras.Remove( InvalidJira );
					}

					// Grab the data form JIRA.
					string JiraSearchQuery = string.Join( " OR ", FoundJiras );

					using( FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer( "JiraResults" ) )
					{
						var JiraResults = new Dictionary<string, Dictionary<string, object>>();
						try
						{
							JiraResults = JC.SearchJiraTickets(
							JiraSearchQuery,
							new string[] 
							{ 
								"key",				// string
								"summary",			// string
								"components",		// System.Collections.ArrayList, Dictionary<string,object>, name
								"resolution",		// System.Collections.Generic.Dictionary`2[System.String,System.Object], name
								"fixVersions",		// System.Collections.ArrayList, Dictionary<string,object>, name
								"customfield_11200" // string
							} );
						}
						catch (System.Exception)
						{

						}


						// Jira Key, Summary, Components, Resolution, Fix version, Fix changelist
						foreach( var Jira in JiraResults )
						{
							string JiraID = Jira.Key;

							string Summary = (string)Jira.Value["summary"];

							string ComponentsText = "";
							System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"];
							foreach( Dictionary<string, object> Component in Components )
							{
								ComponentsText += (string)Component["name"];
								ComponentsText += " ";
							}

							Dictionary<string, object> ResolutionFields = (Dictionary<string, object>)Jira.Value["resolution"];
							string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : "";

							string FixVersionsText = "";
							System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"];
							foreach( Dictionary<string, object> FixVersion in FixVersions )
							{
								FixVersionsText += (string)FixVersion["name"];
								FixVersionsText += " ";
							}

							int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0;

							List<Bugg> BuggsForJira;
							JiraIDtoBugg.TryGetValue( JiraID, out BuggsForJira );

							//var BuggsForJira = JiraIDtoBugg[JiraID];

							if( BuggsForJira != null )
							{
								foreach( Bugg Bugg in BuggsForJira )
								{
									Bugg.JiraSummary = Summary;
									Bugg.JiraComponentsText = ComponentsText;
									Bugg.JiraResolution = Resolution;
									Bugg.JiraFixVersionsText = FixVersionsText;
									if( FixCL != 0 )
									{
										Bugg.JiraFixCL = FixCL.ToString();
									}

									BuggsCopy.Remove( Bugg );
								}
							}
						}
					}

					// If there are buggs, we need to update the summary to indicate an error.
					// Usually caused when bugg's project has changed.
					foreach( var Bugg in BuggsCopy.Where( b => !string.IsNullOrEmpty( b.Jira ) ) )
					{
						Bugg.JiraSummary = "JIRA MISMATCH";
						Bugg.JiraComponentsText = "JIRA MISMATCH";
						Bugg.JiraResolution = "JIRA MISMATCH";
						Bugg.JiraFixVersionsText = "JIRA MISMATCH";
						Bugg.JiraFixCL = "JIRA MISMATCH";
					}
				}

				Buggs = Buggs.OrderByDescending( b => b.CrashesInTimeFrameGroup ).ToList();

				return new ReportsViewModel
				{
					Buggs = Buggs,
					/*Crashes = Crashes,*/
					DateFrom = (long)( FormData.DateFrom - CrashesViewModel.Epoch ).TotalMilliseconds,
					DateTo = (long)( FormData.DateTo - CrashesViewModel.Epoch ).TotalMilliseconds,
					TotalAffectedUsers = TotalAffectedUsers,
					TotalAnonymousCrashes = TotalAnonymousCrashes,
					TotalUniqueAnonymousCrashes = TotalUniqueAnonymousCrashes
				};
			}
		}
예제 #19
0
 /// <summary>
 /// Link the Http context cache to a Bugg repository.
 /// </summary>
 /// <param name="inCache">The current Http context cache.</param>
 /// <param name="inBuggRepository">The repository to associate the cache with.</param>
 public CachedDataService(Cache inCache, BuggRepository inBuggRepository)
 {
     CacheInstance = inCache;
     Buggs         = inBuggRepository;
 }
예제 #20
0
        /// <summary>
        /// Adds the bugg as a new JIRA ticket
        /// </summary>
        public void CopyToJira()
        {
            var JC = JiraConnection.Get();
            if( JC.CanBeUsed() && string.IsNullOrEmpty( this.Jira ) )
            {
                Dictionary<string, object> Fields = new Dictionary<string, object>();
                Fields.Add( "project", new Dictionary<string, object> { { "id", 11205 } } );	// UE
                Fields.Add( "summary", "[CrashReport] " + ToJiraSummary );						// Call Stack, Line 1
                Fields.Add( "description", string.Join( "\r\n", ToJiraDescriptions ) );			// Description
                Fields.Add( "issuetype", new Dictionary<string, object> { { "id", "1" } } );	// Bug
                Fields.Add( "labels", new string[] { "crash", "liveissue" } );					// <label>crash, live issue</label>
                Fields.Add( "customfield_11500", ToJiraFirstCLAffected );						// Changelist # / Found Changelist
                Fields.Add( "environment", LatestOSAffected );									// Platform

                // Components
                var SupportComponent = JC.GetNameToComponents()["Support"];
                Fields.Add( "components", new object[] { SupportComponent } );

                // ToJiraVersions
                Fields.Add( "versions", ToJiraVersions );

                // ToJiraBranches
                Fields.Add( "customfield_11201", ToJiraBranches );

                // ToJiraPlatforms
                Fields.Add( "customfield_11203", ToJiraPlatforms );

                // Callstack customfield_11807
                string JiraCallstack = string.Join( "\r\n", ToJiraFunctionCalls );
                Fields.Add( "customfield_11807", JiraCallstack );								// Callstack

                string BuggLink = "http://crashreporter/Buggs/Show/" + Id;
                Fields.Add( "customfield_11205", BuggLink );									// Additional Info URL / Link to Crash/Bugg

                string Key = JC.AddJiraTicket( Fields );
                if( !string.IsNullOrEmpty( Key ) )
                {
                    Jira = Key;
                    BuggRepository Buggs = new BuggRepository();
                    Buggs.SetJIRAForBuggAndCrashes( Key, Id );
                }

            }
        }
예제 #21
0
        /// <summary>
        /// Return the top lines of a callstack.
        /// </summary>
        /// <param name="Max">The number of lines to return.</param>
        /// <returns>A list of callstack entries.</returns>
        public List<string> GetFunctionCalls( int Max )
        {
            BuggRepository LocalBuggRepository = new BuggRepository();
            List<string> Results = LocalBuggRepository.GetFunctionCalls( Pattern );

            return Results;
        }
예제 #22
0
        /// <summary>
        /// The Show action.
        /// </summary>
        /// <param name="BuggsForm">The form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the Bugg.</param>
        /// <returns>The view to display a Bugg on the client.</returns>
        public ActionResult Show( FormCollection BuggsForm, int id )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(BuggId=" + id + ")", bCreateNewLog: true ) )
            {
                // Handle 'CopyToJira' button
                int BuggIDToBeAddedToJira = 0;
                foreach( var Entry in BuggsForm )
                {
                    if( Entry.ToString().Contains( Bugg.JiraSubmitName ) )
                    {
                        int.TryParse( Entry.ToString().Substring( Bugg.JiraSubmitName.Length ), out BuggIDToBeAddedToJira );
                        break;
                    }
                }

                BuggRepository Buggs = new BuggRepository();

                // Set the display properties based on the radio buttons
                bool DisplayModuleNames = false;
                if( BuggsForm["DisplayModuleNames"] == "true" )
                {
                    DisplayModuleNames = true;
                }

                bool DisplayFunctionNames = false;
                if( BuggsForm["DisplayFunctionNames"] == "true" )
                {
                    DisplayFunctionNames = true;
                }

                bool DisplayFileNames = false;
                if( BuggsForm["DisplayFileNames"] == "true" )
                {
                    DisplayFileNames = true;
                }

                bool DisplayFilePathNames = false;
                if( BuggsForm["DisplayFilePathNames"] == "true" )
                {
                    DisplayFilePathNames = true;
                    DisplayFileNames = false;
                }

                bool DisplayUnformattedCallStack = false;
                if( BuggsForm["DisplayUnformattedCallStack"] == "true" )
                {
                    DisplayUnformattedCallStack = true;
                }

                // Create a new view and populate with crashes
                List<Crash> Crashes = null;

                BuggViewModel Model = new BuggViewModel();
                Bugg NewBugg = Buggs.GetBugg( id );
                if( NewBugg == null )
                {
                    return RedirectToAction( "" );
                }

                Crashes = NewBugg.GetCrashes();

                using (FAutoScopedLogTimer GetCrashesTimer = new FAutoScopedLogTimer( "Bugg.PrepareBuggForJira" ))
                {
                    if (Crashes.Count > 0)
                    {
                        NewBugg.PrepareBuggForJira( Crashes );

                        if (BuggIDToBeAddedToJira != 0)
                        {
                            NewBugg.CopyToJira();
                        }
                    }

                }

                using( FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer( "Bugg.GrabJira" ) )
                {
                    var JC = JiraConnection.Get();
                    bool bValidJira = false;

                    // Verify valid JiraID, this may be still a TTP
                    if( !string.IsNullOrEmpty( NewBugg.Jira ) )
                    {
                        int TTPID = 0;
                        int.TryParse( NewBugg.Jira, out TTPID );

                        if( TTPID == 0 )
                        {
                            //AddBuggJiraMapping( NewBugg, ref FoundJiras, ref JiraIDtoBugg );
                            bValidJira = true;
                        }
                    }

                    if( JC.CanBeUsed() && bValidJira )
                    {
                        // Grab the data form JIRA.
                        string JiraSearchQuery = "key = " + NewBugg.Jira;

                        var JiraResults = JC.SearchJiraTickets(
                            JiraSearchQuery,
                            new string[]
                            {
                                "key",				// string
                                "summary",			// string
                                "components",		// System.Collections.ArrayList, Dictionary<string,object>, name
                                "resolution",		// System.Collections.Generic.Dictionary`2[System.String,System.Object], name
                                "fixVersions",		// System.Collections.ArrayList, Dictionary<string,object>, name
                                "customfield_11200" // string
                            } );

                        // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist
                        foreach( var Jira in JiraResults )
                        {
                            string JiraID = Jira.Key;

                            string Summary = (string)Jira.Value["summary"];

                            string ComponentsText = "";
                            System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"];
                            foreach( Dictionary<string, object> Component in Components )
                            {
                                ComponentsText += (string)Component["name"];
                                ComponentsText += " ";
                            }

                            Dictionary<string, object> ResolutionFields = (Dictionary<string, object>)Jira.Value["resolution"];
                            string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : "";

                            string FixVersionsText = "";
                            System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"];
                            foreach( Dictionary<string, object> FixVersion in FixVersions )
                            {
                                FixVersionsText += (string)FixVersion["name"];
                                FixVersionsText += " ";
                            }

                            int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0;

                            NewBugg.JiraSummary = Summary;
                            NewBugg.JiraComponentsText = ComponentsText;
                            NewBugg.JiraResolution = Resolution;
                            NewBugg.JiraFixVersionsText = FixVersionsText;
                            if( FixCL != 0 )
                            {
                                NewBugg.JiraFixCL = FixCL.ToString();
                            }

                            break;
                        }
                    }
                }

                // Apply any user settings
                if( BuggsForm.Count > 0 )
                {
                    if( !string.IsNullOrEmpty( BuggsForm["SetStatus"] ) )
                    {
                        NewBugg.Status = BuggsForm["SetStatus"];
                        Buggs.SetBuggStatus( NewBugg.Status, id );
                    }

                    if( !string.IsNullOrEmpty( BuggsForm["SetFixedIn"] ) )
                    {
                        NewBugg.FixedChangeList = BuggsForm["SetFixedIn"];
                        Buggs.SetBuggFixedChangeList( NewBugg.FixedChangeList, id );
                    }

                    if( !string.IsNullOrEmpty( BuggsForm["SetTTP"] ) )
                    {
                        NewBugg.Jira = BuggsForm["SetTTP"];
                        Buggs.SetJIRAForBuggAndCrashes( NewBugg.Jira, id );
                    }

                    // <STATUS>
                }

                // Set up the view model with the crash data
                Model.Bugg = NewBugg;
                Model.Crashes = Crashes;

                Crash NewCrash = Model.Crashes.FirstOrDefault();
                if( NewCrash != null )
                {
                    using( FScopedLogTimer LogTimer2 = new FScopedLogTimer( "CallstackTrimming" ) )
                    {
                        CallStackContainer CallStack = new CallStackContainer( NewCrash );

                        // Set callstack properties
                        CallStack.bDisplayModuleNames = DisplayModuleNames;
                        CallStack.bDisplayFunctionNames = DisplayFunctionNames;
                        CallStack.bDisplayFileNames = DisplayFileNames;
                        CallStack.bDisplayFilePathNames = DisplayFilePathNames;
                        CallStack.bDisplayUnformattedCallStack = DisplayUnformattedCallStack;

                        Model.CallStack = CallStack;

                        // Shorten very long function names.
                        foreach( CallStackEntry Entry in Model.CallStack.CallStackEntries )
                        {
                            Entry.FunctionName = Entry.GetTrimmedFunctionName( 128 );
                        }

                        Model.SourceContext = NewCrash.SourceContext;
                    }

                    Model.Bugg.LatestCrashSummary = NewCrash.Summary;
                }

                Model.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
                return View( "Show", Model );
            }
        }
예제 #23
0
		/// <summary>
		/// Adds the bugg as a new JIRA ticket
		/// </summary>
		public void CopyToJira()
		{
            var jc = JiraConnection.Get();
		    Dictionary<string, object> issueFields;

            if (BranchesFoundIn.Any(data => data.ToLower().Contains("//fort")))
            {
                issueFields = CreateFortniteIssue(jc);
            }
            //else if (BranchesFoundIn.Any(data => data.ToLower().Contains("//orion")))
            //{
            //    issueFields = CreateOrionIssue();
            //}
            else
		    {
                issueFields = CreateGeneralIssue(jc);
		    }
            
			if(jc.CanBeUsed() && string.IsNullOrEmpty( this.Jira ))
			{
				// Additional Info URL / Link to Crash/Bugg
                string Key = jc.AddJiraTicket(issueFields);
				if( !string.IsNullOrEmpty( Key ) )
				{
					Jira = Key;
					var buggs = new BuggRepository();
					buggs.SetJIRAForBuggAndCrashes( Key, Id );
				}
			}
		}
예제 #24
0
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public EntitySet<Crash> GetCrashes()
        {
            if( BuggCrashes == null )
            {
                BuggCrashes = Crashes;
            }

            int CrashCount = BuggCrashes.Count;
            if( NumberOfCrashes != CrashCount )
            {
                NumberOfCrashes = CrashCount;

                if( NumberOfCrashes > 0 )
                {
                    BuggRepository LocalBuggRepository = new BuggRepository();
                    LocalBuggRepository.UpdateBuggData( this, BuggCrashes );
                }
            }

            // Just fill the CallStackContainers
            foreach( Crash CurrentCrash in BuggCrashes )
            {
                if( CurrentCrash.CallStackContainer == null )
                {
                    CurrentCrash.CallStackContainer = CurrentCrash.GetCallStack();
                }

                if( SourceContext == null )
                {
                    SourceContext = CurrentCrash.SourceContext;
                }
            }

            return BuggCrashes;
        }