// 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();
}
}
}