// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Text;
using System.Web.Mvc;
using System.Xml;
using Tools.CrashReporter.CrashReportWebSite.Models;
using Tools.CrashReporter.CrashReportWebSite.Properties;
using Tools.DotNETCommon;
namespace Tools.CrashReporter.CrashReportWebSite.Controllers
{
// Each time the controller is run, create a new CSV file in the specified folder and add the link and the top of the site,
// so it could be easily downloaded
// Removed files older that 7 days
/*
GameName
TimeOfCrash
BuiltFromCL
PlatformName
EngineMode
MachineId
Module
BuildVersion
Jira
Branch
CrashType
EpicId
BuggId
*/
/// CSV data row.
public class FCSVRow
{
/// GameName.
public string GameName;
/// TimeOfCrash.
public DateTime TimeOfCrash;
/// BuiltFromCL.
public string BuiltFromCL;
/// PlatformName.
public string PlatformName;
/// EngineMode.
public string EngineMode;
/// MachineId.
public string MachineId;
/// Module.
public string Module;
/// BuildVersion.
public string BuildVersion;
/// Jira.
public string Jira;
/// Branch.
public string Branch;
/// CrashType.
public short CrashType;
/// EpicId.
public string EpicId;
/// BuggId.
public int BuggId;
/// Returns crash type as a string.
public string GetCrashTypeAsString()
{
if (CrashType == 1)
{
return "Crash";
}
else if (CrashType == 2)
{
return "Assert";
}
else if (CrashType == 3)
{
return "Ensure";
}
return "Unknown";
}
}
///
/// The controller to handle graphing of crashes per user group over time.
///
public class CSVController : Controller
{
/// Fake id for all user groups
public static readonly int AllUserGroupId = -1;
//static readonly int MinNumberOfCrashes = 2;
///
/// Retrieve all Buggs matching the search criteria.
///
/// The incoming form of search criteria from the client.
/// A view to display the filtered Buggs.
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 Users = FRepository.Get().GetUserNamesFromGroupName( AnonumousGroup );
int AnonymousGroupID = FRepository.Get( BuggsRepo ).FindOrAddGroup( AnonymousGroup );
HashSet AnonumousIDs = FRepository.Get( BuggsRepo ).GetUserIdsFromUserGroup( AnonymousGroup );
int AnonymousID = AnonumousIDs.First();
HashSet 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 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,
};
}
}
///
///
///
///
public ActionResult Index( FormCollection Form )
{
using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ) )
{
FormHelper FormData = new FormHelper( Request, Form, "JustReport" );
CSV_ViewModel Results = GetResults( FormData );
Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
return View( "Index", Results );
}
}
}
}