Как перенаправить ошибку, но не выводить текст и сохранить его в правильном порядке?(F #) - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть две программы, одна из которых запущена другой дочерней.Когда дочерний процесс пишет в stderr, я хочу записать это в родительском процессе, чтобы я мог сказать, была ли ошибка, и затем записать сообщение об ошибке в консоль, как пытался сделать дочерний процесс.

Проблема в том, что дочерний процесс записывает несколько строк текста в стандартный вывод сразу после записи в стандартный поток ошибок.Когда родительский процесс перехватывает сообщения stderr и сам регистрирует их, они записываются параллельно с сообщениями stdout, и текст отображается в неправильном порядке.

Я создал два сценария F # как минимальное воспроизведение этой проблемы.Это скрипт для дочернего процесса:

open System

let logError (x : string) : unit =
    Console.ForegroundColor <- ConsoleColor.Red
    try stderr.WriteLine x
    finally Console.ResetColor ()

let logWarning (x : string) : unit =
    Console.ForegroundColor <- ConsoleColor.Yellow
    try stdout.WriteLine x
    finally Console.ResetColor ()

let logInfo (x : string) : unit =
    Console.ForegroundColor <- ConsoleColor.Green
    try stdout.WriteLine x
    finally Console.ResetColor ()

logError "The quick brown fox jumps over the lazy dog."

logWarning "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc eu est ut arcu finibus iaculis. Maecenas dapibus luctus convallis. Donec tristique accumsan ante sit amet maximus. Sed molestie eros sit amet pretium rhoncus. Sed odio lectus, vestibulum vitae consequat sit amet, eleifend ac augue. Vivamus eros quam, lobortis eget consequat in, pulvinar vel dolor. Sed efficitur fermentum purus eu imperdiet. Mauris posuere, metus nec fringilla accumsan, massa nisi egestas augue, et tristique ligula dolor sit amet nibh. Proin ultricies fermentum tellus, vitae porttitor mauris elementum id. Donec arcu dolor, posuere vel efficitur ultrices, sollicitudin sit amet mauris. Sed eu suscipit leo, in vehicula sem. Morbi congue nibh vitae orci lobortis, gravida volutpat augue imperdiet. Phasellus fringilla arcu ac tellus porttitor mattis. Donec in ante vitae sem varius pulvinar."

logInfo "Nam lorem justo, laoreet ac convallis et, semper et leo. Fusce ornare, risus ut porta tristique, purus lacus ultricies ante, ac semper metus eros quis sapien. Nunc vulputate neque ut efficitur condimentum. Quisque facilisis lacus at lorem condimentum suscipit. Aenean volutpat et dui non pharetra. Pellentesque pretium euismod sollicitudin. Phasellus ullamcorper nulla quis nibh tincidunt consectetur. Nulla gravida finibus mi, sed elementum ligula maximus sed. Ut eu dignissim ex. Nullam vestibulum accumsan ex, ut facilisis elit facilisis scelerisque. Integer pellentesque, sem a molestie porta, tortor felis consectetur lorem, ut interdum lacus mauris vel nisi. Maecenas justo nulla, pharetra at malesuada ac, sollicitudin quis tortor. Integer vehicula, mauris ac tristique vehicula, leo nibh cursus sem, sed rhoncus libero sapien ac tellus."

А это скрипт для родительского процесса:

open System
open System.Diagnostics

let handleErr (args : DataReceivedEventArgs) : unit =
    Console.ForegroundColor <- ConsoleColor.Red
    try stderr.WriteLine args.Data
    finally Console.ResetColor ()

let p = new Process ()
p.StartInfo.FileName <- "fsi"
p.StartInfo.Arguments <- "child.fsx"
p.StartInfo.UseShellExecute <- false
p.StartInfo.RedirectStandardError <- true
p.ErrorDataReceived.Add handleErr
p.Start ()
p.BeginErrorReadLine ()
p.WaitForExit ()

Ожидаемый результат дочернего процесса будет красной линиейза ним следует абзац желтым и, наконец, абзац зеленым.Когда я запускаю дочерний процесс сам по себе, это то, что получает вывод.Но когда я запускаю его через родительский процесс, это происходит: Mangled output

Вы видите, что сообщение об ошибке «Быстрая коричневая лиса перепрыгнула через ленивую собаку».напечатан в середине абзаца, который должен был быть напечатан после него, а цвет переднего плана неправильный.Я попытался найти решение для этого и потерпел неудачу до сих пор, так как ни одна из следующих вещей не будет работать:

  • Используйте блокировки, чтобы разрешить одновременную печать только одной функции на консоли - Это победило 'Это не помогает, потому что функции изолированы в разных процессах, а не только в разных потоках.
  • Redirect stdout и stderr - это делает невозможным сохранение цвета сообщений, записанных в stdout.
  • Объединить stderr с stdout - мне нужен способ различать stderr и stdout, чтобы родительский процесс мог определить, был ли записан stderr.

Есть ли способ в родительском процессе, который я могуопределить, записал ли дочерний процесс запись в stderr, не перенаправляя поток stderr и по-прежнему позволяя дочернему процессу обрабатывать ведение журнала на консоли?

1 Ответ

0 голосов
/ 22 ноября 2018

Типичный способ для родительского процесса узнать, была ли у ребенка ошибка с кодом завершения, когда он отличается от нуля.Кроме этого вам понадобится другой тип межпроцессного взаимодействия.

Я знаю, что вы сказали, что блокировки не будут работать, но на всякий случай я предоставлю вам это возможное решение, которое работает с конкретным сценарием, который вы опубликовали:

Это включает использование MailBoxProcessor для последовательности действий.Сначала некоторые вспомогательные функции:

module Mailbox =

    /// A simple Mailbox processor to serially process Async tasks
    /// use:
    ///      let logThisMsgA = Mailbox.iterA (printfn "%A") (fun msg -> async { printfn "Log: %s" msg } )
    ///      logThisMsgA.Post "message Async"
    ///      
    let iterA hndl f =
        MailboxProcessor.Start(fun inbox ->
            async {
                while true do
                    try       let!   msg = inbox.Receive()
                              do!  f msg
                    with e -> hndl e
            }
        )

    /// A simple Mailbox processor to serially process tasks
    /// use:
    ///      let logThisMsg = Mailbox.iter (printfn "%A") (printfn "Log: %s")
    ///      logThisMsg.Post "message"
    ///      
    let iter hndl f = iterA hndl (fun msg -> async { f msg } )

Вот агент почтового ящика и функция для его вызова:

let sequenceActions = Mailbox.iter (printfn "%A") (fun f -> f() )
let logSeq    f txt = sequenceActions.Post <| fun () -> f txt

, и ваш процесс вызывает функции следующим образом:

logSeq logError   "The quick brown fox jumps over the lazy dog."

logSeq logWarning "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc eu est ut arcu finibus iaculis. Maecenas dapibus luctus convallis. Donec tristique accumsan ante sit amet maximus. Sed molestie eros sit amet pretium rhoncus. Sed odio lectus, vestibulum vitae consequat sit amet, eleifend ac augue. Vivamus eros quam, lobortis eget consequat in, pulvinar vel dolor. Sed efficitur fermentum purus eu imperdiet. Mauris posuere, metus nec fringilla accumsan, massa nisi egestas augue, et tristique ligula dolor sit amet nibh. Proin ultricies fermentum tellus, vitae porttitor mauris elementum id. Donec arcu dolor, posuere vel efficitur ultrices, sollicitudin sit amet mauris. Sed eu suscipit leo, in vehicula sem. Morbi congue nibh vitae orci lobortis, gravida volutpat augue imperdiet. Phasellus fringilla arcu ac tellus porttitor mattis. Donec in ante vitae sem varius pulvinar."

logSeq logInfo    "Nam lorem justo, laoreet ac convallis et, semper et leo. Fusce ornare, risus ut porta tristique, purus lacus ultricies ante, ac semper metus eros quis sapien. Nunc vulputate neque ut efficitur condimentum. Quisque facilisis lacus at lorem condimentum suscipit. Aenean volutpat et dui non pharetra. Pellentesque pretium euismod sollicitudin. Phasellus ullamcorper nulla quis nibh tincidunt consectetur. Nulla gravida finibus mi, sed elementum ligula maximus sed. Ut eu dignissim ex. Nullam vestibulum accumsan ex, ut facilisis elit facilisis scelerisque. Integer pellentesque, sem a molestie porta, tortor felis consectetur lorem, ut interdum lacus mauris vel nisi. Maecenas justo nulla, pharetra at malesuada ac, sollicitudin quis tortor. Integer vehicula, mauris ac tristique vehicula, leo nibh cursus sem, sed rhoncus libero sapien ac tellus."

Надеюсь, это поможет.

...