Ejemplo n.º 1
0
        private bool ReadToEnd(ProcessStreamReader processStream, out string message)
        {
            var readStreamTask = Task.Run(() => processStream.ReadToEnd());
            var successful     = readStreamTask.Wait(_maxTime);

            message = successful ? readStreamTask.Result : "Error reading from stream";
            return(successful);
        }
Ejemplo n.º 2
0
        protected bool ReadToEnd(ProcessStreamReader processStream, out string message)
        {
            var readStreamTask = Task.Run(() => processStream.ReadToEnd());
            var successful     = readStreamTask.Wait(TimeSpan.FromSeconds(180));

            message = successful ? readStreamTask.Result : "Error reading from stream";
            return(successful);
        }
Ejemplo n.º 3
0
        private static ProcessResult RunProcess(string workingDirectory, string exeFileName, string argumentsAsString, int?maxTimeoutMs, CommandLineOutputCaptureOptionsFlag captureOptionsFlag)
        {
            // Start the indicated program and wait for it
            // to finish, hiding while we wait.
            ProcessResult r;

            using (var processWrapper = new KillOnDisposeProcessWrapper(new Process {
                StartInfo = new ProcessStartInfo(exeFileName, argumentsAsString)
            }))
            {
                if (!String.IsNullOrEmpty(workingDirectory))
                {
                    processWrapper.Process.StartInfo.WorkingDirectory = workingDirectory;
                }
                var outputSink = new ProcessStreamReader(captureOptionsFlag);
                processWrapper.Process.StartInfo.UseShellExecute        = false;
                processWrapper.Process.StartInfo.RedirectStandardOutput = true;
                processWrapper.Process.StartInfo.RedirectStandardError  = true;
                processWrapper.Process.StartInfo.CreateNoWindow         = true;
                processWrapper.Process.OutputDataReceived += outputSink.ReceiveStdOut;
                processWrapper.Process.ErrorDataReceived  += outputSink.ReceiveStdErr;

                var processDebugInfo = String.Format("Process Details:\r\n\"{0}\" {1}\r\nWorking Directory: {2}", exeFileName, argumentsAsString, workingDirectory);
                try
                {
                    processWrapper.Process.Start();
                }
                catch (Exception e)
                {
                    var message = String.Format("Program {0} got an exception on process start.\r\nException message: {1}\r\n{2}", Path.GetFileName(exeFileName), e.Message, processDebugInfo);
                    throw new Exception(message, e);
                }

                processWrapper.Process.BeginOutputReadLine();
                processWrapper.Process.BeginErrorReadLine();

                var processTimeoutPeriod = (maxTimeoutMs.HasValue) ? TimeSpan.FromMilliseconds(maxTimeoutMs.Value) : _maxTimeout;
                var hasExited            = processWrapper.Process.WaitForExit(Convert.ToInt32(processTimeoutPeriod.TotalMilliseconds));

                if (!hasExited)
                {
                    processWrapper.Process.Kill();
                }

                // TODO: Fix this so it works without a hacky "Sleep", right now this hack waits for the output to trickle in. The asychronous reads of STDERR and STDOUT may not yet be complete (run unit test under debugger for example) even though the process has exited. -MF & ASW 11/21/2011
                Thread.Sleep(TimeSpan.FromSeconds(.25));

                if (!hasExited)
                {
                    var message = String.Format("Program {0} did not exit within timeout period {1} and was terminated.\r\n{2}\r\nOutput:\r\n{3}", Path.GetFileName(exeFileName), processTimeoutPeriod,
                                                processDebugInfo, outputSink.StdOutAndStdErr);
                    throw new Exception(message);
                }

                r = new ProcessResult(processWrapper.Process.ExitCode, outputSink.StdOut, outputSink.StdErr, outputSink.StdOutAndStdErr);
            }
            return(r);
        }
Ejemplo n.º 4
0
 private static async Task PipeAsync(ProcessStreamReader source, ProcessStreamWriter destination)
 {
     // NOTE: we use PipeFrom() since this will automatically flush any characters written to the
     // TextWriter APIs of destination first. However, we wrap with a using to ensure that source is
     // disposed rather than just source.BaseStream (which is all we pass to PipeFrom)
     using (source)
     {
         await destination.PipeFromAsync(source.BaseStream).ConfigureAwait(false);
     }
 }
Ejemplo n.º 5
0
        private bool ReadToEnd(ProcessStreamReader processStream, TimeSpan maxTime, out string message)
        {
            var readStreamTask = Task.Run(() => processStream.ReadToEnd());
            // We also have a max time in the test runner so add a bit of extra here
            // just in case so we don't fail it to early.
            var successful = readStreamTask.Wait(maxTime.Add(TimeSpan.FromSeconds(30)));

            message = successful ? readStreamTask.Result : "Stuck when reading from stream!";
            return(successful);
        }
Ejemplo n.º 6
0
        private string ReadToEnd(ProcessStreamReader processStream, CancellationToken cancellationToken)
        {
            var readStreamTask = Task.Run(
                () =>
            {
                var streamMessage = string.Empty;

                while (processStream.Peek() >= 0)
                {
                    streamMessage += processStream.ReadLine();
                }

                return(streamMessage);
            });

            var successful = readStreamTask.Wait((int)_maxTime.TotalMilliseconds, cancellationToken);

            return(successful ? readStreamTask.Result : "Stuck when reading from stream!");
        }
Ejemplo n.º 7
0
        private bool ReadToEnd(ProcessStreamReader processStream, TimeSpan maxTime, CancellationToken cancellationToken, out string message)
        {
            var readStreamTask = Task.Run(
                () =>
            {
                var streamMessage = string.Empty;

                while (processStream.Peek() >= 0)
                {
                    streamMessage += processStream.ReadLine();
                }

                return(streamMessage);
            },
                cancellationToken);

            // We also have a max time in the test runner so add a bit of extra here
            // just in case so we don't fail it to early.
            var successful = readStreamTask.Wait((int)maxTime.Add(TimeSpan.FromSeconds(30)).TotalMilliseconds, cancellationToken);

            message = successful ? readStreamTask.Result : "Stuck when reading from stream!";
            return(successful);
        }
Ejemplo n.º 8
0
        public static ProcessUtilityResult ShellAndWaitImpl(string workingDirectory, string exeFileName, List <string> commandLineArguments, bool redirectStdErrAndStdOut, int?maxTimeoutMs)
        {
            var argumentsAsString = ConjoinCommandLineArguments(commandLineArguments);
            var stdErrAndStdOut   = Empty;

            // Start the indicated program and wait for it
            // to finish, hiding while we wait.
            var objProc = new Process {
                StartInfo = new ProcessStartInfo(exeFileName, argumentsAsString)
            };

            if (!IsNullOrEmpty(workingDirectory))
            {
                objProc.StartInfo.WorkingDirectory = workingDirectory;
            }
            var streamReader = new ProcessStreamReader();

            if (redirectStdErrAndStdOut)
            {
                objProc.StartInfo.UseShellExecute        = false;
                objProc.StartInfo.RedirectStandardOutput = true;
                objProc.StartInfo.RedirectStandardError  = true;
                objProc.StartInfo.CreateNoWindow         = true;
                objProc.OutputDataReceived += streamReader.ReceiveStdOut;
                objProc.ErrorDataReceived  += streamReader.ReceiveStdErr;
            }

            string processDebugInfo = $"Process Details:\r\n\"{exeFileName}\" {argumentsAsString}\r\nWorking Directory: {workingDirectory}";

            Logger.Info($"Starting Process: {processDebugInfo}");
            try
            {
                objProc.Start();
            }
            catch (Exception e)
            {
                var message = $"Program {Path.GetFileName(exeFileName)} got an exception on process start.\r\nException message: {e.Message}\r\n{processDebugInfo}";
                throw new Exception(message, e);
            }

            if (redirectStdErrAndStdOut)
            {
                objProc.BeginOutputReadLine();
                objProc.BeginErrorReadLine();
            }

            var processTimeoutPeriod = (maxTimeoutMs.HasValue) ? TimeSpan.FromMilliseconds(maxTimeoutMs.Value) : MaxTimeout;
            var hasExited            = objProc.WaitForExit(Convert.ToInt32(processTimeoutPeriod.TotalMilliseconds));

            if (!hasExited)
            {
                objProc.Kill();
            }

            if (redirectStdErrAndStdOut)
            {
                // TODO: Fix this so it works without a hacky "Sleep", right now this hack waits for the output to trickle in. The asychronous reads of STDERR and STDOUT may not yet be complete (run unit test under debugger for example) even though the process has exited. -MF & ASW 11/21/2011
                Thread.Sleep(TimeSpan.FromSeconds(.25));
                stdErrAndStdOut = streamReader.StdOutAndStdErr;
            }

            if (!hasExited)
            {
                var message = $"Program {Path.GetFileName(exeFileName)} did not exit within timeout period {processTimeoutPeriod} and was terminated.\r\n{processDebugInfo}\r\nOutput:\r\n{streamReader.StdOutAndStdErr}";
                throw new Exception(message);
            }

            return(new ProcessUtilityResult(objProc.ExitCode, streamReader.StdOut, stdErrAndStdOut));
        }
Ejemplo n.º 9
0
        // ReSharper restore NonLocalizedString

        public static List <string> ConvertPilotFiles(IList <string> inputFiles, IProgressMonitor progress, ProgressStatus status)
        {
            string groupConverterExePath    = null;
            var    inputFilesPilotConverted = new List <string>();

            for (int index = 0; index < inputFiles.Count; index++)
            {
                string inputFile = inputFiles[index];
                if (!inputFile.EndsWith(BiblioSpecLiteBuilder.EXT_PILOT))
                {
                    inputFilesPilotConverted.Add(inputFile);
                    continue;
                }
                string outputFile = Path.ChangeExtension(inputFile, BiblioSpecLiteBuilder.EXT_PILOT_XML);
                // Avoid re-converting files that have already been converted
                if (File.Exists(outputFile))
                {
                    // Avoid duplication, in case the user accidentally adds both .group and .group.xml files
                    // for the same results
                    if (!inputFiles.Contains(outputFile))
                    {
                        inputFilesPilotConverted.Add(outputFile);
                    }
                    continue;
                }

                string message = string.Format(Resources.VendorIssueHelper_ConvertPilotFiles_Converting__0__to_xml, Path.GetFileName(inputFile));
                int    percent = index * 100 / inputFiles.Count;
                progress.UpdateProgress(status = status.ChangeMessage(message).ChangePercentComplete(percent));

                if (groupConverterExePath == null)
                {
                    var key = Registry.LocalMachine.OpenSubKey(KEY_PROTEIN_PILOT, false);
                    if (key != null)
                    {
                        string proteinPilotCommandWithArgs = (string)key.GetValue(string.Empty);

                        var proteinPilotCommandWithArgsSplit =
                            proteinPilotCommandWithArgs.Split(new[] { "\" \"" }, StringSplitOptions.RemoveEmptyEntries);     // Remove " "%1" // Not L10N
                        string path = Path.GetDirectoryName(proteinPilotCommandWithArgsSplit[0].Trim(new[] { '\\', '\"' })); // Remove preceding "
                        if (path != null)
                        {
                            var groupFileExtractorPath = Path.Combine(path, EXE_GROUP_FILE_EXTRACTOR);
                            if (File.Exists(groupFileExtractorPath))
                            {
                                groupConverterExePath = groupFileExtractorPath;
                            }
                            else
                            {
                                var group2XmlPath = Path.Combine(path, EXE_GROUP2_XML);
                                if (File.Exists(group2XmlPath))
                                {
                                    groupConverterExePath = group2XmlPath;
                                }
                                else
                                {
                                    string errorMessage = string.Format(Resources.VendorIssueHelper_ConvertPilotFiles_Unable_to_find__0__or__1__in_directory__2____Please_reinstall_ProteinPilot_software_to_be_able_to_handle__group_files_,
                                                                        EXE_GROUP_FILE_EXTRACTOR, EXE_GROUP2_XML, path);
                                    throw new IOException(errorMessage);
                                }
                            }
                        }
                    }

                    if (groupConverterExePath == null)
                    {
                        throw new IOException(Resources.VendorIssueHelper_ConvertPilotFiles_ProteinPilot_software__trial_or_full_version__must_be_installed_to_convert___group__files_to_compatible___group_xml__files_);
                    }
                }

                // run group2xml
                // ReSharper disable NonLocalizedString
                var argv = new[]
                {
                    "XML",
                    "\"" + inputFile + "\"",
                    "\"" + outputFile + "\""
                };
                // ReSharper restore NonLocalizedString

                var psi = new ProcessStartInfo(groupConverterExePath)
                {
                    CreateNoWindow  = true,
                    UseShellExecute = false,
                    // Common directory includes the directory separator
                    WorkingDirectory       = Path.GetDirectoryName(groupConverterExePath) ?? string.Empty,
                    Arguments              = string.Join(" ", argv.ToArray()),  // Not L10N
                    RedirectStandardError  = true,
                    RedirectStandardOutput = true,
                };

                var sbOut = new StringBuilder();
                var proc  = new Process {
                    StartInfo = psi
                };
                proc.Start();

                var    reader = new ProcessStreamReader(proc);
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    if (progress.IsCanceled)
                    {
                        proc.Kill();
                        throw new LoadCanceledException(status.Cancel());
                    }

                    sbOut.AppendLine(line);
                }

                while (!proc.WaitForExit(200))
                {
                    if (progress.IsCanceled)
                    {
                        proc.Kill();
                        return(inputFilesPilotConverted);
                    }
                }

                if (proc.ExitCode != 0)
                {
                    throw new IOException(TextUtil.LineSeparate(string.Format(Resources.VendorIssueHelper_ConvertPilotFiles_Failure_attempting_to_convert_file__0__to__group_xml_,
                                                                              inputFile), string.Empty, sbOut.ToString()));
                }

                inputFilesPilotConverted.Add(outputFile);
            }
            progress.UpdateProgress(status.ChangePercentComplete(100));
            return(inputFilesPilotConverted);
        }
Ejemplo n.º 10
0
        private static void ConvertBrukerToMzml(string filePathBruker,
                                                string outputPath, IProgressMonitor monitor, ProgressStatus status)
        {
            // We use CompassXport, if it is installed, to convert a Bruker raw file to mzML.  This solves two
            // issues: the Bruker reader can't be called on any thread other than the main thread, and there
            // is no 64-bit version of the reader.  So we start CompassXport in its own 32-bit process,
            // and use it to convert the raw data to mzML in a temporary file, which we read back afterwards.
            var    key             = Registry.LocalMachine.OpenSubKey(KEY_COMPASSXPORT, false);
            string compassXportExe = (key != null) ? (string)key.GetValue(string.Empty) : null;

            if (compassXportExe == null)
            {
                throw new IOException(Resources.VendorIssueHelper_ConvertBrukerToMzml_CompassXport_software_must_be_installed_to_import_Bruker_raw_data_files_);
            }

            // CompassXport arguments
            // ReSharper disable NonLocalizedString
            var argv = new[]
            {
                "-a \"" + filePathBruker + "\"",                    // input file (directory)
                "-o \"" + outputPath + "\"",                        // output file (directory)
                "-mode 2",                                          // mode 2 (mzML)
                "-raw 0"                                            // export line spectra (profile data is HUGE and SLOW!)
            };
            // ReSharper restore NonLocalizedString

            // Start CompassXport in its own process.
            var psi = new ProcessStartInfo(compassXportExe)
            {
                CreateNoWindow  = true,
                UseShellExecute = false,
                // Common directory includes the directory separator
                WorkingDirectory       = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty,
                Arguments              = string.Join(" ", argv), // Not L10N
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };
            var proc = new Process {
                StartInfo = psi
            };

            proc.Start();

            // CompassXport starts by calculating a hash of the input file.  This takes a long time, and there is
            // no intermediate output during this time.  So we set the progress bar some fraction of the way and
            // let it sit there and animate while we wait for the start of spectra processing.
            const int hashPercent = 25; // percentage of import time allocated to calculating the input file hash

            int spectrumCount = 0;

            var    sbOut  = new StringBuilder();
            var    reader = new ProcessStreamReader(proc);
            string line;

            while ((line = reader.ReadLine()) != null)
            {
                if (monitor.IsCanceled)
                {
                    proc.Kill();
                    throw new LoadCanceledException(status.Cancel());
                }

                sbOut.AppendLine(line);
                line = line.Trim();

                // The main part of conversion starts with the hash calculation.
                if (line.StartsWith("Calculating hash")) // Not L10N
                {
                    status = status.ChangeMessage(Resources.VendorIssueHelper_ConvertBrukerToMzml_Calculating_hash_of_input_file)
                             .ChangePercentComplete(hashPercent);
                    monitor.UpdateProgress(status);
                    continue;
                }

                // Determine how many spectra will be converted so we can track progress.
                var match = Regex.Match(line, @"Converting (\d+) spectra"); // Not L10N
                if (match.Success)
                {
                    spectrumCount = int.Parse(match.Groups[1].Value);
                    continue;
                }

                // Update progress as each spectra batch is converted.
                match = Regex.Match(line, @"Spectrum \d+ - (\d+)"); // Not L10N
                if (match.Success)
                {
                    var spectrumEnd     = int.Parse(match.Groups[1].Value);
                    var percentComplete = hashPercent + (100 - hashPercent) * spectrumEnd / spectrumCount;
                    status = status.ChangeMessage(line).ChangePercentComplete(percentComplete);
                    monitor.UpdateProgress(status);
                }
            }

            while (!proc.WaitForExit(200))
            {
                if (monitor.IsCanceled)
                {
                    proc.Kill();
                    throw new LoadCanceledException(status.Cancel());
                }
            }

            if (proc.ExitCode != 0)
            {
                throw new IOException(TextUtil.LineSeparate(string.Format(Resources.VendorIssueHelper_ConvertBrukerToMzml_Failure_attempting_to_convert__0__to_mzML_using_CompassXport_,
                                                                          filePathBruker), string.Empty, sbOut.ToString()));
            }
        }
Ejemplo n.º 11
0
        private static void ConvertLocalWiffToMzxml(string filePathWiff, int sampleIndex,
                                                    string outputPath, IProgressMonitor monitor)
        {
            var argv = new[]
            {
                "--mzXML",                  // Not L10N
                "-s" + (sampleIndex + 1),   // Not L10N
                "\"" + filePathWiff + "\"", // Not L10N
                "\"" + outputPath + "\"",   // Not L10N
            };

            var psi = new ProcessStartInfo(EXE_MZ_WIFF)
            {
                CreateNoWindow  = true,
                UseShellExecute = false,
                // Common directory includes the directory separator
                WorkingDirectory       = Path.GetDirectoryName(filePathWiff) ?? string.Empty,
                Arguments              = string.Join(" ", argv.ToArray()), // Not L10N
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            var sbOut = new StringBuilder();
            var proc  = new Process {
                StartInfo = psi
            };

            proc.Start();

            var    reader = new ProcessStreamReader(proc);
            string line;

            while ((line = reader.ReadLine()) != null)
            {
                if (monitor.IsCanceled)
                {
                    proc.Kill();
                    throw new LoadCanceledException(new ProgressStatus(string.Empty).Cancel());
                }

                sbOut.AppendLine(line);
            }

            while (!proc.WaitForExit(200))
            {
                if (monitor.IsCanceled)
                {
                    proc.Kill();
                    throw new LoadCanceledException(new ProgressStatus(string.Empty).Cancel());
                }
            }

            // Exit code -4 is a compatibility warning but not necessarily an error
            if (proc.ExitCode != 0 && !IsCompatibilityWarning(proc.ExitCode))
            {
                var message = TextUtil.LineSeparate(string.Format(Resources.VendorIssueHelper_ConvertLocalWiffToMzxml_Failure_attempting_to_convert_sample__0__in__1__to_mzXML_to_work_around_a_performance_issue_in_the_AB_Sciex_WiffFileDataReader_library,
                                                                  sampleIndex, filePathWiff),
                                                    string.Empty,
                                                    sbOut.ToString());
                throw new IOException(message);
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// This does a command line from within a cmd.exe process, which we need for at least Headless Chrome. It's a bit awkward,
        /// but hopefully all the messy details are buttoned off in this fuction.
        /// </summary>
        /// <param name="workingDirectory"></param>
        /// <param name="exeFileName"></param>
        /// <param name="commandLineArguments"></param>
        /// <param name="optionalStandardErrorResultStringToWaitFor">If provided, will wait for this string to appear in Standard Error, aborting the timeout.</param>
        /// <param name="maxTimeoutMs">Maximum amount of time to wait in milliseconds after running the exeFileName and its commandLineArguments before shutting down the controlling cmd.exe and returning.</param>
        public static void RunCommandLineLaunchingFromCmdExeWithOptionalTimeout(string workingDirectory,
                                                                                FileInfo exeFileName,
                                                                                List <string> commandLineArguments,
                                                                                string optionalStandardErrorResultStringToWaitFor,
                                                                                int?maxTimeoutMs)
        {
            string argumentsAsString = ConjoinCommandLineArguments(commandLineArguments);
            string fullCommandLine   = $"\"{exeFileName.FullName}\" {argumentsAsString}";
            string stdErrAndStdOut   = string.Empty;

            ProcessStreamReader standardOutputAndErrorStreamReader = new ProcessStreamReader();

            // Start a cmd.exe process
            Logger.Info($"Starting a cmd.exe process");
            Process cmd = new Process();

            cmd.StartInfo.FileName = "cmd.exe";
            cmd.StartInfo.RedirectStandardInput  = true;
            cmd.StartInfo.RedirectStandardOutput = true;
            // Will this cause problems?
            cmd.StartInfo.RedirectStandardError = true;
            cmd.StartInfo.CreateNoWindow        = true;
            cmd.StartInfo.UseShellExecute       = false;
            cmd.OutputDataReceived += standardOutputAndErrorStreamReader.ReceiveStdOut;
            cmd.ErrorDataReceived  += standardOutputAndErrorStreamReader.ReceiveStdErr;
            cmd.Start();

            // Start output streams
            cmd.BeginOutputReadLine();
            cmd.BeginErrorReadLine();

            //Thread.Sleep(50000);

            // Change to working directory
            Logger.Info($"Changing directory in cmd.exe process to working directory {workingDirectory}");
            string cdToWorkingDirectoryCommand = $"cd {workingDirectory}";

            cmd.StandardInput.WriteLine(cdToWorkingDirectoryCommand);

            // Write the command out to the cmd.exe command line
            Logger.Info($"Executing command line in cmd.exe process: {fullCommandLine}");
            cmd.StandardInput.WriteLine(fullCommandLine);
            cmd.StandardInput.Flush();

            DateTime timeStarted     = DateTime.Now;
            bool     messageWasFound = false;

            // If caller specified a timeout, use it to wait before shutting down the cmd.exe process
            if (maxTimeoutMs.HasValue)
            {
                // Check for output every 1/4 second (250 ms)
                const int outputCheckInterval = 250;
                // How many intervals are there in the user's requested delay?
                int numberOfCheckIntervals = maxTimeoutMs.Value / outputCheckInterval;
                // Loop, delaying for the interval, then checking for output
                Logger.Info($"About to loop, waiting for timeout of {maxTimeoutMs.Value} milliseconds, or for optional string (\"{optionalStandardErrorResultStringToWaitFor}\") in standard error output.");
                for (int checkInterval = 0; checkInterval < numberOfCheckIntervals; checkInterval++)
                {
                    //Logger.Info($"Looping, checkInterval {checkInterval} - time elapsed: {checkInterval * outputCheckInterval} ms.");
                    string stdError = standardOutputAndErrorStreamReader.StdErr;
                    if (stdError != "")
                    {
                        Logger.Info($"Standard error output: {stdError}");
                        if (optionalStandardErrorResultStringToWaitFor != null && stdError.Contains(optionalStandardErrorResultStringToWaitFor))
                        {
                            Logger.Info($"Found optional string (\"{optionalStandardErrorResultStringToWaitFor}\") in standard error output: {stdError}");
                            messageWasFound = true;
                            break;
                        }
                    }
                    Thread.Sleep(outputCheckInterval);
                }
            }
            Logger.Info($"Done with any looping, elapsed time: {(DateTime.Now - timeStarted).TotalSeconds} seconds.");
            Logger.Info($"Message was found: {messageWasFound}");

            Logger.Info($"Shutting down cmd.exe process");
            // In the case of this cmd.exe, it's like hitting ^c on the parent process, which would then kill any child processes. However,
            // we have good reason to hope that Chrome is well done by now, and has already exited.
            cmd.StandardInput.Close();
            cmd.WaitForExit();

            // This gives a mingled view with prefixes
            string mingledStandardOutputAndError = standardOutputAndErrorStreamReader.StdOutAndStdErr;

            Logger.Info($"Standard output & error: {mingledStandardOutputAndError}");
        }