// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.ServiceProcess; using System.Text; using System.Threading.Tasks; using Tools.CrashReporter.CrashReportCommon; using Tools.CrashReporter.CrashReportProcess.Properties; namespace Tools.CrashReporter.CrashReportProcess { /// /// A class to handle processing received crash reports for displaying on the website. /// partial class CrashReporterProcessServicer : ServiceBase { /// A class the handle detection of new reports. public ReportWatcher Watcher = null; /// A class to lazily process reports as they are detected. public readonly List Processors = new List(); /// Current log file to write debug progress info to public static LogWriter Log = null; private static SlackWriter Slack = null; public static StatusReporting StatusReporter = null; /// Folder in which to store log files static private string LogFolder = null; /// /// Write a status update to the event log. /// static public void WriteEvent( string Message ) { if( Message != null && Message.Length > 2 ) { Log.Print( "[STATUS] " + Message ); } } /// /// Write a status update to the event log, from the MinidumpDiagnostics. /// static public void WriteMDD( string Message ) { if( Message != null && Message.Length > 2 ) { Log.Print( "[MDD ] " + Message ); } } /// /// Write a status update to the event log, from the P4. /// static public void WriteP4( string Message ) { if( Message != null && Message.Length > 2 ) { Log.Print( "[P4 ] " + Message ); } } /// /// Write a failure to the event log. /// static public void WriteFailure( string Message ) { if( Message != null && Message.Length > 2 ) { Log.Print( "[FAILED] " + Message ); } } /// /// Write an exception message to the event log. /// static public void WriteException( string Message ) { if( Message != null && Message.Length > 2 ) { Log.Print( "[EXCEPT] " + Message ); StatusReporter.IncrementCount(StatusReportingEventNames.ExceptionEvent); } } /// /// Write to Slack. /// static public void WriteSlack(string Message) { if (Message != null && Message.Length > 0) { Slack.Write(Message); } } /// /// Initialise all the components, and create an event log. /// public CrashReporterProcessServicer() { InitializeComponent(); var StartupPath = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location ); LogFolder = Path.Combine( StartupPath, "Logs" ); } /// /// Start the service, and stop the service if there were any errors found. /// /// Command line arguments (unused). protected override void OnStart( string[] Arguments ) { // Create a log file for any start-up messages Log = new LogWriter("CrashReportProcess", LogFolder); Config.LoadConfig(); Slack = new SlackWriter { WebhookUrl = Config.Default.SlackWebhookUrl, Channel = Config.Default.SlackChannel, Username = Config.Default.SlackUsername, IconEmoji = Config.Default.SlackEmoji }; StatusReporter = new StatusReporting(); // Add directory watchers Watcher = new ReportWatcher(); for (int ProcessorIndex = 0; ProcessorIndex < Config.Default.ProcessorThreadCount; ProcessorIndex++) { var Processor = new ReportProcessor(Watcher, ProcessorIndex); Processors.Add(Processor); } StatusReporter.Start(); DateTime StartupTime = DateTime.UtcNow; WriteEvent("Successfully started at " + StartupTime); } /// /// Stop the service. /// protected override void OnStop() { StatusReporter.OnPreStopping(); // Clean up the directory watcher and crash processor threads foreach (var Processor in Processors) { Processor.Dispose(); } Processors.Clear(); Watcher.Dispose(); Watcher = null; StatusReporter.Dispose(); StatusReporter = null; Slack.Dispose(); Slack = null; // Flush the log to disk Log.Dispose(); Log = null; } /// /// Run the service in debug mode. This spews all logging to the console rather than suppressing it. /// public void DebugRun() { OnStart( null ); Console.WriteLine( "Press enter to exit" ); Console.Read(); OnStop(); } } }