// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web.Mvc;
using Tools.CrashReporter.CrashReportWebSite.DataModels;
using Tools.CrashReporter.CrashReportWebSite.DataModels.Repositories;
using Tools.CrashReporter.CrashReportWebSite.Models;
namespace Tools.CrashReporter.CrashReportWebSite.Controllers
{
///
///
///
public struct FCrashMinimal
{
///
///
///
public readonly DateTime TimeOfCrash;
///
///
///
public readonly int UserId;
///
///
///
public readonly string EngineVersion;
///
///
///
///
///
///
public FCrashMinimal( DateTime InTimeOfCrash, int InUserId, string InEngineVersion )
{
TimeOfCrash = InTimeOfCrash;
UserId = InUserId;
EngineVersion = InEngineVersion;
}
}
///
/// The controller to handle graphing of Crashes per user group over time.
///
public class DashboardController : Controller
{
/// Fake id for all user groups
public static readonly int AllUserGroupId = -1;
//
CrashReportEntities _entities = new CrashReportEntities();
private CrashRepository _Crashes;
private BuggRepository _Buggs;
public DashboardController()
{
//Hideous temporary code
//no! Unity! Dependency injection! Single Context wrapper!
_Crashes = new CrashRepository(_entities);
_Buggs = new BuggRepository(_entities);
}
///
/// Return a dictionary of Crashes per group grouped by week.
///
/// A set of Crashes to interrogate.
/// The id of the user group to interrogate.
/// A dictionary of week vs. Crash count.
public Dictionary GetWeeklyCountsByGroup( List Crashes, int UserGroupId )
{
using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(UserGroupId=" + UserGroupId + ")" ) )
{
Dictionary Results = new Dictionary();
var UsersIds = new HashSet(_entities.Users.Distinct().Select(data => data.Id));
// Trim Crashes to user group.
if( UserGroupId != DashboardController.AllUserGroupId )
{
Crashes = Crashes.Where( Crash => UsersIds.Contains( Crash.UserId ) ).ToList();
}
try
{
Results =
(
from CrashDetail in Crashes
group CrashDetail by CrashDetail.TimeOfCrash.AddDays( -(int)CrashDetail.TimeOfCrash.DayOfWeek ).Date into GroupCount
orderby GroupCount.Key
select new { Count = GroupCount.Count(), Date = GroupCount.Key }
).ToDictionary( x => x.Date, y => y.Count );
}
catch( Exception Ex )
{
Debug.WriteLine( "Exception in GetWeeklyCountsByGroup: " + Ex.ToString() );
}
return Results;
}
}
///
/// Return a dictionary of Crashes per version grouped by week.
///
/// A set of Crashes to interrogate.
/// Engine version
/// Anonymous id
/// A dictionary of week vs. Crash count.
public Dictionary GetWeeklyCountsByVersion( List Crashes, string EngineVersion, int AnonymousID )
{
using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(EngineVersion=" + EngineVersion + ")" ))
{
Dictionary Results = new Dictionary();
Crashes = Crashes
.Where( Crash => Crash.UserId == AnonymousID )
.Where( Crash => Crash.EngineVersion.Contains( EngineVersion ) )
.ToList();
try
{
Results =
(
from CrashDetail in Crashes
group CrashDetail by CrashDetail.TimeOfCrash.AddDays( -(int)CrashDetail.TimeOfCrash.DayOfWeek ).Date into VersionCount
orderby VersionCount.Key
select new { Count = VersionCount.Count(), Date = VersionCount.Key }
).ToDictionary( x => x.Date, y => y.Count );
}
catch (Exception Ex)
{
Debug.WriteLine( "Exception in GeWeeklyCountsByVersion: " + Ex.ToString() );
}
return Results;
}
}
///
/// Return a dictionary of Crashes per group grouped by day.
///
/// A set of Crashes to interrogate.
/// The id of the user group to interrogate.
/// A dictionary of day vs. Crash count.
public Dictionary GetDailyCountsByGroup( List Crashes, int UserGroupId )
{
using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(UserGroupId=" + UserGroupId + ")" ) )
{
Dictionary Results = new Dictionary();
var UsersIds = _entities.UserGroups.First(data => data.Id == UserGroupId ).Users.Select(data => data.Id);
// Trim Crashes to user group.
if( UserGroupId != DashboardController.AllUserGroupId )
{
Crashes = Crashes.Where( Crash => UsersIds.Contains( Crash.UserId ) ).ToList();
}
try
{
Results =
(
from CrashDetail in Crashes
group CrashDetail by CrashDetail.TimeOfCrash.Date into GroupCount
orderby GroupCount.Key
select new { Count = GroupCount.Count(), Date = GroupCount.Key }
).ToDictionary( x => x.Date, y => y.Count );
}
catch( Exception Ex )
{
Debug.WriteLine( "Exception in GetDailyCountsByGroup: " + Ex.ToString() );
}
return Results;
}
}
///
/// Return a dictionary of Crashes per version grouped by day.
///
/// A set of Crashes to interrogate.
/// Engine version
/// Anonymous id
/// A dictionary of day vs. Crash count.
public Dictionary GetDailyCountsByVersion( List Crashes, string EngineVersion, int AnonymousID )
{
using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(EngineVersion=" + EngineVersion + ")" ))
{
Dictionary Results = new Dictionary();
Crashes = Crashes
.Where( Crash => Crash.UserId == AnonymousID )
.Where( Crash => Crash.EngineVersion.Contains( EngineVersion ) )
.ToList();
try
{
Results =
(
from CrashDetail in Crashes
group CrashDetail by CrashDetail.TimeOfCrash.Date into VersionCount
orderby VersionCount.Key
select new { Count = VersionCount.Count(), Date = VersionCount.Key }
).ToDictionary( x => x.Date, y => y.Count );
}
catch (Exception Ex)
{
Debug.WriteLine( "Exception in GetDailyCountsByVersion: " + Ex.ToString() );
}
return Results;
}
}
///
/// The main view of the dash board.
///
/// A view showing two charts of Crashes over time.
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 = _Crashes.GetVersions();
List EngineUE4Versions = new List();
foreach (var Version in TempVersions)
{
if( Version.StartsWith("4.") )
{
EngineUE4Versions.Add( Version );
}
}
// Only 4 latest version.
EngineUE4Versions = EngineUE4Versions.OrderByDescending( item => item ).Take( 5 ).ToList();
var endDate = Today.AddDays(1);
IQueryable CrashesInTimeFrame = _Crashes.ListAll()
.Where(MyCrash => MyCrash.TimeOfCrash >= AfewMonthsAgo && MyCrash.TimeOfCrash <= endDate);
//IEnumerable Crashes = FRepository.Get().Crashes.FilterByDate( FRepository.Get().Crashes.ListAll(), AfewMonthsAgo, Today );
var VMinimalCrashes = CrashesInTimeFrame.Select( Crash => new
{
TimeOfCrash = Crash.TimeOfCrash,
UserID = Crash.UserId,
EngineVersion = Crash.BuildVersion,
} )
.ToList();
List MinimalCrashes = new List( VMinimalCrashes.Count );
foreach( var Anotype in VMinimalCrashes )
{
MinimalCrashes.Add( new FCrashMinimal( Anotype.TimeOfCrash, Anotype.UserID, Anotype.EngineVersion ) );
}
LogTimerSQL.Dispose();
HashSet AnonumousIDs = new HashSet(_entities.UserGroups.First(data => data.Name == "Anonymous").Users.Select(data => data.Id));
int AnonymousID = AnonumousIDs.First();
int GeneralUserGroupId = 1;//FRepository.Get( _Crashes ).FindOrAddGroup( "General" );
int CoderUserGroupId = 3;//FRepository.Get( _Crashes ).FindOrAddGroup( "Coder" );
int EngineQAUserGroupId = 22;//FRepository.Get( _Crashes ).FindOrAddGroup( "EngineQA" );
int GameQAUserGroupId = 21;//FRepository.Get( _Crashes ).FindOrAddGroup( "GameQA" );
// Weekly
Dictionary WeeklyGeneralResults = GetWeeklyCountsByGroup( MinimalCrashes, GeneralUserGroupId );
Dictionary WeeklyCoderResults = GetWeeklyCountsByGroup( MinimalCrashes, CoderUserGroupId );
Dictionary WeeklyEngineQAResults = GetWeeklyCountsByGroup( MinimalCrashes, EngineQAUserGroupId );
Dictionary WeeklyGameQAResults = GetWeeklyCountsByGroup( MinimalCrashes, GameQAUserGroupId );
Dictionary> WeeklyEngineVersionResults = new Dictionary>();
foreach (string UE4Version in EngineUE4Versions)
{
Dictionary Results = GetWeeklyCountsByVersion( MinimalCrashes, UE4Version, AnonymousID );
WeeklyEngineVersionResults.Add( UE4Version, Results );
}
Dictionary WeeklyAllResults = GetWeeklyCountsByGroup( MinimalCrashes, AllUserGroupId );
// Daily
Dictionary DailyGeneralResults = GetDailyCountsByGroup( MinimalCrashes, GeneralUserGroupId );
Dictionary DailyCoderResults = GetDailyCountsByGroup( MinimalCrashes, CoderUserGroupId );
Dictionary DailyEngineQAResults = GetDailyCountsByGroup( MinimalCrashes, EngineQAUserGroupId );
Dictionary DailyGameQAResults = GetDailyCountsByGroup( MinimalCrashes, GameQAUserGroupId );
Dictionary> DailyEngineVersionResults = new Dictionary>();
foreach(string UE4Version in EngineUE4Versions)
{
Dictionary Results = GetDailyCountsByVersion( MinimalCrashes, UE4Version, AnonymousID );
DailyEngineVersionResults.Add( UE4Version, Results );
}
Dictionary DailyAllResults = GetDailyCountsByGroup( MinimalCrashes, AllUserGroupId );
// Get daily buggs stats.
List Buggs = _Buggs.ListAll().Where( Bugg => Bugg.TimeOfFirstCrash >= AfewMonthsAgo ).ToList();
Dictionary 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 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 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 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 );
}
}
}
}