Specify stdout/stderr for a System Extension

Before the era of system/network extensions, we could specify stdout/stderr log locations for our daemons which were launched by launchd. Is it possible to do the same with system extensions?

Answered by Systems Engineer in 697425022

Is it possible to do the same with system extensions?

While i'm sure it may be technically still possible to pipe stdout and stderr to a file or other location, I find it much easier to stream logs from the Network System Extension with the os_log API. Something like so usually works for me:


// Objective-C

#import <os/log.h>

@property os_log_t log;

...

_log = os_log_create("com.example.apple-samplecode.MyProject.MySystemExtension", "provider");

...

os_log(self._log, "provider will start");

...

os_log(self._log, "Failed to apply filter settings: %{public}@", error.localizedDescription);

// Swift

let log = OSLog(subsystem: "com.example.apple-samplecode.MyProject.MySystemExtension", category: "provider")

...

os_log(.debug, log: self.log, "provider will start")

if let error = coreError as NSError? {
	os_log(.debug, log: self.log, "provider did not start, core failed, error: %{public}@ / %zd", error.domain, error.code)
}

And then for viewing these logs in the Terminal while your System Extension is running, you can run the commands:

$ log stream --level debug --predicate 'subsystem == "com.example.apple-samplecode.MyProject.MySystemExtension"'
... Lots of output ...
Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Accepted Answer

Is it possible to do the same with system extensions?

While i'm sure it may be technically still possible to pipe stdout and stderr to a file or other location, I find it much easier to stream logs from the Network System Extension with the os_log API. Something like so usually works for me:


// Objective-C

#import <os/log.h>

@property os_log_t log;

...

_log = os_log_create("com.example.apple-samplecode.MyProject.MySystemExtension", "provider");

...

os_log(self._log, "provider will start");

...

os_log(self._log, "Failed to apply filter settings: %{public}@", error.localizedDescription);

// Swift

let log = OSLog(subsystem: "com.example.apple-samplecode.MyProject.MySystemExtension", category: "provider")

...

os_log(.debug, log: self.log, "provider will start")

if let error = coreError as NSError? {
	os_log(.debug, log: self.log, "provider did not start, core failed, error: %{public}@ / %zd", error.domain, error.code)
}

And then for viewing these logs in the Terminal while your System Extension is running, you can run the commands:

$ log stream --level debug --predicate 'subsystem == "com.example.apple-samplecode.MyProject.MySystemExtension"'
... Lots of output ...
Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Thanks @meaton! We are leveraging os_log already but I was curious about stdout/stderr. I'm accepting your answer as an acknowledgement that there's really not a standard way to pipe stdout/stderr for a system extension.

I'm accepting your answer as an acknowledgement that there's really not a standard way to pipe stdout/stderr for a system extension.

The system extension mechanism does not provide this facility. However, a sysex has a main function and so, if you want to redirect stdout and stderr, you can do that at the start of main. For more info, see the dup2 man page.


Having said that, like Matt I encourage you to use the unified logging system for your logging. It has a world of benefits, including:

  • It’s easy to capture with sysdiagnose.

  • It’s integrated with Console and the log tool.

  • It’s configurable, especially on the Mac where you can configure it with either using log config or a configuration profile.

  • It’s architected to minimise your write count, an important feature on modern hardware.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Specify stdout/stderr for a System Extension
 
 
Q