0

I can redirect both stdout and stderr to logger this way:

./myprog 2>&1 | tee /dev/tty | logger

but I would like to be able to tag each log entry with "myprog-out" and "myprog-err" based on where it came from (stdout and stderr respectively).

I would also like to be able to see both stdout and stderr output on screen.

2

Given that you have features available, you can use process substitution to redirect each stream individually like you would with plain files:

./myprog  > >(logger -t myprog-out)  2> >(tee /dev/tty | logger -t myprog-err)
  • this is very close to what I need, but as-is I only see stderr on screen but not stdout (they both log to syslog as required) – Sparkler Oct 30 '18 at 17:10
1

See https://stackoverflow.com/questions/9112979/pipe-stdout-and-stderr-to-two-different-processes-in-shell-script

You can replace the sed with logger -t tag commands to get them to go into system log files.

Here's what I did with the sample script in the above URL:

#!/bin/bash

foo() {
    echo a
    echo b >&2
    echo c
    echo d >&2
    }

{ foo 2>&1 1>&3 3>&- | logger -t 'my-err'; } 3>&1 1>&2 | logger -t 'my-stdout'

exit 0

Hope this helps

  • this seems to be working too: { ./foo 2>&3 | logger -t my-out; } 3>&1 1>&2 | logger -t my-err. what's the function of 2>&1 1>&3 3>&- in your answer? – Sparkler Oct 30 '18 at 17:07
  • I was following what was in the URL. It was saying you needed to temporarily redirect stdout to a different file descriptor to avoid mixing stderr and stdout. – Lewis M Oct 30 '18 at 17:09
  • any idea how to also still maintain both on screen while logging them? – Sparkler Oct 30 '18 at 17:12
  • You could do a "tee /dev/tty | logger" in lieu of just logger. That might work. – Lewis M Oct 30 '18 at 17:17
0

I was working on the answer below, but came across an issue which may be relevant to the other answers, as well as to problems which don't use logger, with its tag option, so I'll submit my findings.

First, I generated mixed standard output and error messages, with some gaps between them with:

echo abc; sleep 1; echo def >&2; sleep 1; echo ghi; sleep 1; echo jkl >&2

Then I added out: to the front of the standard output messages with:

{ echo abc; sleep 1; echo def >&2; sleep 1; echo ghi; sleep 1; echo jkl >&2; } | \
    sed 's/^/out: /g';

I then added err: to the error stream by adding to all records, then removing the out: strings already added (note that whatever string is used for out: must not start any unmodified error record):

{ { echo abc; sleep 1; echo def >&2; sleep 1; echo ghi; sleep 1; echo jkl >&2; } | \
    sed 's/^/out: /g'; } 2>&1 | sed -e 's/^/err: /g' -e 's/^err: out: /out: /g'

Lewis M's answer suggests that it might be possible to use redirection to stream 3 to avoid the double substitution, but this works fine with the constraint above; however, buffering means that the records are not necessarily recorded in the order in which they were generated, so I finished up with:

stdbuf -i0 -o0 -e0 bash -c \
    "{ { echo abc; sleep 1; echo def >&2; sleep 1; echo ghi; sleep 1; echo jkl >&2; } | \
    sed 's/^/out: /g'; } 2>&1 | sed -e 's/^/err: /g' -e 's/^err: out: /out: /g'" | \
    tee /dev/tty | logger

This runs the previous command in a unbuffered environment, then pipes the output through tee, so that it is seen on the console, then on to the logger.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.