Earlier, I could read all stdout/stderr data from applications in Console.app. Since a while, this is not the case anymore (NSLog data is still there, though). I'm on 10.8 now.
There was an earlier similar question from 2010 which doesn't seem up-to-date anymore.
On SU, there is also a similar question which wasn't yet answered.
Has that been changed, i.e. stdout is not supposed to be logged anymore? Or is something broken on my system (from the old SU question, it sounded like that might be the case - although without being helpful)?
Can I somehow change it back?
Prior to Mountain Lion, all processes managed by launchd, including regular applications, had their stdout and stderr file descriptors forwarded to the system log. In Mountain Lion and above, stdout and stderr go nowhere for launchd managed applications. Only messages explicitly sent to the system log will end up there.
If you're writing an application and would like some output to show up in the console, then adopt an API built on syslog(3) or asl(3) instead. NSLog is one such API, and it has the advantage of logging to stderr too so you can easily see your output no matter how you've launched your application. If you'd like that functionality but want to use asl or syslog directly then you'll want to look in to the ASL_OPT_STDERR option to asl_open, and the LOG_PERROR option to openlog respectively.
If you have an old app and want to see stdout or stderr, open the app from Terminal. You can wind your way to the executable and open it from the command line, like in the normal, old world: type the program name. Then the messages will appear on the terminal.
This is not a repudiation of any of the other, better suggestions. It is just a way to get the output without altering the (old) program.
Related
In macOS one can normally get some appreciable console / shell output by executing a process by executing it's binary directly in the Terminal via:
/Applications/SOME_APPLICATION.app/Contents/MacOS/SOME_APPLICATION
This can be very useful from time to time for debugging and catching errors that occur. With the introduction of Catalina (10.15), direct execution of applications in this fashion is discouraged from scripts, etc. and causes various problems, ultimately requiring the use of /usr/bin/open.
How can we redirect STDERR / STDOUT of a process after it's been started?
There has been some discussion on this topic previously for Linux, but it's not clear as to whether some of this will work out for macOS now.
reptyr would be fantastic if it could be repurposed for macOS since it already works mostly for FreeBSD.
This answer is from 2013 but is mostly still relevant.
Prior to Mountain Lion, all processes managed by launchd, including
regular applications, had their stdout and stderr file descriptors
forwarded to the system log. In Mountain Lion and above, stdout and
stderr go nowhere for launchd managed applications. Only messages
explicitly sent to the system log will end up there.
If you're writing an application and would like some output to show up
in the console, then adopt an API built on syslog(3) or asl(3)
instead. NSLog is one such API, and it has the advantage of logging to
stderr too so you can easily see your output no matter how you've
launched your application. If you'd like that functionality but want
to use asl or syslog directly then you'll want to look in to the
ASL_OPT_STDERR option to asl_open, and the LOG_PERROR option to
openlog respectively.
Basically, when you double-click an app (same as /usr/bin/open) there is no stdout/stderr. The dev is expected to send any relevant output/errors to the available logging APIs such as NSLog.
I'm trying to redirect panic/standard error back to bash terminal with the following go code:
if err := syscall.Dup2(-1,int(os.Stderr.Fd())); err != nil {
log.Fatalf("Failed to redirect stderr to bash: %v",err)
}
But the err gives me a "bad file descriptor", probably because of the -1 I used in the first argument. I chose the value -1 because I found that int(file.(*os.File).Fd()) returned a -1 when file.Close() has been called.
As for what I'm trying to do. Elsewhere in my program, I had called a syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())), which logs stderr to an external file. But I want stderr to point to bash terminal on occasion.
https://golang.org/pkg/syscall/ Doesn't give a verbose explanation of syscall.Dup2. I started poking around what file.Fd() returns and how it is used, but also didn't fully understand.
Can anyone tell me how to redirect stderr back to bash terminal?
You have to save the original stderr somewhere before overwriting it with your first Dup2. (In general, it’s a bad idea to use the dup2 feature of closing the target, since it can’t report errors therefrom.) Then you can Dup2 that back to int(os.Stderr.Fd()) (aka 2).
Can anyone tell me how to redirect stderr back to bash terminal?
In general, that is impossible, because a Unix program can be started (or run) without any terminal. For example, it could be started by a crontab(5) job, or thru some at or ssh command, etc. Think also of your program being run with redirections or in a pipeline, or of your program being run in a server (e.g. inside a data center); then it is likely to not have any terminal.
The common practice is for the user of your program to perhaps redirect stderr (and probably not to a terminal, but more likely to some file). Your user would use its shell for that purpose (e.g. run yourprogram 2> /tmp/errorfile; read the documentation of bash about redirections)
Terminals are quite complex stuff. You could read the TTY demystified page. See also pty(7) and termios(3). The usual way to handle terminals (on Unix) is by using the ncurses library (which has been wrapped as goncurses in Go).
Elsewhere in my program, I had called a syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())), which logs stderr to an external file.
That is really a bad idea. Your user expects his/her stderr to stay the same (and would have redirected the stderr in his/her shell if so needed). Conventionally, you should not mess that standard streams in your program (and leave them to what they are).
A file descriptor is some small positive-or-zero index (into the file descriptor table of your process). System calls like dup2(2) are expecting valid file descriptors, and Go's syscall.Dup2 is just wrapping that dup2(2).
On Linux, you can query the file descriptor table of some process of pid 1234 by looking into the /proc/1234/fd/ directory. See proc(5) for more.
If you are absolutely certain that your program is running in a terminal, you might open /dev/tty to get it. See tty(4) for more. However, I don't recommend doing that (because you'll better design your program to be runnable outside of any terminal).
You may want to read some Linux programming book, such as ALP.
For logging purposes, Go provides its log package. See also syslog(3) and the log/syslog package of Go.
PS. I don't know Windows, but I believe it also can start programs without any terminal, e.g. as a background process. So even on Windows I would try to avoid doing that (redirection of stderr to a terminal).
I don't know why, but syscall.Dup2(0,int(os.Stderr.Fd())) returns panic stderr back to terminal.
My understanding of the linux operating system is weak. So I don't understand the significance of 0 in this context and the linux documentation.
Also, I haven't attempted this approach on a windows machine, so not sure what will happen there. I hope other people give better answers.
I'm working on a project using Ogre3D. We recently ported our project to MacOSX but there are some things that were linked to the Windows API. In particular I don't know how this should be translated:
#if defined( __WIN32__ ) || defined( _WIN32 )
AllocConsole();
#endif
It would be nice to port the project under Linux someday, so is there an Unix-compatible way to allocate a console for standard output/input?
Thank you
From UNIX point of view, since I'm not that experienced in Mac-specific development.
A console is "allocated" by default. You cannot order the OS to open a console though. You could tell the IDE you are using to open it in a terminal, or, if it supports that, create your current application as a Console Application, despite using GUI.
What do I mean by saying that console is allocated by default? Each process actually gets its stdin, stdout and stderr (file identifiers 0, 1 and 2) from the calling process. So unless calling process (bash, Finder, whatever) conveniently forgets to leave those open, you always have a console open ... but perhaps invisible?
Easiest way to get a console is to launch the application from Terminal as Finder would do it from GUI. Remember, .apps are actually folders:
/projects/myapp$ ./BuiltApplication.app/Contents/MacOS/BuiltApplication
Finder sets the current working directory to the folder where the .app bundle is located, so the above emulates it all best.
Additionally, take a look at the Console application at /Applications/Utilities/Console.app, included with MacOS. Console is usually used for viewing stdout and stderr. I cannot test this since I'm not on Mac, but I've actually found some sources that say that stdout and stderr should be redirected there. See this post:
You can use Console.app to see the output of applications launched in the normal manner, because the launch infrastructure specifically sends their stdout and stderr there. You can also use the asl routines to query the log, or perform more sophisticated logging if you so desire.
With the application Utilities/Console.app, I can see the console output of applications.
Is there a way to access this log from another application?
To be more specific: I am writing a crashhandler for my application and I want that it attaches the console output to the crash information.
Ah, just found out that there is the file /var/log/system.log which contains those information.
/var/log/system.log was not really a solution because the output didn't immediatly appeared there (which was a big problem because how should my crash handler know that everything is complete there), also the grepping of the related messages was very hackish and then, when I started several instances of the application, I didn't really know about the correct related output (unless I knew the pid but even then, also the pid is not unique).
Know, a solution I am very happy with, is that the application itself is keeping track about all the console output. It is doing that by forking itself and piping its output to the fork and emulating the tee tool there, where one output is a special log file. When it crashes, it sends the filename of the logfile to the crashhandler.
If you are interested, look at the OpenLieroX source code ( http://sourceforge.net/projects/openlierox ).
It used to be that stdout went to the console log, displayed by Console.app. I've been having some problems with a firefox plugin (see other questions, sorry about the spam...) and I was trying to use printfs to at least see if I was STARTING my plugin.
I just noticed today that my console log hasn't been updated since January 6. (Yes, I've been using the machine for the past month.) Now, I'm not the only program that uses the console log, so all those messages must be going SOMEWHERE else.
Does anyone know where?
The problem was that syslogd was broken. It's fixed now.
Solution: the problem wasn't that stdout wasn't going to the console. The problem was that the console wasn't getting written to because syslogd was buggered. Syslogd was being sandboxed for some reason, and so NOTHING had been written to the console since January 6.
the solution was to re-comment out the "uncomment this if you want to sandbox syslogd" section of LaunchDaemons/com.apple.syslogd.plist.
The solution came from superuser.com....
thanks!
printf should be going to the Console.app. It sounds like yours is broken.
A good way to debug your plugin would be to set FireFox as your XCode project's Custom Executable, and run in the debugger. Then the XCode Console would catch the output.
In that case you also just use a breakpoint to see if your plugin was loading instead of printf.
After starting an app and running "lsof | grep <program_name>" it shows file descriptors 0, 1 and 2 are all /dev/null