/// <summary>
        /// Add a new crash to the db based on a CrashDescription sent from the client.
        /// </summary>
        /// <param name="NewCrashInfo">The crash description sent from the client.</param>
        /// <returns>The id of the newly added crash.</returns>
        public int AddNewCrash(CrashDescription NewCrashInfo)
        {
            int NewID = -1;

            Crash NewCrash = new Crash();

            NewCrash.Branch       = NewCrashInfo.BranchName;
            NewCrash.BaseDir      = NewCrashInfo.BaseDir;
            NewCrash.BuildVersion = NewCrashInfo.BuildVersion;
            NewCrash.BuiltFromCL  = NewCrashInfo.BuiltFromCL.ToString();
            NewCrash.CommandLine  = NewCrashInfo.CommandLine;
            NewCrash.EngineMode   = NewCrashInfo.EngineMode;
            NewCrash.MachineId    = NewCrashInfo.MachineGuid;

            //if there's a valid username assign the associated UserNameId else use "anonymous"
            NewCrash.UserNameId = FRepository.Get(this).FindOrAddUser(!string.IsNullOrEmpty(NewCrashInfo.UserName) ? NewCrashInfo.UserName : UserNameAnonymous);

            //If there's a valid EpicAccountId assign that.
            if (!string.IsNullOrEmpty(NewCrashInfo.EpicAccountId))
            {
                NewCrash.EpicAccountId = NewCrashInfo.EpicAccountId;
            }

            NewCrash.Description = "";
            if (NewCrashInfo.UserDescription != null)
            {
                NewCrash.Description = string.Join(Environment.NewLine, NewCrashInfo.UserDescription);
            }

            NewCrash.EngineMode   = NewCrashInfo.EngineMode;
            NewCrash.GameName     = NewCrashInfo.GameName;
            NewCrash.LanguageExt  = NewCrashInfo.Language;            // Converted by the crash process.
            NewCrash.PlatformName = NewCrashInfo.Platform;

            if (NewCrashInfo.ErrorMessage != null)
            {
                NewCrash.Summary = string.Join("\n", NewCrashInfo.ErrorMessage);
            }

            if (NewCrashInfo.CallStack != null)
            {
                NewCrash.RawCallStack = string.Join("\n", NewCrashInfo.CallStack);
            }

            if (NewCrashInfo.SourceContext != null)
            {
                NewCrash.SourceContext = string.Join("\n", NewCrashInfo.SourceContext);
            }

            NewCrash.TimeOfCrash         = NewCrashInfo.TimeofCrash;
            NewCrash.bAllowToBeContacted = NewCrashInfo.bAllowToBeContacted;

            NewCrash.Jira            = "";
            NewCrash.FixedChangeList = "";

            // Set the crash type
            NewCrash.CrashType = 1;
            if (NewCrash.RawCallStack != null)
            {
                if (NewCrash.RawCallStack.Contains("FDebug::AssertFailed"))
                {
                    NewCrash.CrashType = 2;
                }
                else if (NewCrash.RawCallStack.Contains("FDebug::Ensure"))
                {
                    NewCrash.CrashType = 3;
                }
                else if (NewCrash.RawCallStack.Contains("FDebug::OptionallyLogFormattedEnsureMessageReturningFalse"))
                {
                    NewCrash.CrashType = 3;
                }
                else if (NewCrash.RawCallStack.Contains("NewReportEnsure"))
                {
                    NewCrash.CrashType = 3;
                }
            }

            // As we're adding it, the status is always new
            NewCrash.Status = "New";

            /*
             *      Unused Crashes' fields.
             *
             *      Title				nchar(20)
             *      Selected			bit
             *      Version				int
             *      AutoReporterID		int
             *      Processed			bit	-> renamed to AllowToBeContacted
             *      HasDiagnosticsFile	bit	always true
             *      HasNewLogFile		bit
             *      HasMetaData			bit	always true
             */
            // Set the unused fields to the default values.
            //NewCrash.Title = "";			removed from dbml
            //NewCrash.Selected = false;	removed from dbml
            //NewCrash.Version = 4;			removed from dbml
            //NewCrash.AutoReporterID = 0;	removed from dbml
            //NewCrash.HasNewLogFile = false;removed from dbml
            //
            //NewCrash.HasDiagnosticsFile = true;
            //NewCrash.HasMetaData = true;

            NewCrash.UserActivityHint = NewCrashInfo.UserActivityHint;

            // Add the crash to the database
            Context.Crashes.InsertOnSubmit(NewCrash);
            SubmitChanges();

            NewID = NewCrash.Id;

            // Build a callstack pattern for crash bucketing
            NewCrash.BuildPattern(Context);

            return(NewID);
        }
Beispiel #2
0
        /// <summary>
        /// Sort the container of Buggs by the requested criteria.
        /// </summary>
        /// <param name="Results">A container of unsorted Buggs.</param>
        /// <param name="SortTerm">The term to sort by.</param>
        /// <param name="bSortDescending">Whether to sort by descending or ascending.</param>
        /// <param name="DateFrom">The date of the earliest Bugg to examine.</param>
        /// <param name="DateTo">The date of the most recent Bugg to examine.</param>
        /// <param name="GroupName">The user group name to filter by.</param>
        /// <returns>A sorted container of Buggs.</returns>
        public IEnumerable <Bugg> GetSortedResults(IEnumerable <Bugg> Results, string SortTerm, bool bSortDescending, DateTime DateFrom, DateTime DateTo, string GroupName)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                try
                {
                    // Get the group id and grab all buggs for the specified group.
                    HashSet <string> UserNamesForUserGroup = FRepository.Get(this).GetUserNamesFromGroupName(GroupName);

                    // Simplified query.
                    var BuggIdToCountMapGroup = new Dictionary <int, int>();
                    var BuggIdToCountMapRest  = new Dictionary <int, int>();
                    var BuggIdToMachineSet    = new Dictionary <int, HashSet <string> >();
                    Dictionary <string, int> MachineIdToCountMap = new Dictionary <string, int>();
                    List <Buggs_Crash>       BuggsFromDate       = null;
                    Dictionary <int, string> CrashToUser         = null;
                    Dictionary <int, string> CrashToMachine      = null;


                    // Get all buggs from the date range.
                    using (FScopedLogTimer LogTimer1 = new FScopedLogTimer("BuggRepository.GetSortedResults.BuggsFromDate SQL"))
                    {
                        BuggsFromDate =
                            (
                                from BuggCrash in Context.Buggs_Crashes
                                where BuggCrash.Crash.TimeOfCrash >= DateFrom && BuggCrash.Crash.TimeOfCrash <= DateTo.AddDays(1)
                                select BuggCrash
                            ).AsEnumerable().ToList();

                        var CrashesWithIdUserMachine =
                            (
                                from Crash in Context.Crashes
                                where Crash.TimeOfCrash >= DateFrom && Crash.TimeOfCrash <= DateTo.AddDays(1)
                                select new { Id = Crash.Id, UserName = Crash.UserName, MachineId = Crash.MachineId }
                            );

                        CrashToUser    = CrashesWithIdUserMachine.ToDictionary(x => x.Id, y => y.UserName);
                        CrashToMachine = CrashesWithIdUserMachine.ToDictionary(x => x.Id, y => y.MachineId);
                    }


                    using (FScopedLogTimer LogTimer0 = new FScopedLogTimer("BuggRepository.GetSortedResults.Filtering"))
                    {
                        // This calculates total crashes for selected group and all groups.
                        foreach (Buggs_Crash BuggCrash in BuggsFromDate)
                        {
                            string MachineId;
                            CrashToMachine.TryGetValue(BuggCrash.CrashId, out MachineId);

                            string UserName       = CrashToUser[BuggCrash.CrashId];
                            bool   bValidForGroup = UserNamesForUserGroup.Contains(UserName);
                            if (!bValidForGroup)
                            {
                                int  CountRest     = 0;
                                bool bFoundRestKey = BuggIdToCountMapRest.TryGetValue(BuggCrash.BuggId, out CountRest);
                                if (bFoundRestKey)
                                {
                                    BuggIdToCountMapRest[BuggCrash.BuggId]++;
                                }
                                else
                                {
                                    BuggIdToCountMapRest.Add(BuggCrash.BuggId, 1);
                                }

                                continue;
                            }

                            int  Count     = 0;
                            bool bFoundKey = BuggIdToCountMapGroup.TryGetValue(BuggCrash.BuggId, out Count);
                            if (bFoundKey)
                            {
                                BuggIdToCountMapGroup[BuggCrash.BuggId]++;
                            }
                            else
                            {
                                BuggIdToCountMapGroup.Add(BuggCrash.BuggId, 1);
                            }

                            if (MachineId != null && MachineId.Length > 0)
                            {
                                HashSet <string> MachineSet       = null;
                                bool             bFoundMachineKey = BuggIdToMachineSet.TryGetValue(BuggCrash.BuggId, out MachineSet);
                                if (!bFoundMachineKey)
                                {
                                    BuggIdToMachineSet.Add(BuggCrash.BuggId, new HashSet <string>());
                                }

                                BuggIdToMachineSet[BuggCrash.BuggId].Add(MachineId);
                            }
                        }
                    }

                    using (FScopedLogTimer LogTimer2 = new FScopedLogTimer("BuggRepository.GetSortedResults.CrashesInTimeFrame"))
                    {
                        foreach (var Result in Results)
                        {
                            int GroupCount = 0;
                            BuggIdToCountMapGroup.TryGetValue(Result.Id, out GroupCount);
                            Result.CrashesInTimeFrameGroup = GroupCount;

                            int GroupRest = 0;
                            BuggIdToCountMapRest.TryGetValue(Result.Id, out GroupRest);
                            Result.CrashesInTimeFrameAll = GroupCount + GroupRest;
                        }
                    }

                    using (FScopedLogTimer LogTimer2 = new FScopedLogTimer("BuggRepository.GetSortedResults.UniqueMachineCrashesInTimeFrame"))
                    {
                        foreach (var Result in Results)
                        {
                            HashSet <string> MachineSet = null;
                            bool             bFoundKey  = BuggIdToMachineSet.TryGetValue(Result.Id, out MachineSet);
                            if (bFoundKey)
                            {
                                Result.NumberOfUniqueMachines = MachineSet.Count;
                            }
                            else
                            {
                                Result.NumberOfUniqueMachines = 0;
                            }
                        }
                    }

                    switch (SortTerm)
                    {
                    case "CrashesInTimeFrameGroup":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.CrashesInTimeFrameGroup, bSortDescending);
                        break;

                    case "CrashesInTimeFrameAll":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.CrashesInTimeFrameAll, bSortDescending);
                        break;

                    case "Id":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.Id, bSortDescending);
                        break;

                    case "BuildVersion":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.BuildVersion, bSortDescending);
                        break;

                    case "LatestCrash":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.TimeOfLastCrash, bSortDescending);
                        break;

                    case "FirstCrash":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.TimeOfFirstCrash, bSortDescending);
                        break;

                    case "NumberOfCrashes":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.NumberOfCrashes, bSortDescending);
                        break;


                    case "NumberOfUsers":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.NumberOfUniqueMachines, bSortDescending);
                        break;

                    case "Pattern":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.Pattern, bSortDescending);
                        break;

                    case "CrashType":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.CrashType, bSortDescending);
                        break;

                    case "Status":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.Status, bSortDescending);
                        break;

                    case "FixedChangeList":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.FixedChangeList, bSortDescending);
                        break;

                    case "TTPID":
                        Results = EnumerableOrderBy(Results, BuggCrashInstance => BuggCrashInstance.Jira, bSortDescending);
                        break;
                    }
                    return(Results);
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetSortedResults: " + Ex.ToString());
                }
                return(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,
                });
            }
        }
Beispiel #4
0
        /// <summary>
        /// Add a new crash to the db based on a CrashDescription sent from the client.
        /// </summary>
        /// <param name="NewCrashInfo">The crash description sent from the client.</param>
        /// <returns>The id of the newly added crash.</returns>
        public int AddNewCrash(CrashDescription NewCrashInfo)
        {
            int NewID = -1;

            Crash NewCrash = new Crash();

            NewCrash.Branch            = NewCrashInfo.BranchName;
            NewCrash.BaseDir           = NewCrashInfo.BaseDir;
            NewCrash.BuildVersion      = NewCrashInfo.BuildVersion;
            NewCrash.ChangeListVersion = NewCrashInfo.BuiltFromCL.ToString();
            NewCrash.CommandLine       = NewCrashInfo.CommandLine;
            NewCrash.EngineMode        = NewCrashInfo.EngineMode;
            NewCrash.ComputerName      = NewCrashInfo.MachineGuid;

            // Valid MachineID and UserName, updated crash from non-UE4 release
            if (!string.IsNullOrEmpty(NewCrashInfo.UserName))
            {
                NewCrash.UserNameId = FRepository.Get(this).FindOrAddUser(NewCrashInfo.UserName);
            }
            // Valid MachineID and EpicAccountId, updated crash from UE4 release
            else if (!string.IsNullOrEmpty(NewCrashInfo.EpicAccountId))
            {
                NewCrash.EpicAccountId = NewCrashInfo.EpicAccountId;
                NewCrash.UserNameId    = FRepository.Get(this).FindOrAddUser(UserNameAnonymous);
            }
            // Crash from an older version.
            else
            {
                // MachineGuid for older crashes is obsolete, so ignore it.
                //NewCrash.ComputerName = NewCrashInfo.MachineGuid;
                NewCrash.UserNameId = FRepository.Get(this).FindOrAddUser
                                      (
                    !string.IsNullOrEmpty(NewCrashInfo.UserName) ? NewCrashInfo.UserName : UserNameAnonymous
                                      );
            }

            NewCrash.Description = "";
            if (NewCrashInfo.UserDescription != null)
            {
                NewCrash.Description = string.Join(Environment.NewLine, NewCrashInfo.UserDescription);
            }

            NewCrash.EngineMode   = NewCrashInfo.EngineMode;
            NewCrash.GameName     = NewCrashInfo.GameName;
            NewCrash.LanguageExt  = NewCrashInfo.Language;            // Converted by the crash process.
            NewCrash.PlatformName = NewCrashInfo.Platform;

            if (NewCrashInfo.ErrorMessage != null)
            {
                NewCrash.Summary = string.Join("\n", NewCrashInfo.ErrorMessage);
            }

            if (NewCrashInfo.CallStack != null)
            {
                NewCrash.RawCallStack = string.Join("\n", NewCrashInfo.CallStack);
            }

            if (NewCrashInfo.SourceContext != null)
            {
                NewCrash.SourceContext = string.Join("\n", NewCrashInfo.SourceContext);
            }

            NewCrash.TimeOfCrash = NewCrashInfo.TimeofCrash;

            NewCrash.HasLogFile         = NewCrashInfo.bHasLog;
            NewCrash.HasMiniDumpFile    = NewCrashInfo.bHasMiniDump;
            NewCrash.HasDiagnosticsFile = NewCrashInfo.bHasDiags;
            NewCrash.HasVideoFile       = NewCrashInfo.bHasVideo;
            NewCrash.HasMetaData        = NewCrashInfo.bHasWERData;

            NewCrash.bAllowToBeContacted = NewCrashInfo.bAllowToBeContacted;

            NewCrash.TTPID           = "";
            NewCrash.FixedChangeList = "";

            // Set the crash type
            NewCrash.CrashType = 1;
            if (NewCrash.RawCallStack != null)
            {
                if (NewCrash.RawCallStack.Contains("FDebug::AssertFailed()"))
                {
                    NewCrash.CrashType = 2;
                }
                else if (NewCrash.RawCallStack.Contains("FDebug::EnsureFailed()"))
                {
                    NewCrash.CrashType = 3;
                }
            }

            // As we're adding it, the status is always new
            NewCrash.Status = "New";

            /*
             *      Unused Crashes' fields.
             *
             *      Title				nchar(20)
             *      Selected			bit
             *      Version				int
             *      AutoReporterID		int
             *      Processed			bit	-> renamed to AllowToBeContacted
             *      HasDiagnosticsFile	bit	always true
             *      HasNewLogFile		bit
             *      HasMetaData			bit	always true
             */
            // Set the unused fields to the default values.
            //NewCrash.Title = "";			removed from dbml
            //NewCrash.Selected = false;	removed from dbml
            //NewCrash.Version = 4;			removed from dbml
            //NewCrash.AutoReporterID = 0;	removed from dbml
            //NewCrash.HasNewLogFile = false;removed from dbml
            //
            //NewCrash.HasDiagnosticsFile = true;
            //NewCrash.HasMetaData = true;

            // Add the crash to the database
            Context.Crashes.InsertOnSubmit(NewCrash);
            SubmitChanges();

            NewID = NewCrash.Id;

            // Build a callstack pattern for crash bucketing
            NewCrash.BuildPattern(Context);

            return(NewID);
        }