async Task <bool> IManager.RunPostprocessor( KeyValuePair <ILogSourcePostprocessor, ILogSource>[] typesAndSources, object customData) { var sources = typesAndSources.Select(typesAndSource => { var outputType = typesAndSource.Key; var forLogSource = typesAndSource.Value; if (!knownLogSources.TryGetValue(forLogSource, out LogSourceRecord logSourceRecord)) { throw new ArgumentException("Log source is unknown"); } var postprocessorRecord = logSourceRecord.PostprocessorsOutputs.SingleOrDefault(parserRec => parserRec.metadata == outputType); if (postprocessorRecord == null) { throw new ArgumentException("Bad Postprocessor output type: " + outputType.Kind.ToString()); } if (postprocessorRecord.state.PostprocessorNeedsRunning == null) { throw new InvalidOperationException("Can not start postprocessor in this state"); } string outputFileName; using (var section = forLogSource.LogSourceSpecificStorageEntry.OpenXMLSection( outputType.MakePostprocessorOutputFileName(), Persistence.StorageSectionOpenFlag.ReadOnly)) outputFileName = section.AbsolutePath; bool needsProcessing = logSourceRecord.logSource.Visible && postprocessorRecord.state.PostprocessorNeedsRunning == true; needsProcessing |= crossLogSourcePostprocessorsTypes.Contains(postprocessorRecord.metadata); var sourceContentsEtag = logSourceRecord.logSource.Provider.Stats.ContentsEtag?.ToString(); return(new { OutputType = outputType, PostprocessorInput = logSourceRecord.ToPostprocessorInput( outputFileName, sourceContentsEtag, customData ), PostprocessorRecord = postprocessorRecord, LogSourceMeta = logSourceRecord.metadata, LogSource = logSourceRecord.logSource, NeedsProcessing = needsProcessing, TemplatesTracker = new TemplatesTracker(), IsSelected = new Ref <bool>() }); }).ToList(); bool noLogNeedsProcessing = sources.All(s => !s.NeedsProcessing); if (noLogNeedsProcessing) { sources.ForEach(s => s.IsSelected.Value = true); } else { sources.ForEach(s => s.IsSelected.Value = s.NeedsProcessing); } var outerTasks = new List <Task>(); foreach (var postprocessorTypeGroup in sources.Where(s => s.IsSelected.Value).GroupBy(s => s.OutputType)) { var postprocessorProgress = progressAggregator.CreateChildAggregator(); postprocessorProgress.ProgressChanged += (s, e) => FireChangedEvent(); var innerTask = RunPostprocessorBody(async() => { IPostprocessorRunSummary summary; using (var progressSinks = new ProgressSinksCollection()) { summary = await postprocessorTypeGroup.Key.Run( postprocessorTypeGroup .Select(s => s .PostprocessorInput .AttachProgressHandler(postprocessorProgress, progressSinks.Sinks) .SetTemplatesTracker(s.TemplatesTracker) ) .ToArray() ); } foreach (var p in postprocessorTypeGroup) { telemetry.ReportUsedFeature( MakeLogSourcePostprocessorFeatureId(p.LogSourceMeta, postprocessorTypeGroup.Key), p.TemplatesTracker.GetUsedTemplates() ); } return(summary); }); foreach (var postprocessorRecord in postprocessorTypeGroup.Select(s => s.PostprocessorRecord)) { var flowCompletion = new TaskCompletionSource <int>(); postprocessorRecord.SetState(new RunningState(postprocessorRecord.state.ctx, innerTask, postprocessorProgress, flowCompletion)); outerTasks.Add(flowCompletion.Task); } } Refresh(); await Task.WhenAll(outerTasks); return(true); }
async Task <bool> IPostprocessorsManager.RunPostprocessor( KeyValuePair <ILogSourcePostprocessor, ILogSource>[] typesAndSources, bool forceSourcesSelection, object customData) { var sources = typesAndSources.Select(typesAndSource => { var outputType = typesAndSource.Key; var forLogSource = typesAndSource.Value; LogSourceRecordInternal logSourceRecord; if (!knownLogSources.TryGetValue(forLogSource, out logSourceRecord)) { throw new ArgumentException("Log source is unknown"); } var postprocessorRecord = logSourceRecord.PostprocessorsOutputs.SingleOrDefault(parserRec => parserRec.Metadata == outputType); if (postprocessorRecord == null) { throw new ArgumentException("Bad Postprocessor output type: " + outputType.TypeID); } if (postprocessorRecord.status == LogSourcePostprocessorOutput.Status.InProgress) { throw new InvalidOperationException("Postprocessor output for log source is already being generated"); } string outputFileName; using (var section = forLogSource.LogSourceSpecificStorageEntry.OpenXMLSection( MakePostprocessorOutputFileName(outputType), Persistence.StorageSectionOpenFlag.ReadOnly)) outputFileName = section.AbsolutePath; bool needsProcessing = logSourceRecord.logSource.Visible && ( postprocessorRecord.status == LogSourcePostprocessorOutput.Status.NeverRun || postprocessorRecord.status == LogSourcePostprocessorOutput.Status.Failed || postprocessorRecord.status == LogSourcePostprocessorOutput.Status.Outdated); needsProcessing |= crossLogSourcePostprocessorsTypes.Contains(postprocessorRecord.Metadata); XAttribute contentsEtagAttr = null; var sourceContentsEtag = logSourceRecord.logSource.Provider.Stats.ContentsEtag; if (sourceContentsEtag != null) { contentsEtagAttr = new XAttribute( XName.Get("etag", xmlNs), logSourceRecord.logSource.Provider.Stats.ContentsEtag ); } return(new { OutputType = outputType, PostprocessorInput = logSourceRecord.ToPostprocessorInput( outputFileName, contentsEtagAttr, customData ), PostprocessorRecord = postprocessorRecord, LogSourceMeta = logSourceRecord.metadata, LogSource = logSourceRecord.logSource, NeedsProcessing = needsProcessing, UILogSourceInfo = new LogsSourcesSelectorDialogParams.LogSourceInfo() { Description = forLogSource.GetShortDisplayNameWithAnnotation() }, TemplatesTracker = new TemplatesTracker() }); }).ToList(); bool noLogNeedsProcessing = sources.All(s => !s.NeedsProcessing); if (noLogNeedsProcessing) { sources.ForEach(s => s.UILogSourceInfo.IsSelected = true); } else { sources.ForEach(s => s.UILogSourceInfo.IsSelected = s.NeedsProcessing); } if (forceSourcesSelection && userInteractions != null) { if (!await userInteractions.ShowLogsSourcesSelectorDialog(new LogsSourcesSelectorDialogParams() { LogSources = sources.Select(s => s.UILogSourceInfo).ToList() }, CancellationToken.None)) { return(false); } } var outerTasks = new List <Task>(); foreach (var postprocessorTypeGroup in sources.Where(s => s.UILogSourceInfo.IsSelected).GroupBy(s => s.OutputType)) { var postprocessorProgress = progressAggregator.CreateChildAggregator(); postprocessorProgress.ProgressChanged += (s, e) => RefreshInternal(assumeSomethingChanging: true); var innerTask = RunPostprocessor(async() => { IPostprocessorRunSummary summary; using (var progressSinks = new ProgressSinksCollection()) { summary = await postprocessorTypeGroup.Key.Run( postprocessorTypeGroup .Select(s => s .PostprocessorInput .AttachProgressHandler(postprocessorProgress, progressSinks.Sinks) .SetTemplatesTracker(s.TemplatesTracker) ) .ToArray() ); } foreach (var p in postprocessorTypeGroup) { telemetry.ReportUsedFeature( MakeLogSourcePostprocessorFeatureId(p.LogSourceMeta, postprocessorTypeGroup.Key), p.TemplatesTracker.GetUsedTemplates() ); } return(summary); }); outerTasks.Add(AwaitOnPostprocessorTaskAndUpdate(innerTask)); foreach (var postprocessorRecord in postprocessorTypeGroup.Select(s => s.PostprocessorRecord)) { postprocessorRecord.postprocessorTask = innerTask; postprocessorRecord.postprocessorProgress = postprocessorProgress; } } RefreshInternal(); await Task.WhenAll(outerTasks); return(true); }