public DashboardController() { //Hideous temporary code //no! Unity! Dependency injection! Single Context wrapper! _Crashes = new CrashRepository(_entities); _Buggs = new BuggRepository(_entities); }
static AppActs.API.Service.Interface.IDeviceService setup() { MongoClient client = new MongoClient(ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString); string database = ConfigurationManager.AppSettings["database"]; AppActs.Repository.Interface.IApplicationRepository applicationRepository = new AppActs.Repository.ApplicationRepository(client, database); IDeviceRepository deviceRepository = new DeviceRepository(new DeviceMapper(client, database)); IFeedbackRepository feedbackRepository = new FeedbackRepository(new FeedbackMapper(client, database)); IEventRepository eventRep = new EventRepository(new EventMapper(client, database)); ICrashRepository crashRep = new CrashRepository(new CrashMapper(client, database)); IAppUserRepository appUserRep = new AppUserRepository(new AppUserMapper(client, database)); IErrorRepository errorRep = new ErrorRepository(new ErrorMapper(client, database)); ISystemErrorRepository systemErrorRep = new SystemErrorRepository(new SystemErrorMapper(client, database)); return(new DeviceService ( deviceRepository, errorRep, eventRep, crashRep, feedbackRepository, systemErrorRep, appUserRep, applicationRepository, new Model.Settings() { DataLoggingRecordRaw = true, DataLoggingRecordSystemErrors = true } )); }
/// <summary> /// Add a crash passed in the payload as Xml to the database. /// </summary> /// <param name="id">Unused.</param> /// <returns>The row id of the newly added crash.</returns> public ActionResult AddCrash(int id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(NewCrashId=" + id + ")")) { CrashRepository Crashes = new CrashRepository(); CrashReporterResult NewCrashResult = new CrashReporterResult(); NewCrashResult.ID = -1; try { using (StreamReader Reader = new StreamReader(Request.InputStream, Request.ContentEncoding)) { string Result = Reader.ReadToEnd(); CrashDescription NewCrash = XmlHandler.FromXmlString <CrashDescription>(Result); NewCrashResult.ID = Crashes.AddNewCrash(NewCrash); NewCrashResult.bSuccess = true; } } catch (Exception Ex) { NewCrashResult.Message = Ex.ToString(); NewCrashResult.bSuccess = false; } string ReturnResult = XmlHandler.ToXmlString <CrashReporterResult>(NewCrashResult); return(Content(ReturnResult, "text/xml")); } }
/// <summary> /// Add a crash passed in the payload as Xml to the database. /// </summary> /// <param name="id">Unused.</param> /// <returns>The row id of the newly added crash.</returns> public ActionResult AddCrash( int id ) { using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(NewCrashId=" + id + ")" ) ) { CrashRepository Crashes = new CrashRepository(); CrashReporterResult NewCrashResult = new CrashReporterResult(); NewCrashResult.ID = -1; try { using( StreamReader Reader = new StreamReader( Request.InputStream, Request.ContentEncoding ) ) { string Result = Reader.ReadToEnd(); CrashDescription NewCrash = XmlHandler.FromXmlString<CrashDescription>( Result ); NewCrashResult.ID = Crashes.AddNewCrash( NewCrash ); NewCrashResult.bSuccess = true; } } catch( Exception Ex ) { NewCrashResult.Message = Ex.ToString(); NewCrashResult.bSuccess = false; } string ReturnResult = XmlHandler.ToXmlString<CrashReporterResult>( NewCrashResult ); return Content( ReturnResult, "text/xml" ); } }
private void UnsafeAddCrash(CrashReporterResult NewCrashResult, CrashRepository Crashes) { using (StreamReader Reader = new StreamReader(Request.InputStream, Request.ContentEncoding)) { string Result = Reader.ReadToEnd(); CrashDescription NewCrash = XmlHandler.FromXmlString <CrashDescription>(Result); NewCrashResult.ID = Crashes.AddNewCrash(NewCrash); NewCrashResult.bSuccess = true; } }
/// <summary> /// Add a crash passed in the payload as Xml to the database. /// </summary> /// <param name="id">Unused.</param> /// <returns>The row id of the newly added crash.</returns> public ActionResult AddCrash(int id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(NewCrashId=" + id + ")")) { CrashRepository Crashes = new CrashRepository(); CrashReporterResult NewCrashResult = new CrashReporterResult(); NewCrashResult.ID = -1; string PayloadString = string.Empty; for (int Index = 0; Index < 3; Index++) { try { using (StreamReader Reader = new StreamReader(Request.InputStream, Request.ContentEncoding)) { PayloadString = Reader.ReadToEnd(); CrashDescription NewCrash = XmlHandler.FromXmlString <CrashDescription>(PayloadString); NewCrashResult.ID = Crashes.AddNewCrash(NewCrash); NewCrashResult.bSuccess = true; } break; } catch (SqlException SqlExc) { if (SqlExc.Number == -2) { FLogger.Global.WriteEvent(string.Format("AddCrash:Timeout, retrying {0} of 3", Index + 1)); } else { NewCrashResult.Message = SqlExc.ToString(); NewCrashResult.bSuccess = false; break; } } catch (Exception Ex) { StringBuilder MessageBuilder = new StringBuilder(); MessageBuilder.AppendLine("Exception was:"); MessageBuilder.AppendLine(Ex.ToString()); MessageBuilder.AppendLine("Received payload was:"); MessageBuilder.AppendLine(PayloadString); NewCrashResult.Message = MessageBuilder.ToString(); NewCrashResult.bSuccess = false; break; } System.Threading.Thread.Sleep(5000 * (Index + 1)); } string ReturnResult = XmlHandler.ToXmlString <CrashReporterResult>(NewCrashResult); return(Content(ReturnResult, "text/xml")); } }
/// <summary> /// Display a summary list of crashes based on the search criteria. /// </summary> /// <param name="CrashesForm">A form of user data passed up from the client.</param> /// <returns>A view to display a list of crash reports.</returns> public ActionResult Index( FormCollection CrashesForm ) { using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ) ) { CrashRepository Crashes = new CrashRepository(); // Handle any edits made in the Set form fields foreach( var Entry in CrashesForm ) { int Id = 0; if( int.TryParse( Entry.ToString(), out Id ) ) { Crash CurrentCrash = Crashes.GetCrash( Id ); if( CurrentCrash != null ) { if( !string.IsNullOrEmpty( CrashesForm["SetStatus"] ) ) { CurrentCrash.Status = CrashesForm["SetStatus"]; } if( !string.IsNullOrEmpty( CrashesForm["SetFixedIn"] ) ) { CurrentCrash.FixedChangeList = CrashesForm["SetFixedIn"]; } if( !string.IsNullOrEmpty( CrashesForm["SetTTP"] ) ) { CurrentCrash.Jira = CrashesForm["SetTTP"]; } } } Crashes.SubmitChanges(); } // <STATUS> // Parse the contents of the query string, and populate the form FormHelper FormData = new FormHelper( Request, CrashesForm, "TimeOfCrash" ); CrashesViewModel Result = Crashes.GetResults( FormData ); // Add the FromCollection to the CrashesViewModel since we don't need it for the get results function but we do want to post it back to the page. Result.FormCollection = CrashesForm; Result.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" ); return View( "Index", Result ); } }
/// <summary> /// Display a summary list of crashes based on the search criteria. /// </summary> /// <param name="CrashesForm">A form of user data passed up from the client.</param> /// <returns>A view to display a list of crash reports.</returns> public ActionResult Index(FormCollection CrashesForm) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString(), bCreateNewLog: true)) { CrashRepository Crashes = new CrashRepository(); // Handle any edits made in the Set form fields foreach (var Entry in CrashesForm) { int Id = 0; if (int.TryParse(Entry.ToString(), out Id)) { Crash CurrentCrash = Crashes.GetCrash(Id); if (CurrentCrash != null) { if (!string.IsNullOrEmpty(CrashesForm["SetStatus"])) { CurrentCrash.Status = CrashesForm["SetStatus"]; } if (!string.IsNullOrEmpty(CrashesForm["SetFixedIn"])) { CurrentCrash.FixedChangeList = CrashesForm["SetFixedIn"]; } if (!string.IsNullOrEmpty(CrashesForm["SetTTP"])) { CurrentCrash.Jira = CrashesForm["SetTTP"]; } } } Crashes.SubmitChanges(); } // <STATUS> // Parse the contents of the query string, and populate the form FormHelper FormData = new FormHelper(Request, CrashesForm, "TimeOfCrash"); CrashesViewModel Result = Crashes.GetResults(FormData); // Add the FromCollection to the CrashesViewModel since we don't need it for the get results function but we do want to post it back to the page. Result.FormCollection = CrashesForm; Result.GenerationTime = LogTimer.GetElapsedSeconds().ToString("F2"); return(View("Index", Result)); } }
/// <summary> /// Add a crash passed in the payload as Xml to the database. /// </summary> /// <param name="id">Unused.</param> /// <returns>The row id of the newly added crash.</returns> public ActionResult AddCrash(int id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(NewCrashId=" + id + ")")) { CrashRepository Crashes = new CrashRepository(); CrashReporterResult NewCrashResult = new CrashReporterResult(); NewCrashResult.ID = -1; for (int Index = 0; Index < 3; Index++) { try { UnsafeAddCrash(NewCrashResult, Crashes); break; } catch (SqlException SqlExc) { if (SqlExc.Number == -2) { FLogger.Global.WriteEvent(string.Format("AddCrash:Timeout, retrying {0} of 3", Index + 1)); } else { NewCrashResult.Message = SqlExc.ToString(); NewCrashResult.bSuccess = false; break; } } catch (Exception Ex) { NewCrashResult.Message = Ex.ToString(); NewCrashResult.bSuccess = false; break; } System.Threading.Thread.Sleep(5000 * (Index + 1)); } string ReturnResult = XmlHandler.ToXmlString <CrashReporterResult>(NewCrashResult); return(Content(ReturnResult, "text/xml")); } }
/// <summary> /// Display the main user groups. /// </summary> /// <param name="UserForms">A form of user data passed up from the client.</param> /// <param name="UserGroup">The name of the current user group to display users for.</param> /// <returns>A view to show a list of users in the current user group.</returns> public ActionResult Index( FormCollection UserForms, string UserGroup ) { CrashRepository Crashes = new CrashRepository(); // Examine an incoming form for a new user group foreach( var FormInstance in UserForms ) { string UserName = FormInstance.ToString(); string NewUserGroup = UserForms[UserName]; FRepository.Get( Crashes ).SetUserGroup( UserName, NewUserGroup ); } UsersViewModel Model = new UsersViewModel(); Model.UserGroup = UserGroup; Model.Users = FRepository.Get( Crashes ).GetUserNamesFromGroupName( UserGroup ); Model.GroupCounts = FRepository.Get( Crashes ).GetCountsByGroup(); return View( "Index", Model ); }
/// <summary> /// Display the main user groups. /// </summary> /// <param name="UserForms">A form of user data passed up from the client.</param> /// <param name="UserGroup">The name of the current user group to display users for.</param> /// <returns>A view to show a list of users in the current user group.</returns> public ActionResult Index(FormCollection UserForms, string UserGroup) { CrashRepository Crashes = new CrashRepository(); // Examine an incoming form for a new user group foreach (var FormInstance in UserForms) { string UserName = FormInstance.ToString(); string NewUserGroup = UserForms[UserName]; FRepository.Get(Crashes).SetUserGroup(UserName, NewUserGroup); } UsersViewModel Model = new UsersViewModel(); Model.UserGroup = UserGroup; Model.Users = FRepository.Get(Crashes).GetUserNamesFromGroupName(UserGroup); Model.GroupCounts = FRepository.Get(Crashes).GetCountsByGroup(); return(View("Index", Model)); }
/// <summary> /// The main view of the dash board. /// </summary> /// <returns>A view showing two charts of crashes over time.</returns> public ActionResult Index() { CrashRepository LocalCrashRepository = new CrashRepository(); IQueryable<Crash> Crashes = LocalCrashRepository.ListAll(); int UndefinedUserGroupId = LocalCrashRepository.FindOrAddUserGroup( "Undefined" ); int GeneralUserGroupId = LocalCrashRepository.FindOrAddUserGroup( "General" ); int CoderUserGroupId = LocalCrashRepository.FindOrAddUserGroup( "Coder" ); int EngineQAUserGroupId = LocalCrashRepository.FindOrAddUserGroup( "EngineQA" ); int GameQAUserGroupId = LocalCrashRepository.FindOrAddUserGroup( "GameQA" ); int AutomatedUserGroupId = LocalCrashRepository.FindOrAddUserGroup( "Automated" ); Dictionary<DateTime, int> GeneralResults = LocalCrashRepository.GetWeeklyCountsByGroup( Crashes, GeneralUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> CoderResults = LocalCrashRepository.GetWeeklyCountsByGroup( Crashes, CoderUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> EngineQAResults = LocalCrashRepository.GetWeeklyCountsByGroup( Crashes, EngineQAUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> GameQAResults = LocalCrashRepository.GetWeeklyCountsByGroup( Crashes, GameQAUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> AutomatedResults = LocalCrashRepository.GetWeeklyCountsByGroup( Crashes, AutomatedUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> AllResults = LocalCrashRepository.GetWeeklyCountsByGroup( Crashes, -1, UndefinedUserGroupId ); Dictionary<DateTime, int> DailyGeneralResults = LocalCrashRepository.GetDailyCountsByGroup( Crashes, GeneralUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> DailyCoderResults = LocalCrashRepository.GetDailyCountsByGroup( Crashes, CoderUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> DailyEngineQAResults = LocalCrashRepository.GetDailyCountsByGroup( Crashes, EngineQAUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> DailyGameQAResults = LocalCrashRepository.GetDailyCountsByGroup( Crashes, GameQAUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> DailyAutomatedResults = LocalCrashRepository.GetDailyCountsByGroup( Crashes, AutomatedUserGroupId, UndefinedUserGroupId ); Dictionary<DateTime, int> DailyAllResults = LocalCrashRepository.GetDailyCountsByGroup( Crashes, -1, UndefinedUserGroupId ); string CrashesByWeek = ""; foreach( KeyValuePair<DateTime, int> Result in AllResults ) { int GeneralCrashes = 0; try { GeneralCrashes = GeneralResults[Result.Key]; } catch { } int CoderCrashes = 0; try { CoderCrashes = CoderResults[Result.Key]; } catch { } int EngineQACrashes = 0; try { EngineQACrashes = EngineQAResults[Result.Key]; } catch { } int GameQACrashes = 0; try { GameQACrashes = GameQAResults[Result.Key]; } catch { } int AutomatedCrashes = 0; try { AutomatedCrashes = AutomatedResults[Result.Key]; } catch { } int Year = Result.Key.Year; int Month = Result.Key.AddMonths( -1 ).Month; if( Result.Key.Month == 13 || Result.Key.Month == 1 ) { Month = 0; } int Day = Result.Key.Day + 6; string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + GeneralCrashes + ", " + CoderCrashes + ", " + EngineQACrashes + ", " + GameQACrashes + ", " + AutomatedCrashes + ", " + Result.Value + "], "; CrashesByWeek = CrashesByWeek + Line; } CrashesByWeek = CrashesByWeek.TrimEnd( ", ".ToCharArray() ); string CrashesByDay = ""; foreach( KeyValuePair<DateTime, int> DailyResult in DailyAllResults ) { int GeneralCrashes = 0; try { GeneralCrashes = DailyGeneralResults[DailyResult.Key]; } catch { } int CoderCrashes = 0; try { CoderCrashes = DailyCoderResults[DailyResult.Key]; } catch { } int EngineQACrashes = 0; try { EngineQACrashes = DailyEngineQAResults[DailyResult.Key]; } catch { } int GameQACrashes = 0; try { GameQACrashes = DailyGameQAResults[DailyResult.Key]; } catch { } int AutomatedCrashes = 0; try { AutomatedCrashes = DailyAutomatedResults[DailyResult.Key]; } catch { } int Year = DailyResult.Key.Year; int Month = DailyResult.Key.AddMonths( -1 ).Month; if( DailyResult.Key.Month == 13 || DailyResult.Key.Month == 1 ) { Month = 0; } int Day = DailyResult.Key.Day; string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + GeneralCrashes + ", " + CoderCrashes + ", " + EngineQACrashes + ", " + GameQACrashes + ", " + AutomatedCrashes + ", " + DailyResult.Value + "], "; CrashesByDay = CrashesByDay + Line; } CrashesByDay = CrashesByDay.TrimEnd( ", ".ToCharArray() ); return View( "Index", new DashboardViewModel { CrashesByWeek = CrashesByWeek, CrashesByDay = CrashesByDay } ); }
/// <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 }; } }
/// <summary> /// Gets a formatted callstack for the crash. /// </summary> /// <returns>A formatted callstack.</returns> public CallStackContainer GetCallStack() { CrashRepository Crashes = new CrashRepository(); return Crashes.GetCallStack( this ); }
public void SaveThrowsDataAccessLayerException() { ICrashRepository iCrashRepository = new CrashRepository(this.connectionString); iCrashRepository.Save(1, 1, new Crash("1.1.1.1", Guid.NewGuid(), DateTime.Now)); }
/// <summary> /// Accesses the instance. /// </summary> public static FRepository Get( CrashRepository Crashes ) { return new FRepository() { _Crashes = Crashes }; }
//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, }; } }
/// <summary> /// The main view of the dash board. /// </summary> /// <returns>A view showing two charts of crashes over time.</returns> public ActionResult Index() { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString(), bCreateNewLog: true)) { DateTime Today = DateTime.UtcNow; DateTime AfewMonthsAgo = Today.AddMonths(-6); FAutoScopedLogTimer LogTimerSQL = new FAutoScopedLogTimer("CrashesFilterByDate", "", ""); // Get engine versions from the last 6 months. var TempVersions = CrashRepository.GetVersions(); List <string> EngineUE4Versions = new List <string>(); foreach (var Version in TempVersions) { if (Version.StartsWith("4.")) { EngineUE4Versions.Add(Version); } } // Only 4 latest version. EngineUE4Versions = EngineUE4Versions.OrderByDescending(item => item).Take(5).ToList(); IQueryable <Crash> CrashesInTimeFrame = _Crashes.ListAll() .Where(MyCrash => MyCrash.TimeOfCrash >= AfewMonthsAgo && MyCrash.TimeOfCrash <= Today.AddDays(1)); //IEnumerable<Crash> Crashes = FRepository.Get().Crashes.FilterByDate( FRepository.Get().Crashes.ListAll(), AfewMonthsAgo, Today ); var VMinimalCrashes = CrashesInTimeFrame.Select(Crash => new { TimeOfCrash = Crash.TimeOfCrash.Value, UserID = Crash.UserNameId.Value, EngineVersion = Crash.BuildVersion, }) .ToList(); List <FCrashMinimal> MinimalCrashes = new List <FCrashMinimal>(VMinimalCrashes.Count); foreach (var Anotype in VMinimalCrashes) { MinimalCrashes.Add(new FCrashMinimal(Anotype.TimeOfCrash, Anotype.UserID, Anotype.EngineVersion)); } LogTimerSQL.Dispose(); HashSet <int> AnonumousIDs = FRepository.Get(_Crashes).GetUserIdsFromUserGroup("Anonymous"); int AnonymousID = AnonumousIDs.First(); int GeneralUserGroupId = FRepository.Get(_Crashes).FindOrAddGroup("General"); int CoderUserGroupId = FRepository.Get(_Crashes).FindOrAddGroup("Coder"); int EngineQAUserGroupId = FRepository.Get(_Crashes).FindOrAddGroup("EngineQA"); int GameQAUserGroupId = FRepository.Get(_Crashes).FindOrAddGroup("GameQA"); // Weekly Dictionary <DateTime, int> WeeklyGeneralResults = GetWeeklyCountsByGroup(MinimalCrashes, GeneralUserGroupId); Dictionary <DateTime, int> WeeklyCoderResults = GetWeeklyCountsByGroup(MinimalCrashes, CoderUserGroupId); Dictionary <DateTime, int> WeeklyEngineQAResults = GetWeeklyCountsByGroup(MinimalCrashes, EngineQAUserGroupId); Dictionary <DateTime, int> WeeklyGameQAResults = GetWeeklyCountsByGroup(MinimalCrashes, GameQAUserGroupId); Dictionary <string, Dictionary <DateTime, int> > WeeklyEngineVersionResults = new Dictionary <string, Dictionary <DateTime, int> >(); foreach (string UE4Version in EngineUE4Versions) { Dictionary <DateTime, int> Results = GetWeeklyCountsByVersion(MinimalCrashes, UE4Version, AnonymousID); WeeklyEngineVersionResults.Add(UE4Version, Results); } Dictionary <DateTime, int> WeeklyAllResults = GetWeeklyCountsByGroup(MinimalCrashes, AllUserGroupId); // Daily Dictionary <DateTime, int> DailyGeneralResults = GetDailyCountsByGroup(MinimalCrashes, GeneralUserGroupId); Dictionary <DateTime, int> DailyCoderResults = GetDailyCountsByGroup(MinimalCrashes, CoderUserGroupId); Dictionary <DateTime, int> DailyEngineQAResults = GetDailyCountsByGroup(MinimalCrashes, EngineQAUserGroupId); Dictionary <DateTime, int> DailyGameQAResults = GetDailyCountsByGroup(MinimalCrashes, GameQAUserGroupId); Dictionary <string, Dictionary <DateTime, int> > DailyEngineVersionResults = new Dictionary <string, Dictionary <DateTime, int> >(); foreach (string UE4Version in EngineUE4Versions) { Dictionary <DateTime, int> Results = GetDailyCountsByVersion(MinimalCrashes, UE4Version, AnonymousID); DailyEngineVersionResults.Add(UE4Version, Results); } Dictionary <DateTime, int> DailyAllResults = GetDailyCountsByGroup(MinimalCrashes, AllUserGroupId); // Get daily buggs stats. List <Bugg> Buggs = _Buggs.ListAll().Where(Bugg => Bugg.TimeOfFirstCrash >= AfewMonthsAgo).ToList(); Dictionary <DateTime, int> BuggDailyAllResults = ( from Bugg in Buggs group Bugg by Bugg.TimeOfFirstCrash.Value.Date into GroupCount orderby GroupCount.Key select new { Count = GroupCount.Count(), Date = GroupCount.Key } ).ToDictionary(x => x.Date, y => y.Count); string CrashesByWeek = ""; foreach (KeyValuePair <DateTime, int> WeeklyResult in WeeklyAllResults) { int GeneralCrashes = 0; WeeklyGeneralResults.TryGetValue(WeeklyResult.Key, out GeneralCrashes); int CoderCrashes = 0; WeeklyCoderResults.TryGetValue(WeeklyResult.Key, out CoderCrashes); int EngineQACrashes = 0; WeeklyEngineQAResults.TryGetValue(WeeklyResult.Key, out EngineQACrashes); int GameQACrashes = 0; WeeklyGameQAResults.TryGetValue(WeeklyResult.Key, out GameQACrashes); string AnonymousLine = ""; foreach (var VersionCrashes in WeeklyEngineVersionResults) { int EngineVersionCrashes = 0; VersionCrashes.Value.TryGetValue(WeeklyResult.Key, out EngineVersionCrashes); AnonymousLine += EngineVersionCrashes; AnonymousLine += ", "; } int Year = WeeklyResult.Key.Year; int Month = WeeklyResult.Key.AddMonths(-1).Month; if (WeeklyResult.Key.Month == 13 || WeeklyResult.Key.Month == 1) { Month = 0; } int Day = WeeklyResult.Key.Day + 6; string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + GeneralCrashes + ", " + CoderCrashes + ", " + EngineQACrashes + ", " + GameQACrashes + ", " + AnonymousLine + WeeklyResult.Value + "], "; CrashesByWeek += Line; } CrashesByWeek = CrashesByWeek.TrimEnd(", ".ToCharArray()); string CrashesByDay = ""; foreach (KeyValuePair <DateTime, int> DailyResult in DailyAllResults) { int GeneralCrashes = 0; DailyGeneralResults.TryGetValue(DailyResult.Key, out GeneralCrashes); int CoderCrashes = 0; DailyCoderResults.TryGetValue(DailyResult.Key, out CoderCrashes); int EngineQACrashes = 0; DailyEngineQAResults.TryGetValue(DailyResult.Key, out EngineQACrashes); int GameQACrashes = 0; DailyGameQAResults.TryGetValue(DailyResult.Key, out GameQACrashes); string AnonymousLine = ""; foreach (var VersionCrashes in DailyEngineVersionResults) { int EngineVersionCrashes = 0; VersionCrashes.Value.TryGetValue(DailyResult.Key, out EngineVersionCrashes); AnonymousLine += EngineVersionCrashes; AnonymousLine += ", "; } int Year = DailyResult.Key.Year; int Month = DailyResult.Key.AddMonths(-1).Month; if (DailyResult.Key.Month == 13 || DailyResult.Key.Month == 1) { Month = 0; } int Day = DailyResult.Key.Day; string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + GeneralCrashes + ", " + CoderCrashes + ", " + EngineQACrashes + ", " + GameQACrashes + ", " + AnonymousLine + DailyResult.Value + "], "; CrashesByDay += Line; } CrashesByDay = CrashesByDay.TrimEnd(", ".ToCharArray()); string BuggsByDay = ""; foreach (KeyValuePair <DateTime, int> DailyResult in BuggDailyAllResults) { int Year = DailyResult.Key.Year; int Month = DailyResult.Key.AddMonths(-1).Month; if (DailyResult.Key.Month == 13 || DailyResult.Key.Month == 1) { Month = 0; } int Day = DailyResult.Key.Day; string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + DailyResult.Value + "], "; BuggsByDay += Line; } BuggsByDay = BuggsByDay.TrimEnd(", ".ToCharArray()); var ResultDashboard = new DashboardViewModel { CrashesByWeek = CrashesByWeek, CrashesByDay = CrashesByDay, BuggsByDay = BuggsByDay, EngineVersions = EngineUE4Versions, }; ResultDashboard.GenerationTime = LogTimer.GetElapsedSeconds().ToString("F2"); return(View("Index", ResultDashboard)); } }
/// <summary> /// Show detailed information about a crash. /// </summary> /// <param name="CrashesForm">A form of user data passed up from the client.</param> /// <param name="id">The unique id of the crash we wish to show the details of.</param> /// <returns>A view to show crash details.</returns> public ActionResult Show( FormCollection CrashesForm, int id ) { using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + id + ")", bCreateNewLog: true ) ) { CrashRepository Crashes = new CrashRepository(); CallStackContainer CurrentCallStack = null; // Update the selected crash based on the form contents Crash CurrentCrash = Crashes.GetCrash( id ); if( CurrentCrash == null ) { return RedirectToAction( "" ); } string FormValue; FormValue = CrashesForm["SetStatus"]; if( !string.IsNullOrEmpty( FormValue ) ) { CurrentCrash.Status = FormValue; } FormValue = CrashesForm["SetFixedIn"]; if( !string.IsNullOrEmpty( FormValue ) ) { CurrentCrash.FixedChangeList = FormValue; } FormValue = CrashesForm["SetTTP"]; if( !string.IsNullOrEmpty( FormValue ) ) { CurrentCrash.Jira = FormValue; } // Valid to set description to an empty string FormValue = CrashesForm["Description"]; if( FormValue != null ) { CurrentCrash.Description = FormValue; } CurrentCallStack = new CallStackContainer( CurrentCrash ); // Set callstack properties CurrentCallStack.bDisplayModuleNames = true; CurrentCallStack.bDisplayFunctionNames = true; CurrentCallStack.bDisplayFileNames = true; CurrentCallStack.bDisplayFilePathNames = true; CurrentCallStack.bDisplayUnformattedCallStack = false; CurrentCrash.CallStackContainer = CurrentCrash.GetCallStack(); // Populate the crash with the correct user data Crashes.PopulateUserInfo( CurrentCrash ); Crashes.SubmitChanges(); var Model = new CrashViewModel { Crash = CurrentCrash, CallStack = CurrentCallStack }; Model.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" ); return View( "Show", Model ); } }
public void Save() { ICrashRepository iCrashRepository = new CrashRepository(this.client, this.database); iCrashRepository.Save(new Crash(this.Application.Id, this.Device.Id, "1.1", Guid.NewGuid(), DateTime.Now)); }
/// <summary> /// Show detailed information about a crash. /// </summary> /// <param name="CrashesForm">A form of user data passed up from the client.</param> /// <param name="id">The unique id of the crash we wish to show the details of.</param> /// <returns>A view to show crash details.</returns> public ActionResult Show(FormCollection CrashesForm, int id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + id + ")", bCreateNewLog: true)) { CrashRepository Crashes = new CrashRepository(); CallStackContainer CurrentCallStack = null; // Update the selected crash based on the form contents Crash CurrentCrash = Crashes.GetCrash(id); if (CurrentCrash == null) { return(RedirectToAction("")); } string FormValue; FormValue = CrashesForm["SetStatus"]; if (!string.IsNullOrEmpty(FormValue)) { CurrentCrash.Status = FormValue; } FormValue = CrashesForm["SetFixedIn"]; if (!string.IsNullOrEmpty(FormValue)) { CurrentCrash.FixedChangeList = FormValue; } FormValue = CrashesForm["SetTTP"]; if (!string.IsNullOrEmpty(FormValue)) { CurrentCrash.Jira = FormValue; } // Valid to set description to an empty string FormValue = CrashesForm["Description"]; if (FormValue != null) { CurrentCrash.Description = FormValue; } CurrentCallStack = new CallStackContainer(CurrentCrash); // Set callstack properties CurrentCallStack.bDisplayModuleNames = true; CurrentCallStack.bDisplayFunctionNames = true; CurrentCallStack.bDisplayFileNames = true; CurrentCallStack.bDisplayFilePathNames = true; CurrentCallStack.bDisplayUnformattedCallStack = false; CurrentCrash.CallStackContainer = CurrentCrash.GetCallStack(); // Populate the crash with the correct user data Crashes.PopulateUserInfo(CurrentCrash); Crashes.SubmitChanges(); var Model = new CrashViewModel { Crash = CurrentCrash, CallStack = CurrentCallStack }; Model.GenerationTime = LogTimer.GetElapsedSeconds().ToString("F2"); return(View("Show", Model)); } }
/// <summary> /// The main view of the dash board. /// </summary> /// <returns>A view showing two charts of crashes over time.</returns> public ActionResult Index() { CrashRepository LocalCrashRepository = new CrashRepository(); IQueryable <Crash> Crashes = LocalCrashRepository.ListAll(); int UndefinedUserGroupId = LocalCrashRepository.FindOrAddUserGroup("Undefined"); int GeneralUserGroupId = LocalCrashRepository.FindOrAddUserGroup("General"); int CoderUserGroupId = LocalCrashRepository.FindOrAddUserGroup("Coder"); int EngineQAUserGroupId = LocalCrashRepository.FindOrAddUserGroup("EngineQA"); int GameQAUserGroupId = LocalCrashRepository.FindOrAddUserGroup("GameQA"); int AutomatedUserGroupId = LocalCrashRepository.FindOrAddUserGroup("Automated"); Dictionary <DateTime, int> GeneralResults = LocalCrashRepository.GetWeeklyCountsByGroup(Crashes, GeneralUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> CoderResults = LocalCrashRepository.GetWeeklyCountsByGroup(Crashes, CoderUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> EngineQAResults = LocalCrashRepository.GetWeeklyCountsByGroup(Crashes, EngineQAUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> GameQAResults = LocalCrashRepository.GetWeeklyCountsByGroup(Crashes, GameQAUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> AutomatedResults = LocalCrashRepository.GetWeeklyCountsByGroup(Crashes, AutomatedUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> AllResults = LocalCrashRepository.GetWeeklyCountsByGroup(Crashes, -1, UndefinedUserGroupId); Dictionary <DateTime, int> DailyGeneralResults = LocalCrashRepository.GetDailyCountsByGroup(Crashes, GeneralUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> DailyCoderResults = LocalCrashRepository.GetDailyCountsByGroup(Crashes, CoderUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> DailyEngineQAResults = LocalCrashRepository.GetDailyCountsByGroup(Crashes, EngineQAUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> DailyGameQAResults = LocalCrashRepository.GetDailyCountsByGroup(Crashes, GameQAUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> DailyAutomatedResults = LocalCrashRepository.GetDailyCountsByGroup(Crashes, AutomatedUserGroupId, UndefinedUserGroupId); Dictionary <DateTime, int> DailyAllResults = LocalCrashRepository.GetDailyCountsByGroup(Crashes, -1, UndefinedUserGroupId); string CrashesByWeek = ""; foreach (KeyValuePair <DateTime, int> Result in AllResults) { int GeneralCrashes = 0; try { GeneralCrashes = GeneralResults[Result.Key]; } catch { } int CoderCrashes = 0; try { CoderCrashes = CoderResults[Result.Key]; } catch { } int EngineQACrashes = 0; try { EngineQACrashes = EngineQAResults[Result.Key]; } catch { } int GameQACrashes = 0; try { GameQACrashes = GameQAResults[Result.Key]; } catch { } int AutomatedCrashes = 0; try { AutomatedCrashes = AutomatedResults[Result.Key]; } catch { } int Year = Result.Key.Year; int Month = Result.Key.AddMonths(-1).Month; if (Result.Key.Month == 13 || Result.Key.Month == 1) { Month = 0; } int Day = Result.Key.Day + 6; string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + GeneralCrashes + ", " + CoderCrashes + ", " + EngineQACrashes + ", " + GameQACrashes + ", " + AutomatedCrashes + ", " + Result.Value + "], "; CrashesByWeek = CrashesByWeek + Line; } CrashesByWeek = CrashesByWeek.TrimEnd(", ".ToCharArray()); string CrashesByDay = ""; foreach (KeyValuePair <DateTime, int> DailyResult in DailyAllResults) { int GeneralCrashes = 0; try { GeneralCrashes = DailyGeneralResults[DailyResult.Key]; } catch { } int CoderCrashes = 0; try { CoderCrashes = DailyCoderResults[DailyResult.Key]; } catch { } int EngineQACrashes = 0; try { EngineQACrashes = DailyEngineQAResults[DailyResult.Key]; } catch { } int GameQACrashes = 0; try { GameQACrashes = DailyGameQAResults[DailyResult.Key]; } catch { } int AutomatedCrashes = 0; try { AutomatedCrashes = DailyAutomatedResults[DailyResult.Key]; } catch { } int Year = DailyResult.Key.Year; int Month = DailyResult.Key.AddMonths(-1).Month; if (DailyResult.Key.Month == 13 || DailyResult.Key.Month == 1) { Month = 0; } int Day = DailyResult.Key.Day; string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + GeneralCrashes + ", " + CoderCrashes + ", " + EngineQACrashes + ", " + GameQACrashes + ", " + AutomatedCrashes + ", " + DailyResult.Value + "], "; CrashesByDay = CrashesByDay + Line; } CrashesByDay = CrashesByDay.TrimEnd(", ".ToCharArray()); return(View("Index", new DashboardViewModel { CrashesByWeek = CrashesByWeek, CrashesByDay = CrashesByDay })); }
/// <summary> /// Link the Http context cache to a crash repository. /// </summary> /// <param name="InCache">The current Http context cache.</param> /// <param name="InCrashRepository">The repository to associate the cache with.</param> public CachedDataService( Cache InCache, CrashRepository InCrashRepository ) { CacheInstance = InCache; Crashes = InCrashRepository; }
/// <summary> /// Gets a formatted callstack for the crash. /// </summary> /// <returns>A formatted callstack.</returns> public CallStackContainer GetCallStack() { CrashRepository LocalCrashRepository = new CrashRepository(); return LocalCrashRepository.GetCallStack( this ); }
public CrashController(CrashRepository repo) { _crashRepo = repo; }
public void Save() { ICrashRepository iCrashRepository = new CrashRepository(this.connectionString); iCrashRepository.Save(this.Application.Id, this.Device.Id, new Crash("1.1", Guid.NewGuid(), DateTime.Now)); }
/// <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? // 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(); HashSet <string> UserNamesForUserGroup = FRepository.Get(BuggsRepo).GetUserNamesFromGroupName(AnonumousGroup); //FormData.DateFrom = DateTime.Now.AddDays( -1 ); var Crashes = CrashRepo .FilterByDate(CrashRepo.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays(1)) // 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.TTPID, Platform = Crash.PlatformName, FixCL = Crash.FixedChangeList, BuiltFromCL = Crash.ChangeListVersion, Pattern = Crash.Pattern, MachineID = Crash.ComputerName, 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(); // The 100 top. var PatternAndCount = PatternToCountOrdered.Take(100).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>(100); 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.TTPID)) { int TTPID = 0; int.TryParse(NewBugg.TTPID, 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); // Grab the data form JIRA. string JiraSearchQuery = string.Join(" OR ", FoundJiras); using (FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer("JiraResults")) { 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; 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.TTPID))) { 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.NumberOfCrashes).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 }); } }
/// <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 + ")" ) ) { if( GenericFunctionCalls == null ) { CrashRepository CrashRepo = new CrashRepository(); var Crash = ( from BuggCrash in CrashRepo.Context.Buggs_Crashes where BuggCrash.BuggId == Id select BuggCrash.Crash ).FirstOrDefault(); if( Crash != null ) { GenericFunctionCalls = Crash.GetCallStack().GetFunctionCalls(); } else { GenericFunctionCalls = new List<string>(); } } return GenericFunctionCalls; } }
/// <summary> /// Accesses the instance. /// </summary> public static FRepository Get( CrashRepository Crashes, BuggRepository Buggs ) { return new FRepository() { _Crashes = Crashes, _Buggs = Buggs }; }
/// <summary> /// /// </summary> /// <returns></returns> public List<Crash> GetCrashes() { CrashRepository CrashRepo = new CrashRepository(); var CrashList = ( from BuggCrash in CrashRepo.Context.Buggs_Crashes where BuggCrash.BuggId == Id select BuggCrash.Crash ).AsEnumerable().ToList(); return CrashList; }
/// <summary> /// /// </summary> /// <returns></returns> public List<Crash> GetCrashes() { using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) ) { CrashRepository CrashRepo = new CrashRepository(); var CrashList = ( from BuggCrash in CrashRepo.Context.Buggs_Crashes where BuggCrash.BuggId == Id && BuggCrash.Crash.TimeOfCrash > DateTime.UtcNow.AddMonths(-6) select BuggCrash.Crash ).OrderByDescending( c => c.TimeOfCrash ).ToList(); return CrashList; } }
//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, }); } }