/// <summary> /// Start the service, and stop the service if there were any errors found. /// </summary> /// <param name="Arguments">Command line arguments (unused).</param> 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 }; Symbolicator = new Symbolicator(); StatusReporter = new StatusReporting(); ReportIndex = new ReportIndex { IsEnabled = !string.IsNullOrWhiteSpace(Config.Default.ProcessedReportsIndexPath), Filepath = Config.Default.ProcessedReportsIndexPath, Retention = TimeSpan.FromDays(Config.Default.ReportsIndexRetentionDays) }; ReportIndex.ReadFromFile(); WriteEvent("Initializing AWS"); string AWSError; AWSCredentials AWSCredentialsForDataRouter = new StoredProfileAWSCredentials(Config.Default.AWSProfileInputName, Config.Default.AWSCredentialsFilepath); AmazonSQSConfig SqsConfigForDataRouter = new AmazonSQSConfig { ServiceURL = Config.Default.AWSSQSServiceInputURL }; AmazonS3Config S3ConfigForDataRouter = new AmazonS3Config { ServiceURL = Config.Default.AWSS3ServiceInputURL }; DataRouterAWS = new AmazonClient(AWSCredentialsForDataRouter, SqsConfigForDataRouter, S3ConfigForDataRouter, out AWSError); if (!DataRouterAWS.IsSQSValid || !DataRouterAWS.IsS3Valid) { WriteFailure("AWS failed to initialize profile for DataRouter access. Error:" + AWSError); StatusReporter.Alert("AWSFailInput", "AWS failed to initialize profile for DataRouter access", 0); } AWSCredentials AWSCredentialsForOutput = new StoredProfileAWSCredentials(Config.Default.AWSProfileOutputName, Config.Default.AWSCredentialsFilepath); AmazonS3Config S3ConfigForOutput = new AmazonS3Config { ServiceURL = Config.Default.AWSS3ServiceOutputURL }; OutputAWS = new AmazonClient(AWSCredentialsForOutput, null, S3ConfigForOutput, out AWSError); if (!OutputAWS.IsS3Valid) { WriteFailure("AWS failed to initialize profile for output S3 bucket access. Error:" + AWSError); StatusReporter.Alert("AWSFailOutput", "AWS failed to initialize profile for output S3 bucket access", 0); } // Add directory watchers WriteEvent("Creating ReportWatcher"); Watcher = new ReportWatcher(); WriteEvent("Creating ReportProcessors"); for (int ProcessorIndex = 0; ProcessorIndex < Config.Default.ProcessorThreadCount; ProcessorIndex++) { var Processor = new ReportProcessor(Watcher, ProcessorIndex); Processors.Add(Processor); } // Init events by enumerating event names WriteEvent("Initializing Event Counters"); FieldInfo[] EventNameFields = typeof(StatusReportingEventNames).GetFields(BindingFlags.Static | BindingFlags.Public); StatusReporter.InitCounters(EventNameFields.Select(EventNameField => (string)EventNameField.GetValue(null))); WriteEvent("Initializing Performance Mean Counters"); FieldInfo[] MeanNameFields = typeof(StatusReportingPerfMeanNames).GetFields(BindingFlags.Static | BindingFlags.Public); StatusReporter.InitMeanCounters(MeanNameFields.Select(MeanNameField => (string)MeanNameField.GetValue(null))); WriteEvent("Initializing Folder Monitors"); Dictionary <string, string> FoldersToMonitor = new Dictionary <string, string>(); FoldersToMonitor.Add(Config.Default.ProcessedReports, "Processed Reports"); FoldersToMonitor.Add(Config.Default.ProcessedVideos, "Processed Videos"); FoldersToMonitor.Add(Config.Default.DepotRoot, "P4 Workspace"); FoldersToMonitor.Add(Config.Default.InternalLandingZone, "CRR Landing Zone"); FoldersToMonitor.Add(Config.Default.DataRouterLandingZone, "Data Router Landing Zone"); FoldersToMonitor.Add(Config.Default.PS4LandingZone, "PS4 Landing Zone"); FoldersToMonitor.Add(Assembly.GetExecutingAssembly().Location, "CRP Binaries and Logs"); FoldersToMonitor.Add(Config.Default.MDDPDBCachePath, "MDD PDB Cache"); StatusReporter.InitFolderMonitors(FoldersToMonitor); WriteEvent("Starting StatusReporter"); StatusReporter.Start(); // Start the threads now Watcher.Start(); foreach (var Processor in Processors) { Processor.Start(); } DateTime StartupTime = DateTime.UtcNow; WriteEvent("Successfully started at " + StartupTime); }
/// <summary> /// Look for new report folders and add them to the publicly available thread-safe queue. /// </summary> public int CheckForNewReports() { try { if (QueueCount >= Config.Default.MinDesiredMemoryQueueSize) { CrashReporterProcessServicer.WriteEvent(string.Format( "CheckForNewReports: {0} skipped busy queue size {1} in {2}", QueueName, QueueCount, LandingZone)); } else { var NewReportPath = ""; var ReportsInLandingZone = new ReportIdSet(); CrashReporterProcessServicer.StatusReporter.AlertOnLowDisk(LandingZone, Config.Default.DiskSpaceAlertPercent); DirectoryInfo[] DirectoriesInLandingZone; if (GetCrashesFromLandingZone(out DirectoriesInLandingZone)) { LastQueueSizeOnDisk = DirectoriesInLandingZone.Length; int EnqueuedCount = 0; CrashReporterProcessServicer.WriteEvent(string.Format("CheckForNewReports: {0} reports in disk landing zone {1}", DirectoriesInLandingZone.Length, LandingZone)); // Add any new reports for (int DirIndex = 0; DirIndex < DirectoriesInLandingZone.Length && QueueCount < Config.Default.MaxMemoryQueueSize; DirIndex++) { var SubDirInfo = DirectoriesInLandingZone[DirIndex]; try { if (Directory.Exists(SubDirInfo.FullName)) { NewReportPath = SubDirInfo.FullName; ReportsInLandingZone.Add(NewReportPath); if (!ReportsInLandingZoneLastTimeWeChecked.Contains(NewReportPath)) { if (EnqueueNewReport(NewReportPath)) { EnqueuedCount++; } } } } catch (Exception Ex) { CrashReporterProcessServicer.WriteException("CheckForNewReportsInner: " + Ex, Ex); ReportProcessor.MoveReportToInvalid(NewReportPath, "NEWRECORD_FAIL_" + DateTime.Now.Ticks); } } ReportsInLandingZoneLastTimeWeChecked = ReportsInLandingZone; CrashReporterProcessServicer.WriteEvent(string.Format( "CheckForNewReports: {0} enqueued to queue size {1} from {2}", EnqueuedCount, QueueCount, LandingZone)); CrashReporterProcessServicer.WriteEvent(string.Format("CheckForNewReports: Enqueue rate {0:N1}/minute from {1}", EnqueueCounter.EventsPerSecond * 60, LandingZone)); } else { LastQueueSizeOnDisk = 0; } } } catch (Exception Ex) { CrashReporterProcessServicer.WriteException("CheckForNewReportsOuter: " + Ex, Ex); } return(GetTotalWaitingCount()); }
/// <summary> Enqueues a new crash. </summary> void EnqueueNewReport(string NewReportPath) { string ReportName = Path.GetFileName(NewReportPath); string CompressedReportPath = Path.Combine(NewReportPath, ReportName + ".ue4crash"); string MetadataPath = Path.Combine(NewReportPath, ReportName + ".xml"); bool bIsCompressed = File.Exists(CompressedReportPath) && File.Exists(MetadataPath); if (bIsCompressed) { FCompressedCrashInformation CompressedCrashInformation = XmlHandler.ReadXml <FCompressedCrashInformation>(MetadataPath); bool bResult = DecompressReport(CompressedReportPath, CompressedCrashInformation); if (!bResult) { ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); ReportProcessor.MoveReportToInvalid(NewReportPath, "DECOMPRESSION_FAIL_" + DateTime.Now.Ticks + "_" + ReportName); return; } else { // Rename metadata file to not interfere with the WERReportMetadata. File.Move(MetadataPath, Path.ChangeExtension(MetadataPath, "processed_xml")); } } // Unified crash reporting FGenericCrashContext GenericContext = FindCrashContext(NewReportPath); FGenericCrashContext Context = GenericContext; bool bFromWER = false; if (Context == null || !Context.HasProcessedData()) { WERReportMetadata MetaData = FindMetadata(NewReportPath); if (MetaData != null) { FReportData ReportData = new FReportData(MetaData, NewReportPath); Context = ConvertMetadataToCrashContext(MetaData, NewReportPath); bFromWER = true; } } if (Context == null) { CrashReporterProcessServicer.WriteFailure("! NoCntx : Path=" + NewReportPath); ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); } else { if (GenericContext != null && GenericContext.PrimaryCrashProperties.ErrorMessage.Length > 0) { // Get error message from the crash context and fix value in the metadata. Context.PrimaryCrashProperties.ErrorMessage = GenericContext.PrimaryCrashProperties.ErrorMessage; } Context.CrashDirectory = NewReportPath; Context.PrimaryCrashProperties.SetPlatformFullName(); // If based on WER, save to the file. if (bFromWER && GenericContext == null) { Context.ToFile(); } FEngineVersion EngineVersion = new FEngineVersion(Context.PrimaryCrashProperties.EngineVersion); uint BuiltFromCL = EngineVersion.Changelist; string BranchName = EngineVersion.Branch; if (string.IsNullOrEmpty(BranchName)) { CrashReporterProcessServicer.WriteFailure("% NoBranch: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); ReportProcessor.MoveReportToInvalid(NewReportPath, Context.GetAsFilename()); return; } if (BranchName.Equals(CrashReporterConstants.LicenseeBranchName, StringComparison.InvariantCultureIgnoreCase)) { CrashReporterProcessServicer.WriteFailure("% UE4-QA : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); ReportProcessor.CleanReport(NewReportPath); return; } // Look for the Diagnostics.txt, if we have a diagnostics file we can continue event if the CL is marked as broken. bool bHasDiagnostics = FindDiagnostics(NewReportPath); if (BuiltFromCL == 0 && (!bHasDiagnostics && !Context.HasProcessedData())) { // For now ignore all locally made crashes. CrashReporterProcessServicer.WriteFailure("! BROKEN0 : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); ReportProcessor.CleanReport(NewReportPath); return; } lock (NewReportsLock) { NewCrashContexts.Add(Context); } CrashReporterProcessServicer.WriteEvent("+ Enqueued: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); } }
// From CrashUpload.cpp /* * struct FCompressedCrashFile : FNoncopyable * { * int32 CurrentFileIndex; // 4 bytes for file index * FString Filename; // 4 bytes for length + 260 bytes for char data * TArray<uint8> Filedata; // 4 bytes for length + N bytes for data * } */ /// <summary> Enqueues a new crash. </summary> private bool EnqueueNewReport(string NewReportPath) { string ReportName = Path.GetFileName(NewReportPath); string CompressedReportPath = Path.Combine(NewReportPath, ReportName + ".ue4crash"); string MetadataPath = Path.Combine(NewReportPath, ReportName + ".xml"); bool bIsCompressed = File.Exists(CompressedReportPath) && File.Exists(MetadataPath); if (bIsCompressed) { FCompressedCrashInformation CompressedCrashInformation = XmlHandler.ReadXml <FCompressedCrashInformation>(MetadataPath); bool bResult = DecompressReport(CompressedReportPath, CompressedCrashInformation); if (!bResult) { ReportProcessor.MoveReportToInvalid(NewReportPath, "DECOMPRESSION_FAIL_" + DateTime.Now.Ticks + "_" + ReportName); return(false); } else { // Rename metadata file to not interfere with the WERReportMetadata. File.Move(MetadataPath, Path.ChangeExtension(MetadataPath, "processed_xml")); } } // Unified crash reporting FGenericCrashContext GenericContext = FindCrashContext(NewReportPath); FGenericCrashContext Context = GenericContext; bool bContextDirty = false; WERReportMetadata MetaData = FindMetadata(NewReportPath); if (MetaData != null) { if (Context == null) { // Missing crash context FReportData ReportData = new FReportData(MetaData, NewReportPath); ConvertMetadataToCrashContext(ReportData, NewReportPath, ref Context); bContextDirty = true; } else if (!Context.HasProcessedData()) { // Missing data - try to get from WER metadata FReportData ReportData = new FReportData(MetaData, NewReportPath); GetErrorMessageFromMetadata(ReportData, Context); bContextDirty = true; } } if (Context == null) { CrashReporterProcessServicer.WriteFailure("! NoCntx : Path=" + NewReportPath); ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); return(false); } Context.CrashDirectory = NewReportPath; Context.PrimaryCrashProperties.SetPlatformFullName(); // Added data from WER, save to the crash context file. if (bContextDirty) { Context.ToFile(); } FEngineVersion EngineVersion = new FEngineVersion(Context.PrimaryCrashProperties.EngineVersion); uint BuiltFromCL = EngineVersion.Changelist; string BranchName = EngineVersion.Branch; if (string.IsNullOrEmpty(BranchName)) { CrashReporterProcessServicer.WriteEvent("% Warning NoBranch: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath + " EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Engine version has no branch name. EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion; Context.ToFile(); } else if (BranchName.Equals(CrashReporterConstants.LicenseeBranchName, StringComparison.InvariantCultureIgnoreCase)) { CrashReporterProcessServicer.WriteEvent("% Warning branch is UE4-QA : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Branch was the forbidden LicenseeBranchName=" + BranchName; Context.ToFile(); } // Look for the Diagnostics.txt, if we have a diagnostics file we can continue event if the CL is marked as broken. bool bHasDiagnostics = FindDiagnostics(NewReportPath); if (BuiltFromCL == 0 && (!bHasDiagnostics && !Context.HasProcessedData())) { // For now ignore all locally made crashes. CrashReporterProcessServicer.WriteEvent("% Warning CL=0 and no useful data : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Report from CL=0 has no diagnostics, callstack or error msg"; Context.ToFile(); } // Check static reports index for duplicated reports // This WILL happen when running multiple, non-mutually exclusive crash sources (e.g. Receiver + Data Router) // This can be safely discontinued when all crashes come from the same SQS // This DOES NOT scale to multiple CRP instances // ReportIndex can be disabled by leaving the path empty in config if (!CrashReporterProcessServicer.ReportIndex.TryAddNewReport(ReportName)) { // Crash report not accepted by index CrashReporterProcessServicer.WriteEvent(string.Format( "EnqueueNewReport: Duplicate report skipped {0} in queue {1}", NewReportPath, QueueName)); CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.DuplicateRejected); ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); return(false); } if (ShouldDecimateNextReport()) { CrashReporterProcessServicer.WriteEvent(string.Format("EnqueueNewReport: Discarding Report due to backlog of {0} in queue {1}: Path={2}", GetTotalWaitingCount(), QueueName, NewReportPath)); CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.ReportDiscarded); ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); return(false); } lock (NewReportsLock) { NewCrashContexts.Enqueue(Context); } EnqueueCounter.AddEvent(); CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.QueuedEvent); CrashReporterProcessServicer.WriteEvent("+ Enqueued: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); return(true); }
/// <summary> /// Look for new report folders and add them to the publicly available thread-safe queue. /// </summary> public override int CheckForNewReports() { try { if (QueueCount >= SkipQueueRefreshMin) { CrashReporterProcessServicer.WriteEvent(string.Format("CheckForNewReports: skipped busy queue size {0} in {1}", QueueCount, LandingZone)); return(LastQueueSizeOnDisk); } var NewReportPath = ""; var ReportsInLandingZone = new ReportIdSet(); // Check the landing zones for new reports DirectoryInfo DirInfo = new DirectoryInfo(LandingZone); // Couldn't find a landing zone, skip and try again later. // Crash receiver will recreate them if needed. if (!DirInfo.Exists) { CrashReporterProcessServicer.WriteFailure("LandingZone not found: " + LandingZone); return(LastQueueSizeOnDisk); } var DirectoriesInLandingZone = DirInfo.GetDirectories().OrderBy(dirinfo => dirinfo.CreationTimeUtc).ToArray(); LastQueueSizeOnDisk = DirectoriesInLandingZone.Length; int EnqueuedCount = 0; CrashReporterProcessServicer.WriteEvent(string.Format("CheckForNewReports: {0} reports in {1}", DirectoriesInLandingZone.Length, LandingZone)); // Add any new reports for (int DirIndex = 0; DirIndex < DirectoriesInLandingZone.Length && QueueCount < QueueMax; DirIndex++) { var SubDirInfo = DirectoriesInLandingZone[DirIndex]; try { if (Directory.Exists(SubDirInfo.FullName)) { NewReportPath = SubDirInfo.FullName; ReportsInLandingZone.Add(NewReportPath); if (!ReportsInLandingZoneLastTimeWeChecked.Contains(NewReportPath)) { EnqueueNewReport(NewReportPath); EnqueuedCount++; } } } catch (System.Exception Ex) { CrashReporterProcessServicer.WriteException("CheckForNewReportsInner: " + Ex.ToString()); ReportProcessor.MoveReportToInvalid(NewReportPath, "NEWRECORD_FAIL_" + DateTime.Now.Ticks); } } //CrashReporterProcessServicer.WriteEvent( string.Format( "ReportsInLandingZone={0}, ReportsInLandingZoneLastTimeWeChecked={1}", ReportsInLandingZone.Count, ReportsInLandingZoneLastTimeWeChecked.Count ) ); ReportsInLandingZoneLastTimeWeChecked = ReportsInLandingZone; CrashReporterProcessServicer.WriteEvent(string.Format("CheckForNewReports: {0} enqueued to queue size {1} from {2}", EnqueuedCount, QueueCount, LandingZone)); CrashReporterProcessServicer.WriteEvent(string.Format("CheckForNewReports: Enqueue rate {0:N1}/minute from {1}", EnqueueCounter.EventsPerSecond * 60, LandingZone)); } catch (Exception Ex) { CrashReporterProcessServicer.WriteException("CheckForNewReportsOuter: " + Ex.ToString()); } return(LastQueueSizeOnDisk); }
/// <summary> Enqueues a new crash. </summary> private void EnqueueNewReport(string NewReportPath) { string ReportName = Path.GetFileName(NewReportPath); string CompressedReportPath = Path.Combine(NewReportPath, ReportName + ".ue4crash"); string MetadataPath = Path.Combine(NewReportPath, ReportName + ".xml"); bool bIsCompressed = File.Exists(CompressedReportPath) && File.Exists(MetadataPath); if (bIsCompressed) { FCompressedCrashInformation CompressedCrashInformation = XmlHandler.ReadXml <FCompressedCrashInformation>(MetadataPath); bool bResult = DecompressReport(CompressedReportPath, CompressedCrashInformation); if (!bResult) { ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); ReportProcessor.MoveReportToInvalid(NewReportPath, "DECOMPRESSION_FAIL_" + DateTime.Now.Ticks + "_" + ReportName); return; } else { // Rename metadata file to not interfere with the WERReportMetadata. File.Move(MetadataPath, Path.ChangeExtension(MetadataPath, "processed_xml")); } } // Unified crash reporting FGenericCrashContext GenericContext = FindCrashContext(NewReportPath); FGenericCrashContext Context = GenericContext; bool bFromWER = false; if (Context == null || !Context.HasProcessedData()) { WERReportMetadata MetaData = FindMetadata(NewReportPath); if (MetaData != null) { FReportData ReportData = new FReportData(MetaData, NewReportPath); ConvertMetadataToCrashContext(MetaData, NewReportPath, ref Context); bFromWER = true; } } if (Context == null) { CrashReporterProcessServicer.WriteFailure("! NoCntx : Path=" + NewReportPath); ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); } else { Context.CrashDirectory = NewReportPath; Context.PrimaryCrashProperties.SetPlatformFullName(); // Added data from WER, save to the crash context file. if (bFromWER) { Context.ToFile(); } FEngineVersion EngineVersion = new FEngineVersion(Context.PrimaryCrashProperties.EngineVersion); uint BuiltFromCL = EngineVersion.Changelist; string BranchName = EngineVersion.Branch; if (string.IsNullOrEmpty(BranchName)) { CrashReporterProcessServicer.WriteEvent("% Warning NoBranch: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath + " EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Engine version has no branch name. EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion; } else if (BranchName.Equals(CrashReporterConstants.LicenseeBranchName, StringComparison.InvariantCultureIgnoreCase)) { CrashReporterProcessServicer.WriteEvent("% Warning branch is UE4-QA : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Branch was the forbidden LicenseeBranchName=" + BranchName; } // Look for the Diagnostics.txt, if we have a diagnostics file we can continue event if the CL is marked as broken. bool bHasDiagnostics = FindDiagnostics(NewReportPath); if (BuiltFromCL == 0 && (!bHasDiagnostics && !Context.HasProcessedData())) { // For now ignore all locally made crashes. CrashReporterProcessServicer.WriteEvent("% Warning CL=0 and no useful data : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Report from CL=0 has no diagnostics, callstack or error msg"; } lock (NewReportsLock) { NewCrashContexts.Enqueue(Context); } EnqueueCounter.AddEvent(); CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingConstants.QueuedEvent); CrashReporterProcessServicer.WriteEvent("+ Enqueued: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); } }
/// <summary> /// Start the service, and stop the service if there were any errors found. /// </summary> /// <param name="Arguments">Command line arguments (unused).</param> 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 }; Symbolicator = new Symbolicator(); StatusReporter = new StatusReporting(); // Add directory watchers WriteEvent("Creating ReportWatcher"); Watcher = new ReportWatcher(); WriteEvent("Creating ReportProcessors"); for (int ProcessorIndex = 0; ProcessorIndex < Config.Default.ProcessorThreadCount; ProcessorIndex++) { var Processor = new ReportProcessor(Watcher, ProcessorIndex); Processors.Add(Processor); } // Init events by enumerating event names WriteEvent("Initializing Event Counters"); FieldInfo[] EventNameFields = typeof(StatusReportingEventNames).GetFields(BindingFlags.Static | BindingFlags.Public); StatusReporter.InitCounters(EventNameFields.Select(EventNameField => (string)EventNameField.GetValue(null))); WriteEvent("Initializing Folder Monitors"); Dictionary <string, string> FoldersToMonitor = new Dictionary <string, string>(); FoldersToMonitor.Add(Config.Default.ProcessedReports, "Processed Reports"); FoldersToMonitor.Add(Config.Default.ProcessedVideos, "Processed Videos"); FoldersToMonitor.Add(Config.Default.DepotRoot, "P4 Workspace"); FoldersToMonitor.Add(Config.Default.InternalLandingZone, "CRR Landing Zone"); FoldersToMonitor.Add(Config.Default.DataRouterLandingZone, "Data Router Landing Zone"); FoldersToMonitor.Add(Config.Default.InvalidReportsDirectory, "Invalid Reports"); FoldersToMonitor.Add(Assembly.GetExecutingAssembly().Location, "CRP Binaries and Logs"); FoldersToMonitor.Add(Config.Default.MDDPDBCachePath, "MDD PDB Cache"); StatusReporter.InitFolderMonitors(FoldersToMonitor); WriteEvent("Starting StatusReporter"); StatusReporter.Start(); // Start the threads now Watcher.Start(); foreach (var Processor in Processors) { Processor.Start(); } DateTime StartupTime = DateTime.UtcNow; WriteEvent("Successfully started at " + StartupTime); }
/// <summary> /// Start the service, and stop the service if there were any errors found. /// </summary> /// <param name="Arguments">Command line arguments (unused).</param> 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 }; Symbolicator = new Symbolicator(); StatusReporter = new StatusReporting(); // Add directory watchers WriteEvent("Creating ReportWatcher"); Watcher = new ReportWatcher(); WriteEvent("Creating ReportProcessors"); for (int ProcessorIndex = 0; ProcessorIndex < Config.Default.ProcessorThreadCount; ProcessorIndex++) { var Processor = new ReportProcessor(Watcher, ProcessorIndex); Processors.Add(Processor); } // Init events by enumerating event names WriteEvent("Initializing Event Counters"); FieldInfo[] EventNameFields = typeof(StatusReportingEventNames).GetFields(BindingFlags.Static | BindingFlags.Public); StatusReporter.InitCounters(EventNameFields.Select(EventNameField => (string)EventNameField.GetValue(null))); WriteEvent("Initializing Folder Monitors"); Dictionary<string, string> FoldersToMonitor = new Dictionary<string, string>(); FoldersToMonitor.Add(Config.Default.ProcessedReports, "Processed Reports"); FoldersToMonitor.Add(Config.Default.ProcessedVideos, "Processed Videos"); FoldersToMonitor.Add(Config.Default.DepotRoot, "P4 Workspace"); FoldersToMonitor.Add(Config.Default.InternalLandingZone, "CRR Landing Zone"); FoldersToMonitor.Add(Config.Default.DataRouterLandingZone, "Data Router Landing Zone"); FoldersToMonitor.Add(Config.Default.InvalidReportsDirectory, "Invalid Reports"); FoldersToMonitor.Add(Assembly.GetExecutingAssembly().Location, "CRP Binaries and Logs"); FoldersToMonitor.Add(Config.Default.MDDPDBCachePath, "MDD PDB Cache"); StatusReporter.InitFolderMonitors(FoldersToMonitor); WriteEvent("Starting StatusReporter"); StatusReporter.Start(); // Start the threads now Watcher.Start(); foreach (var Processor in Processors) { Processor.Start(); } DateTime StartupTime = DateTime.UtcNow; WriteEvent("Successfully started at " + StartupTime); }