private ProcessFileResult ProcessStream(Stream stream, LogTypeInfo logTypeInfo, LogFileInfo logFileInfo, IList <IPlugin> plugins)
        {
            var linesProcessed = 0;
            var reader         = logTypeInfo.LogReaderProvider(stream, logFileInfo.FilePath);

            try
            {
                foreach (var line in reader.ReadLines())
                {
                    if (!line.HasContent)
                    {
                        continue;
                    }

                    var logLine = new LogLine(line, logFileInfo);

                    foreach (var plugin in plugins)
                    {
                        plugin.ProcessLogLine(logLine, logTypeInfo.LogType);
                    }

                    ++linesProcessed;
                }
            }
            catch (OutOfMemoryException ex)
            {
                var errorMessage = FailureReasonMessageGenerator.OutOfMemoryError(logFileInfo, plugins);
                _logger.LogInformation(ex, errorMessage);
                return(new ProcessFileResult(linesProcessed, errorMessage, ExitReason.OutOfMemory));
            }

            return(new ProcessFileResult(linesProcessed));
        }
        private (string, ExitReason) GetExitReasonAndErrorMessageIfApplicable(ProcessLogTypeResult failedProcessLogTypeResult, Dictionary <LogType, ProcessLogTypeResult> logProcessingStatistics)
        {
            if (failedProcessLogTypeResult != null)
            {
                return(failedProcessLogTypeResult.ErrorMessage, failedProcessLogTypeResult.ExitReason);
            }

            var processedAnyFiles = logProcessingStatistics.Any(kvp => kvp.Value.FilesProcessed > 0);

            return(processedAnyFiles
                ? (null, ExitReason.CompletedSuccessfully)
                : (FailureReasonMessageGenerator.NoTableauLogFilesFound(_config.RequestedPlugins, _config.OriginalLocation), ExitReason.LogSetDoesNotContainRelevantLogs));
        }
        public ProcessLogSetResult ProcessLogSet()
        {
            _logger.LogInformation("Using temp folder `{tempDir}`", _config.TempDir);

            using var logsExtractor = new TableauLogsExtractor(_config.LogSetLocation, _config.TempDir, _processingNotificationsCollector, _loggerFactory.CreateLogger <TableauLogsExtractor>());

            if (!_pluginManager.IsValidPluginConfiguration(out var badPluginNames))
            {
                return(ProcessLogSetResult.Failed(FailureReasonMessageGenerator.BadPluginNamesSpecified(badPluginNames), ExitReason.IncorrectConfiguration));
            }

            var loadedPlugins    = _pluginManager.CreatePlugins(_writerFactory, _processingNotificationsCollector).ToList();
            var requiredLogTypes = _pluginManager.GetRequiredLogTypes().ToList();

            var processedLogTypes = string.Join(", ", requiredLogTypes.OrderBy(name => name));

            _logger.LogInformation("Based on requested plugins, the following log types will be processed: {processedLogTypes}", processedLogTypes);

            var logProcessingStatistics = new Dictionary <LogType, ProcessLogTypeResult>();
            var pluginsReceivedAnyData  = new HashSet <string>();
            ProcessLogTypeResult failedLogTypeResult = null;

            foreach (var logType in requiredLogTypes)
            {
                _logger.LogInformation("Starting to process {logType} logs", logType);

                var logTypeInfo       = _logTypeDetails.GetInfoForLogType(logType);
                var applicablePlugins = loadedPlugins
                                        .Where(plugin => plugin.ConsumedLogTypes.Contains(logType))
                                        .ToList();

                try
                {
                    var logTypeProcessingResult = ProcessLogType(logsExtractor.LogSetParts, logTypeInfo, applicablePlugins);
                    logProcessingStatistics.Add(logType, logTypeProcessingResult);

                    if (!logTypeProcessingResult.IsSuccessful)
                    {
                        failedLogTypeResult = logTypeProcessingResult;
                        break;
                    }

                    _logger.LogInformation("Done processing {logType} logs. {processingResult}", logType, logTypeProcessingResult);

                    if (logTypeProcessingResult.FilesProcessed > 0)
                    {
                        foreach (var plugin in applicablePlugins)
                        {
                            pluginsReceivedAnyData.Add(plugin.Name);
                        }
                    }
                }
                catch (Exception ex)
                {
                    var unhandledExceptionMessage = $"Unhandled exception occurred while processing log type {logType}. Exception: {ex.Message}";
                    _logger.LogError(ex, unhandledExceptionMessage);
                    var fakeProcessingFileResult  = new ProcessFileResult(0, unhandledExceptionMessage, ExitReason.UnclassifiedError);
                    var fakeProcessingTypeResults = new ProcessLogTypeResult();
                    fakeProcessingTypeResults.AddProcessingInfo(TimeSpan.Zero, 0, fakeProcessingFileResult);
                    failedLogTypeResult = fakeProcessingTypeResults;
                    break;
                }
            }

            _logger.LogInformation("Telling all plugins to complete processing of any cached data");
            var pluginsExecutionResults = _pluginManager.SendCompleteProcessingSignalToPlugins(failedLogTypeResult != null);

            _logger.LogInformation("Completed reading log set and generating data");

            var(errorMessage, existReason) = GetExitReasonAndErrorMessageIfApplicable(failedLogTypeResult, logProcessingStatistics);
            var loadedPluginNames = loadedPlugins.Select(plugin => plugin.Name).ToHashSet();

            return(new ProcessLogSetResult(
                       errorMessage,
                       existReason,
                       logsExtractor.LogSetSizeBytes,
                       logsExtractor.IsDirectory,
                       loadedPluginNames,
                       logProcessingStatistics,
                       pluginsExecutionResults,
                       pluginsReceivedAnyData));
        }