Search code examples
cmultithreadingmacosloggingsyslog

OS X asl logging : how to re-direct messages of multi-threaded project into a single file


I've got multi-threaded project where every thread is subject to produce some log messages using asl.

To ease my debug, I've decided to concentrate all those messages on a single separated file (let's call it /tmp/aaa).

Therefore, I've wrapped the standard asl_log method with a call for a lazy c'tor that generate asl_client on the first message created from that thread.

As it can be seen in the code below, I've configured the asl_client messages destination to file /tmp/aaa, by opening that file with write and append attributes.

my question is about keeping this code thread safe. Am I right when making a separate fd(file desc) per thread on the same target file ? I understood that when using the default target file (/var/log/system.log) thread safeness is guaranteed, but is it the case in my scenario.

thanks

#define log_error(fmt, ...)  do { \
    lazy_asl_client_ctor(); \
    log_per_level(ASL_LEVEL_CRIT ,fmt, ##__VA_ARGS__);\
} while (0)

void lazy_asl_client_ctor() {
    if (__improbable(!log_asl_client_get())) {
        // set aslmsg and with a new key named TID (thread-id)
        asl_msg_set((aslmsg*) malloc(sizeof(aslmsg)));
        *asl_msg_get() = asl_new(ASL_TYPE_MSG);
        uint64_t tid;
        pthread_threadid_np(NULL, &tid);
        char tid_str[100];
        sprintf(tid_str,"%llu",tid);
        asl_set(*asl_msg_get(), "TID", tid_str);

        // set log client
        log_asl_client_set((aslclient*) malloc (sizeof(aslclient)));
        *log_asl_client_get() = asl_open(ProcessName(),NULL,ASL_OPT_STDERR);

        // set the file that will receive all thread messages
        int fd = open("/tmp/aaa", O_RDWR | O_CREAT | O_APPEND, 0777);
        asl_add_output_file(*log_asl_client_get(), fd, "$Time $Host $Sender [ $PID : $TID ] $Message",ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_INFO), ASL_ENCODE_SAFE);
    }
}

#define log_per_level(int_level, const_chars_fmt, ...) \
    asl_log(*log_asl_client_get(), *asl_msg_get(), int_level, "[%s] (%s:%d):" const_chars_fmt, \
    SRC_MODULE, __FILENAME__, __LINE__,##__VA_ARGS__)

Solution

  • After some research I've found a neater way to to route logging messages from multiple software components I've made into a separate file :

    asl logs goes to the syslogd which decide what to do with the messages according to pre-defined configuration stated in /etc/asl.conf and /etc/asl/

    To route the messages properly, a new file was added to /etc/asl/ with the following content :

    > traps.log rotate=utc ttl=7 compress file_max=5M all_max=25M mode=0640     
    format=$((Time)(local.6))\ $Host\ $(Sender)[$(PID):$(TID)]\ <$((Level) (str))>:\ $(Message)
    
    ? [= Facility com.paloaltonetworks.traps] [<= Level info] file traps.log
    

    this configuration syntax is explained in the following link : https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/asl.conf.5.html