Make your STDERR red
github.com
github.com
gcc stderred.c -D_GNU_SOURCE -Wall -ldl -fPIC -shared -o lib/stderred.dyld
alias stderred='DYLD_INSERT_LIBRARIES=$PWD/lib/stderred.dyld DYLD_FORCE_FLAT_NAMESPACE=1'
stderred python -c 'import os; print "Yo!"; os.write(2, "Jola\n\r")'
(replace $PWD with the absolute path if you're adding this to your shell config, of course)Is there a reason you allocate a bunch of memory and copy the strings rather than just doing multiple writes?
(*lol_write)(fd, STDERR_COLOR, STDERR_COLOR_SIZE);
(*lol_write)(fd, buf, count);
(*lol_write)(fd, COL_RESET, COL_RESET_SIZE);Note that using ordinary write multiple times has atomicity implications - if you have multiple processes writing to STDERR, you might find their output interleaved in unfortunate ways. Using a single write with a temporary buffer or writev avoids this (provided you're not writing more than PIPE_BUF bytes total)
I was more bothered by the use of alloca(). Even on a 32-bit system with a 32-bit size_t, you can blow your stack to hell with a single call to this modified write(). Having to do a full malloc() here would be pretty lame, but as others suggested, writev() should do nicely.
The other nice property of using writev() is that you don't have to bother with the dlopen/dlsym crap. Can just call writev() directly from the overridden write() in either case.
Of course, that doesn't catch people writing to stderr using writev() directly, but I think that's ok. (The current impl doesn't catch that case anyway.)
(edit: pull request submitted! https://github.com/sickill/stderred/pull/6)
http://people.apache.org/~colm/utils/sexec.c
it uses regular select semantics and a trivial state machine to pick the active fd, and has an XML mode - which is convenient for colourising in XHTML (if you want to record an automated process say).
#include <stdio.h>
int main() {
while (1) {
fprintf(stdout, "Hi.\n");
fprintf(stderr, "Hello.\n");
}
return 0;
}
If you run this program directly from the shell, every odd line says Hi and every even line says Hello. But if you run it through sexec (on a Linux machine at least), you get a large block of lines saying Hi, followed by a large block saying Hello, etc. Whether this is a problem or not of course depends on the use case. But to avoid it you need something more sophisticated than just pipes, e.g. the LD_PRELOAD hack in the original post. ./mytest | tee out.txt # blocks of Hello. and Hi.
unbuffer ./mytest | tee out.txt # expected resultI almost think we need another output stream for something that's neither an error nor output of the program.
One nice thing about having only stdout and stderr is it pushes you to ask: "Is this piece of information actually necessary to display to the user or should it just be logged to a file somewhere?" I'm not sure everyone really asks that though. Every time someone shoves a bunch of needless information to stderr "just in case" is a time I have to 2> /dev/null. (At least the useless stuff is often in stderr so I don't have to grep it out of stdout.)
I would love to see a meta stream, that allows you to mark up semantics of stdout/stderr.
How would you go about creating a new standard stream?
# colorize all stderr red exec 2>>(while read line; do print '\e[91m'${(q)line}'\e[0m' > /dev/tty; print -n $'\0'; done &)
works like a charm.
Anyone know why it does that?
I really can't think of a reason that the way tcsh and zsh handle this isn't the proper way. Surely the principle of least surprise applies here.
Also, the write prototype is incorrect (using int instead of size_t) and could break on 64-bit machines.
struct iovec iov[3] = {{STDERR_COLOR, STDERR_COLOR_SIZE},{buf, count},{COL_RESET, COL_RESET_SIZE}};
ssize_t n = 0;
do { n = writev(2, iov, 3);} while (n == -1 && errno == EINTR);
return n;for(i=0;i<1024;i++) close(i); /* close a lot of fd /
/ open will yield the lowest free fds, here it's 0,1,2 /
f=open("inputfile",O_RDONLY);
g=open("outputfile1",O_RDWR|O_CREAT,0666);
h=open("outputfile2",O_RDWR|O_CREAT,0666);
read(f,buf,1024);
write(g,buf,1024);
write(h,buf,1024); / <-- data is colorized! */
Free clue: the world is not a 1960s UNIX terminal. If you don't want to support Windows, that's fine - don't. I'll use something else or write my own. If you DO claim to "work" on Windows, read the goddamn docs and don't just blindly emit escape sequences on std(out|err) because it DOES NOT WORK.
It's not that hard to support Windows console IO, and it's well documented. I've previously written a (commercial) Java native library to provide curses-style character-at-a-time support for Java running in a terminal, using curses on UNIXalikes and a choice of Win32 console or Cygwin curses on Windows, although Cygwin curses at the time didn't correctly recognise Ctrl-Space (makes supporting Emacs keybindings a non-starter). Win32 has a considerably saner console implementation IMO.
This is a libc/LD_PRELOAD hack, so it's clearly a Unix-only solution. Where did all these "you'll break my Windows console" tears come from??
Anyway, if you want to discard the classical model terminal stack, invent something better first. You can't just declare that we should bin it without providing a viable alternative.
As for an API, see (http://msdn.microsoft.com/en-us/library/windows/desktop/ms68...). Java even uses the exact same virtual key codes for AWT KeyEvent. I suspect at some point they were just included from the equivalent Windows header but it's been a while since I looked at the Sun JVM source code.
Anyway, if the windows terminal stuff works for you, then right on. It is not adequate for many of us however. And for that matter, I agree with roel_v that the windows method is much more cumbersome for evenly moderately complicated things.
Edit: Also, delayed interpretation is a fairly common alternative to timing.
While it would be possible to extend Unicode to carry terminal control sequences (or invent yet another standard to do so) my opinion is that having an out-of-band API is better than in-band sequences - most real terminals of the VT100 vintage had BOTH. This is no longer true, and the support for in-band control sequences is a source of much incompatibility. Remember when we replaced termcap with terminfo? Oh how we laughed.
What do you think is missing from the Win32 Console API, out of interest? I ask because I've written cross platform terminal components and ended up using curses on UNIX because that is the only sane way to interact with terminals; hardly a lightweight or even very portable solution, and that's before we start talking about licensing issues.
So really all it gets you boils down (as far as I can tell) to out of band control sequences^. At this point it hardly matters what exactly your control sequence specification is, and the windows Console API essentially becomes the new curses (while inheriting many of the problems of the traditional system, unless you can magically keep everybody in sync).
This simply is not all worth replacing everything to achieve.
And to be blunt, the advantages that out of band control provide quite likely do not outweigh the benefits afforded by in band control for most of us. For example, observe the triviality of the subject of this discussion. Unless you are on the receiving end, I would say it really does make everything easier.
PS: If you use PDCurses then you shouldn't have GPL issues. Sticking to (at least the features provided by) PDCurses will also clear up most portability issues.
^ As an example of what I mean, IIRC you can check out what ssh does when you give it the -t flag. There is some out of band communication in the traditional system after all.
I'm talking about the layer that interprets the in-band escape sequences of actual type-able characters into logical functions (e.g. ESC[4D into "cursor back 4 spaces"), and the databases of long-obsolete hardware quirks that go with it. Replacing that with something closer to the actual keyboards people use (e.g. vt100 didn't HAVE F1-F4 keys, the codes for them are another non-standard area) shouldn't be so dramatic a change, especially when what we think of as remote text terminals these days are typically two fully featured computers running SSH. Perhaps a remote terminal API should just be an SSH protocol extension?
The way I came up with while brainstorming a while ago (never got around to fully implementing it) is to create a PTY wrapper that you can fire off a program with.
Basically it creates a new PTY and wires it up to it's own controlling PTY, and forks of a child under the new one. You can then trivially do a lot of things transparently, like separating stdout and stderr (normally both stdout and stderr would be attached to the slave side of the PTY (/dev/tty), but if you attach them to a different fd then the select on the master/parent side can do things like color them).
EDIT: if it helps you picture it, this is basically doing userland STREAMS ;)
I'd estimate you could do this for around 250 lines of C. Maybe I'll see what I can do after dinner.
Based off jgreco's 'vindication': https://github.com/jgreco/vindication
Usage:
`./redwrapper python -c 'import os; print "Yo!"; os.write(2, "Jola\n\r");'`
`./redwrapper zsh`
(zsh works with it, but bash doesn't currently for some stupid reason. something about what it expecting stderr to be /dev/tty or something I believe).This is rough code, if you want to use regularly/seriously I suggest reviewing the code. I didn't pay attention much to standards compliance, I've only tested on Linux right now. I know that PTY stuff can get hairy on different *nix's, so beware of that.
EDIT: whoops, remove that '-g -lefence' from the Makefile too before you use this.
The following sequence works:
`./redwrapper zsh
`python -c 'import os; print "Yo!"; os.write(2, "Jola\n\r");'`
This is because the values of stderr/stdout are inherited, unless they are purposely overwritten (redirection or anything that allocates it's own PTY (like 'ssh'), both of which of course disables 'red-ification').Anyway, neither of these solutions are something I would ever deploy in an "always on" setup (although it could be done in mine as well). You certainly wouldn't want to do it for your users, so they're always going to have to type something (or mess their shell's init files, which should work for mine as well).
So this is about as transparent to the user as I dare make it. Unfortunately it is not 100% transparent to the programs you are running under it since they can figure out that stderr is not /dev/tty. Nothing seems to care, with the exception of bash, which uses stderr for seemingly everything inexplicably.
That is true. I find it doesn't matter terribly much in practice though. Obviously with some programs it might.
"your output process might not get around to reading its input ends until it has data at both, and then it can't tell which is which."
I'm not quite sure what you mean.
it isn't a horrible mangling of pipes and/or file descriptors, or some custom wrapper script that you have to run before every command, or any of the other frightening ways to do this that i've seen. it's a simple library that you can load or unload easily, that works system wide, without being an impenetrable, unmaintainable mess. as far as these things go, that's clean.
if i do an strace the writes are going to the same file descriptors.. any ideas?
That being said: turning text red is notable? In 2011?
(Will accept downvotes with dignity.)
npm does something like that: http://i.imgur.com/7oBLP.png
static const char PURPLE[] = "\x1b[38;5;129m"
#define STDERR_COLOR PURPLE
Or something more sane: http://www.mudpedia.org/wiki/Xterm_256_colorsMost programs can write data to stdout so they put all messages on stderr. Making it all coloured hides the errors in the rest of the text.
Making errors red, or any other colour, is a good idea. It makes "under-experienced users" notice them.
If the program is mixing "info" level messages and "error" level messages (to use the syslog terms for them) on stderr, there really isn't much we can do about it. The understanding however is that things on stderr are probably things that the user wants to read.
Coloring both of these red shouldn't hide them anymore than coloring both of them white, except now they are both easily discernible from the 'data' coming out of stdout (which is our goal).
Possible aside: the proper way to write/read from the terminal in cases where your stdin/stdout were redirected is to just open up /dev/tty yourself. Any program that does that will not have that text colored by any of the solutions I've seen here.
Here's what I found on how to support LD_PRELOAD without a $LIB dynamic string token:
Looking at this: http://lists.debian.org/debian-devel/2011/12/msg00300.html it seems you could put a relative path in LD_PRELOAD and count on the linker to use architecture-dependent search paths. I'll also link these two threads for context, though they didn't provide answers: http://comments.gmane.org/gmane.comp.lib.glibc.user/974 (chatting) http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=372626 (concatenating the two libs in LD_PRELOAD works, but is noisy).