Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2015-01-25

Apple System Log Facility

The Apple System Log facility does not seem to be very wel known, but it is a very useful logging tool. For help during debugging as well as to help users when they encounter problems. Unfortunately apple seems to have forgotten to include ASL in Swift as of Xcode 6.1.1.

Its not too difficult to use ASL from Swift though. It can be done the following way:

Create a file "asl-bridge.h" with the following content:

#import <asl.h>
#import <Foundation/Foundation.h>

#ifndef SwiftFire_asl_bridge_h
#define SwiftFire_asl_bridge_h

int asl_bridge_log_message(int level, NSString *message);


#endif

Then add the implementation "asl-bridge.m":

#import <Foundation/Foundation.h>

#import <asl.h>
#import "asl-bridge.h"

int asl_bridge_log_message(int level, NSString *message) {
    return asl_log_message(level, "%s", [message cStringUsingEncoding:NSUTF8StringEncoding]);

}

In the MyProject-Bridging-Header.h include the following:

#import "asl-bridge.h"
#import <asl.h>

The above includes the ASL headers you need, and provide an interface for the logging function without generating a "unsafe" warning.

Since I don't like how the log levels in objective-c are defined I have also created a more Swifty-er log level enum definition:

enum LogLevel: Int {
    case DEBUG      = 0
    case INFO       = 1
    case NOTICE     = 2
    case WARNING    = 3
    case ERROR      = 4
    case CRITICAL   = 5
    case ALERT      = 6
    case EMERGENCY  = 7
    case NONE       = 8
    func toString() -> String {
        switch self {
        case .DEBUG:     return "DEBUG    "
        case .INFO:      return "INFO     "
        case .NOTICE:    return "NOTICE   "
        case .WARNING:   return "WARNING  "
        case .ERROR:     return "ERROR    "
        case .CRITICAL:  return "CRITICAL "
        case .ALERT:     return "ALERT    "
        case .EMERGENCY: return "EMERGENCY"
        case .NONE:      return "NONE     "
        }
    }
    func toAslLevel() -> Int32 {
        switch self {
        case .DEBUG:     return 7
        case .INFO:      return 6
        case .NOTICE:    return 5
        case .WARNING:   return 4
        case .ERROR:     return 3
        case .CRITICAL:  return 2
        case .ALERT:     return 1
        case .EMERGENCY: return 0
        case .NONE:      return -1
        }
    }
}

Finally we get to define the function I actually use for logging:

    private func logAslFacility(level: LogLevel, message: String) {
        asl_bridge_log_message(level.toAslLevel(), message)
    }

Edit: See also part 2

Added 2015-05-08: To see the above in action (and more), check out my github project "SwifterLog" in the upper right corner of this page.

Happy coding

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

2 comments:

  1. I commented saying "Where do I see the logs?" but figured out that the Console app was filtering out logs with levels lower than Warning. Hmm, we need to add more Swift API to set the filter level.. :-)

    ReplyDelete
  2. Hi Andrew, see also part 2 of this post (link at the bottom of the article). There I wrote that Apple will by default filter out the levels "DEBUG" and "INFO". You can see this in the ASL configuration file located in: /etc/asl.conf
    If you want to see those levels, you have to edit that file.

    Also note that I have made SwifterLog (link in the upper right corner). When you use that, you get a "Swifter" interface to the ASL, but also can redirect output to the Xcode console or into a file.

    ReplyDelete