skip to Main Content

Overly verbose logs produced by 3rd party libraries can be hidden in Swift by setting OS_ACTIVITY_MODE environmnet variable to disable in your run scheme – as shown on the image below.

That silences all NSLog output from your app. I want to disable it only for certain calls. I tried to set the environment variable like this:

setenv("OS_ACTIVITY_MODE", "disable", 1)

And like this

putenv(UnsafeMutablePointer<Int8>(mutating: ("OS_ACTIVITY_MODE=disable" as NSString).utf8String))

The environment is changed as verified by calling print(ProcessInfo.processInfo.environment) but there unlike specifying it in XCode run scheme, the logs are not affected.

Why doesn’t it work and how to fix it?

enter image description here

2

Answers


  1. When you set OS_ACTIVITY_MODE to disable, you disable all log outputs for processes that have access to this environment variable, for example the simulators.

    When you set the value to either info or debug it enables the corresponding logging mode unless it is disabled in the logging preferences for certain log categories.

    So in order to enable only a certain log category, you have to enable OS_ACTIVITY_MODE, that is, set it either to info or debug or leave it at the default, and then disable logging for all other categories.

    For more information how to do this see the man page for log, type man log in the console.

    Get the current log preferences for simulators:

    In the console type:
    xcrun simctl spawn booted log config --status

    That basically means: apply log config -status to all booted simulators.

    This may print the following to your console:

    System mode = INFO STREAM_LIVE PRIVATE_DATA
    

    Get the status for a certain category and subsystem

    xcrun simctl spawn booted log config --status --subsystem com.mycompany.myapp --category network
    

    This may print the below to the console:

    Mode for 'com.mycompany.myapp(network)'  INFO PERSIST_DEFAULT
    

    Get Help

    For help, the tools xcrun simctl and log have nifty man pages and help pages.

    For example:
    type log config --help into the console, it prints:

    usage: log config [options] --mode <modes>
       or: log config [options] --status
       or: log config [options] --reset
    
    description:
        Read or configure settings for the logging system. Configuration
        can act system-wide; or on a subsystem, category, or process level.
    
    options:
        --category <name>             Get/set settings for a given category
        --mode <modes>                Enable given modes
        --process <pid> | <name>      Get/set settings for a given process
        --reset                       Reset settings to defaults
        --status                      Show current settings
        --subsystem <name>            Get/set settings for a given subsystem
    
    modes:
        Modes can be specified as a comma-separated list of key:value pairs.
        Valid keys and their values are:
    
        level                         off | default | info | debug
        persist                       off | default | info | debug
        stream                        live | default
    

    Set the log level for a specific subsystem and category

    xcrun simctl spawn booted log config --mode "level:debug" --subsystem com.mycompany.myapp --category network
    

    Get the status again for this sybsystem and category will print:

    Mode for 'com.mycompany.myapp(network)'  DEBUG PERSIST_DEFAULT
    
    Login or Signup to reply.
  2. Because environment variables are usually read only once, when the program starts.

    In libdispatch 442.1.4, the OS_ACTIVITY_MODE variable is read in _voucher_init to determine a value of an internal variable; _voucher_init is in turn called in libdispatch_init, which is called only once at program startup. Interestingly, I cannot find this code in later versions of the library; perhaps it has been moved somewhere else. But it doesn’t really matter; the same principle applies. Setting the value of an environment variable will usually have no effect on already-initialised code, and can only be used to influence child processes.

    As for solutions, I don’t have an easy one. Personally, I would try finding some method to disable logging in the specific library in question, or to filter the messages out: in the worst case, I’d put a couple of my own NSLog calls with messages controlled by me before and after calls to the library, and tell a filter to ignore everything between the two.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search