Ronald Oussoren avatar Ronald Oussoren committed 529d3e8

First cut at a solution for issue #77

This unconditionally redirects stdout/stderr to the Console.app
log.

Some more work it needed before release: the streams should only
be redirected when the application is started by the Finder
(LaunchServices), otherwise interactive use isn't possible anymore
(two use cases for that: the testsuite and bundling command-line
tools)

Comments (0)

Files changed (5)

doc/changelog.rst

 py2app 0.7.4
 ------------
 
+- Issue #77: the stdout/stderr streams of application and plugin bundles did not
+  end up in Console.app on OSX 10.8 (as they do on earlier releases of OSX). This
+  is due to a change in OSX.
+
+  With this version the application executable converts writes to the stdout
+  and stderr streams to the ASL logging subsystem with the options needed to
+  end up in the default view of Console.app.
+
+  FIXME: This can break interactive use, futher work is needed to only redirect
+  the streams when the application is started by the Finder.
+
 - The i386, x86_64 and intel stub binaries are now compiled with clang on OSX 10.8,
   instead of an older version of GCC. The other stub versions still are compiled
   on OSX 10.6.
Add a comment to this file

py2app/apptemplate/prebuilt/main-i386

Binary file modified.

Add a comment to this file

py2app/apptemplate/prebuilt/main-intel

Binary file modified.

Add a comment to this file

py2app/apptemplate/prebuilt/main-x86_64

Binary file modified.

py2app/apptemplate/src/main.c

     return rval;
 }
 
-int main(int argc, char * const *argv, char * const *envp)
+void
+setup_asl(const char* appname)
+{
+	/*
+	 * On Mac OS X 10.8 or later the contents of stdout and stderr
+	 * do not end up in de Console.app log (neither in de default
+	 * view or some other view).
+	 *
+	 * This function detects if "asl_log_descriptor" is available
+	 * (introduced in 10.8), and if it is configures ASL to redirect
+	 * all writes to stdout/stderr to the ASL in such a way that
+	 * log lines end up in the default view of Console.app.
+	 */
+
+	/* Function definitions, don't use the ASL header because that
+	 * doesn't contain all definitions when building the binaries
+	 * with PPC support.
+	 */
+	typedef void* aslclient;
+	typedef void* aslmsg;
+
+	aslclient (*do_asl_open)(const char*, const char*, int);
+	int (*do_asl_add_log_file)(aslclient, int);
+	int (*do_asl_log_descriptor)(aslclient, aslmsg, int, int, uint32_t);
+	int (*do_asl_set)(aslmsg, const char*, const char*);
+	aslmsg (*do_asl_new)(int);
+
+	/*
+	 * Try to resolve the ASL function's we're using.
+	 */
+        void* sys_dylib;
+        sys_dylib = dlopen("/usr/lib/libSystem.dylib", RTLD_LAZY);
+
+	do_asl_open = dlsym(sys_dylib, "asl_open");
+	do_asl_add_log_file = dlsym(sys_dylib, "asl_add_log_file");
+	do_asl_log_descriptor = dlsym(sys_dylib, "asl_log_descriptor");
+	do_asl_set = dlsym(sys_dylib, "asl_set");
+	do_asl_new = dlsym(sys_dylib, "asl_new");
+
+	if (do_asl_log_descriptor == NULL) {
+		/* asl_log_descriptor is not available: running on OSX 10.7
+		 * or earlier, which means we can't set up ASL and don't have to
+		 */
+		return;
+	}
+
+	aslclient cl;
+	aslmsg msg;
+	int fd2;
+	char uidbuf[64];
+
+	cl = do_asl_open(appname, "com.apple.console", 2 /* ASL_OPT_NO_DELAY */);
+	if (cl == NULL) {
+		return;
+	}
+
+	/* Tell ASL to write all log lines to STDERR as well, use a dup-ed file
+	 * descriptor because we'll later replace the original one by a file descriptor
+	 * from ASL.
+	 */
+	fd2 = dup(2);
+	do_asl_add_log_file(cl, fd2);
+
+	/*
+	 * Create an ASL template message for the STDOUT/STDERR redirection.
+	 * All keys are required to get log messages into the default view of Console.app
+	 * for normal users.
+	 */
+	snprintf(uidbuf, sizeof(uidbuf), "%d", getuid());
+	msg = do_asl_new(0 /* ASL_TYPE_MSG */);
+	do_asl_set(msg, "Facility" /* ASL_KEY_FACILITY */, "com.apple.console");
+	do_asl_set(msg, "Level" /* ASL_KEY_LEVEL */, "Notice" /* ASL_STRING_NOTICE */);
+	do_asl_set(msg, "ReadUID" /* ASL_KEY_READ_UID */, uidbuf /* or "-1" for "All users" */);
+
+	/*
+	 * Finally: redirect the STDOUT/STDERR file descriptors to ASL.
+	 */
+	do_asl_log_descriptor(cl, msg, 4 /* ASL_LEVEL_NOTICE */, 1, 2 /* ASL_LOG_DESCRIPTOR_WRITE */);
+	do_asl_log_descriptor(cl, msg, 4 /* ASL_LEVEL_NOTICE */, 2, 2 /* ASL_LOG_DESCRIPTOR_WRITE */);
+}
+
+int
+main(int argc, char * const *argv, char * const *envp)
 {
     int rval;
+    const char *bname;
+
+    bname = strrchr(argv[0], '/');
+    if (bname == NULL) {
+	    bname = argv[0];
+    } else {
+	    bname++;
+    }
+
+    setup_asl(bname);
+
     if (bind_CoreFoundation()) {
         fprintf(stderr, "CoreFoundation not found or functions missing\n");
         return -1;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.