// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. using System; using System.Net; using System.IO; using System.Diagnostics; using System.Collections.Generic; namespace AutoReporter { class UploadReportFiles { string StripPath(string PathName) { int LastBackSlashIndex = PathName.LastIndexOf("\\"); int LastForwardSlashIndex = PathName.LastIndexOf("/"); if (LastBackSlashIndex > LastForwardSlashIndex && LastBackSlashIndex >= 0) { return PathName.Substring(LastBackSlashIndex + 1); } else if (LastForwardSlashIndex >= 0) { return PathName.Substring(LastForwardSlashIndex + 1); } return PathName; } public bool CanAccessFile(string ProcessName, bool bWasAnEnsure, Int32 InProcessID, string Filename, OutputLogFile LogFile) { LogFile.WriteLine("Checking to see if " + Filename + " is Accessible"); bool bWasSuccessful = true; string CheckTempFilename = Filename + "_AutoReportCheck.bak"; FileInfo CheckTempFileInfo = new FileInfo(CheckTempFilename); if (CheckTempFileInfo.Exists) { // Delete any potentially old files laying around CheckTempFileInfo.IsReadOnly = false; CheckTempFileInfo.Delete(); } FileInfo SourceFileInfo = new FileInfo(Filename); if(SourceFileInfo.Exists) { Int32 CopyCount = 0; Int64 CopySize = 0; while ((CopySize == 0) && (CopyCount < 10)) { try { File.Copy(Filename, CheckTempFilename, true); } catch (Exception e) { LogFile.WriteLine(e.Message); LogFile.WriteLine("Couldn't copy file " + Filename + " to " + CheckTempFilename + ", continuing..."); } CheckTempFileInfo = new FileInfo(CheckTempFilename); if(CheckTempFileInfo.Exists) { try { CopySize = CheckTempFileInfo.Length; } catch (IOException) { LogFile.WriteLine("Could not Access file: " + CheckTempFilename + " to get it's size."); } } CopyCount++; if (CopySize == 0) { // Sleep for a bit before trying again System.Threading.Thread.Sleep(30); } } LogFile.WriteLine("Temp file file of " + CopySize + " bytes saved in " + CopyCount + " tries to " + CheckTempFilename + "."); if (CopySize == 0) { LogFile.WriteLine("*** Failed to copy file file: " + CheckTempFilename); // Find any of these processes and log out the results. // This is to assist in determining possible fixes for the 'missing crash log' cases. if (bWasAnEnsure == false) { LogFile.WriteLine("Looking for the process " + ProcessName + "..."); // Kill the process so we can get the log file... Process[] processList = Process.GetProcesses(); List potentialProcesses = new List(); foreach (Process CheckProcess in processList) { LogFile.WriteLine("\t" + CheckProcess.ProcessName); if (CheckProcess.ProcessName == ProcessName) { potentialProcesses.Add(CheckProcess); } } LogFile.WriteLine("Found " + potentialProcesses.Count + " apps..."); foreach (Process foundProcess in potentialProcesses) { bool bKillIt = false; try { LogFile.WriteLine("*** " + foundProcess.Id.ToString()); if (foundProcess.HasExited == false) { LogFile.WriteLine("\tHandle " + foundProcess.Handle.ToString()); LogFile.WriteLine("\tWorkingDir " + foundProcess.StartInfo.WorkingDirectory); // If the app is not responding, it is likely our crashed app... // We could potentially kill it to allow for the log to be uploaded. LogFile.WriteLine("\tResponding " + foundProcess.Responding.ToString()); bKillIt = !foundProcess.Responding; } else { LogFile.WriteLine("\tEXITED!"); } // Only kill it if it matches the process Id passed in! bKillIt &= (foundProcess.Id == InProcessID); } catch (System.Exception /*ex*/) { // Process my have exited by now... } if (bKillIt) { LogFile.WriteLine("Killing process to ensure log file upload: " + foundProcess.Id.ToString() + " " + foundProcess.ProcessName); foundProcess.Kill(); foundProcess.WaitForExit(); // See if killing the thread worked try { File.Copy(Filename, CheckTempFilename, true); bWasSuccessful = true; } catch (Exception e) { LogFile.WriteLine(e.Message); LogFile.WriteLine("Couldn't copy log " + Filename + " to " + CheckTempFilename + ", continuing..."); bWasSuccessful = false; } // Temporary - trying to determine how some people are uploading empty log files... { FileInfo TempInfo = new FileInfo(CheckTempFilename); if (TempInfo.Exists) { LogFile.WriteLine("----------"); try { LogFile.WriteLine("TempFile: Size = " + TempInfo.Length + " for " + CheckTempFilename); } catch (IOException) { LogFile.WriteLine("Could not Access file: " + CheckTempFilename + " to get it's size."); } LogFile.WriteLine("----------"); } else { LogFile.WriteLine("TempLog: Does not exist!"); } } } } } } } else { LogFile.WriteLine("File: " + Filename + " does not exist."); bWasSuccessful = false; } return bWasSuccessful; } public bool UploadFile(string HeaderName, string FileNameTemplate, string Filename, OutputLogFile LogFile, WebClient Client) { //If debugging use local server #if DEBUG string UploadReportURL = Properties.Settings.Default.UploadURL_Debug; #else string UploadReportURL = Properties.Settings.Default.UploadURL; #endif byte[] responseArray; bool bWasSuccessful = false; if (Client == null) { LogFile.WriteLine("Null WebClient Passed to UploadFile."); return false; } if (Client.IsBusy) { LogFile.WriteLine("Client is Busy"); } // Must add Header for the web service to know what to do with the file Client.Headers.Add(HeaderName, FileNameTemplate); var CheckFileInfo = new FileInfo(Filename); long FileSize = 0; if(CheckFileInfo.Exists) { try { FileSize = CheckFileInfo.Length; } catch (IOException) { LogFile.WriteLine("Could not Access file: " + Filename +" to get it's size."); bWasSuccessful = false; } } if (FileSize > 0) { LogFile.WriteLine("Attempting to upload File: " + Filename + " of size:" + FileSize/1024/1024 + "MB to " + UploadReportURL); try { if(UploadReportURL != null && Filename != null) { responseArray = Client.UploadFile(UploadReportURL, "POST", Filename); bWasSuccessful = true; LogFile.WriteLine("Successfully to uploaded file to: " + UploadReportURL); } else { bWasSuccessful = false; LogFile.WriteLine("UploadReportURL or Filename were NULL"); } } catch(NullReferenceException nrE) { bWasSuccessful = false; LogFile.WriteLine("Upload File : "+Filename+"Caused a Null Reference exception" + nrE.Message); } catch (FileNotFoundException fnfE) { bWasSuccessful = false; LogFile.WriteLine("Could Not Find file: " + fnfE.FileName); } catch (WebException ex) { bWasSuccessful = false; WebException webEx = (WebException) ex; LogFile.WriteLine("-------"); LogFile.WriteLine("Response: " + webEx.Response.ToString()); LogFile.WriteLine("Status: " + webEx.Status.ToString()); LogFile.WriteLine("Message: " + webEx.Message); if(webEx.InnerException != null) { LogFile.WriteLine("InnerException: " + webEx.InnerException.Message); } LogFile.WriteLine("-------"); } catch (Exception e) { bWasSuccessful = false; LogFile.WriteLine("Couldn't upload due to Unknown Exception: " + e.Message); } } else { LogFile.WriteLine("Could Not upload file because"+ Filename + " was 0 bytes. Likely because it has been overwritten or cleared between testing the filesize and uploading it."); } // Remove the header so that the next upload call starts afresh Client.Headers.Remove(HeaderName); return bWasSuccessful; } /** * UploadFiles - uploads the two files using HTTP POST * * @param LogFilename - the local log file * @param IniFilename - the local ini file * @param uniqueID - the id of the crash report associated with these files. * @return bool - true if successful */ public bool UploadFiles(string ProcessName, bool bWasAnEnsure, Int32 InProcessID, string LogFilename, string IniFilename, string MiniDumpFilename, string CrashVideoFilename, int uniqueID, OutputLogFile logFile) { logFile.WriteLine("Uploading files..."); logFile.WriteLine("\t" + LogFilename); logFile.WriteLine("\t" + IniFilename); logFile.WriteLine("\t" + MiniDumpFilename); logFile.WriteLine("\t" + CrashVideoFilename); Boolean bWasSuccessful = false; Boolean bUploadedLog = true; Boolean bUploadedVideo = true; Boolean bUploadedMiniDump = true; Boolean bCanAccessLog; Boolean bCanAccessVideo; Boolean bCanAccessMiniDump; bCanAccessLog = CanAccessFile(ProcessName, bWasAnEnsure, InProcessID, LogFilename, logFile); bCanAccessVideo = CanAccessFile(ProcessName, bWasAnEnsure, InProcessID, CrashVideoFilename, logFile); bCanAccessMiniDump = CanAccessFile(ProcessName, bWasAnEnsure, InProcessID, MiniDumpFilename, logFile); WebClient client = new WebClient(); // Send the Crash Id up so that the uploader can name the files correctly. // This used to save crash files to their own unique folder, but that method has been replaced with appending _ to the filename. client.Headers.Add("NewFolderName", uniqueID.ToString()); if(bCanAccessLog) { try { bUploadedLog = UploadFile("LogName", StripPath(LogFilename), LogFilename, logFile, client); } catch (NullReferenceException nrE) { bUploadedLog = false; logFile.WriteLine("Uploading "+ LogFilename+ " caused Null Reference Exception: "+nrE.Message); } } else { bUploadedLog = false; logFile.WriteLine("Could not access File: " + LogFilename); } // Upload Crash Video if(bCanAccessVideo) { try { bUploadedVideo = UploadFile("SaveFileName", "CrashVideo.avi", CrashVideoFilename, logFile, client); } catch (NullReferenceException nrE) { logFile.WriteLine("Uploading "+ CrashVideoFilename+ " caused Null Reference Exception: "+nrE.Message); } if(!bUploadedVideo) { string NetworkPath = @"\\devweb-02\ReportVideos\"; try { // Try copying over the network // \\devweb-02\ReportVideos if(!String.IsNullOrEmpty(CrashVideoFilename) ) { logFile.WriteLine("Attempting to copy file " + CrashVideoFilename + " over the network to " +NetworkPath ); File.Copy(CrashVideoFilename, NetworkPath + uniqueID.ToString()+ "_"+StripPath(CrashVideoFilename)); bUploadedVideo = true; } else { logFile.WriteLine("Argument Null or Empty"); } } catch(Exception e) { logFile.WriteLine(e.ToString()); logFile.WriteLine("Couldn't copy crash video to network..."); try { File.Copy(CrashVideoFilename, CrashVideoFilename+"_" + uniqueID.ToString(), true); } catch (Exception copyFileException) { logFile.WriteLine(copyFileException.Message); logFile.WriteLine("Couldn't copy File " + CrashVideoFilename + ", continuing..."); } throw new Exception("Failed to upload Crash Video to " + NetworkPath + uniqueID.ToString() + "_" + StripPath(CrashVideoFilename) + "after a web and a network copy attempts"); } } } else { bUploadedVideo = false; var CheckFileInfo = new FileInfo(CrashVideoFilename); if (CheckFileInfo.Exists) { logFile.WriteLine("Could not access File: " + CrashVideoFilename); } else { logFile.WriteLine("File: " + CrashVideoFilename+" does not exist."); } } // Upload Minidump if (bCanAccessMiniDump) { try { bUploadedMiniDump = UploadFile("SaveFileName", "MiniDump.dmp", MiniDumpFilename, logFile, client); } catch (NullReferenceException nrE) { bUploadedMiniDump = false; logFile.WriteLine("Uploading "+ MiniDumpFilename+ " caused Null Reference Exception: "+nrE.Message); } } else { bUploadedMiniDump = false; logFile.WriteLine("Could not access File: " + LogFilename); } //Upload file successes try { ReportService.RegisterReport reportService = new ReportService.RegisterReport(); try { bWasSuccessful = reportService.AddCrashFiles(uniqueID, bUploadedLog, bUploadedMiniDump, bUploadedVideo); } catch (Exception e) { throw e; } } catch (WebException webEx) { logFile.WriteLine(webEx.Message); logFile.WriteLine(webEx.InnerException.Message); bWasSuccessful = false; } // Temporary - write out log file contents to autoreporter log logFile.WriteLine(""); logFile.WriteLine("----------"); logFile.WriteLine("Log file: " + LogFilename); logFile.WriteLine("----------"); Int32 FailCount = 0; bool bWroteLogFile = false; bool bFileExists = false; Int64 FileSize = 0; while ((FailCount < 10) && !bWroteLogFile) { FileInfo RealLogInfo = new FileInfo(LogFilename); bFileExists |= RealLogInfo.Exists; if(bFileExists) { try { FileSize = System.Math.Max(FileSize, RealLogInfo.Length); } catch (IOException) { logFile.WriteLine("Could not Access file: " + LogFilename + " to get it's size."); } } if (RealLogInfo.Exists && (FileSize > 0)) { using (StreamReader sr = RealLogInfo.OpenText()) { while (sr.Peek() > 0) { logFile.WriteLine(sr.ReadLine()); } } logFile.WriteLine("----------"); bWroteLogFile = true; } else { FailCount++; // Sleep for a second before trying again System.Threading.Thread.Sleep(1000); } } if (bWroteLogFile == false) { logFile.WriteLine("Attempted to write log file to autoreport log failed."); logFile.WriteLine("\tFile does " + (bFileExists ? "" : "NOT") + " Exist"); logFile.WriteLine("\tFile size = " + FileSize); } return bWasSuccessful; } } }