Provides the means to log debug text to various log areas and at various severity levels and send it to a MODSERIAL serial port object for output.

cLogger.cpp

Committer:
paul_harris77
Date:
2017-06-30
Revision:
2:f1b41864f865
Parent:
1:e1be56fa979a

File content as of revision 2:f1b41864f865:

//*********************************************************************************************************************
//   LOGGER LIBRARY - SOURCE FILE
//   PAUL HARRIS, OCTOBER 2016

// *********************************************************************************************************************

#include "cLogger.h"

//Constructor
cLogger::cLogger(MODSERIAL* std_out)
{
    pStdOut = std_out;
    
    pStdOut->baud(38400);
    
    //Register the LOG area as the first log area for use by the cLogger itself
    registerLogArea(LOGGER, ERROR, "LOGGER>> ");
    
    //Register required log areas here and set default log levels:
    registerLogArea(MAIN, NORMAL, "MAIN>>");
    registerLogArea(SYSTEM_CONTROL, DETAILED, "MAIN_CONTROL>>");
    registerLogArea(LIDAR_IF, SUPPRESSED, "LIDAR_IF>>");
    registerLogArea(LIDAR_CONTROL, SUPPRESSED, "LIDAR_CONTROL>>");
    registerLogArea(MOTOR_CONTROL, SUPPRESSED, "MOTOR_CONTROL>>");
    registerLogArea(ENCODER, SUPPRESSED, "ENCODER>>");
    registerLogArea(EVENT, DETAILED, "EVENT>>");
    registerLogArea(OBSERVER, DETAILED, "OBSERVER>>");
    
}

//***********Begin public member functions************

void cLogger::registerLogArea(eLogArea area, eLogLevel defaultLevel, const char* log_prefix)
{
    //Only add if log area not already registered
    if (getLogListIndex(area) <0){
        log_list.push_back(log_t());
        log_list[log_list.size()-1].area = area;
        log_list[log_list.size()-1].level = defaultLevel;
        log_list[log_list.size()-1].prefix = log_prefix;
        
        if(area != LOGGER) //Don't print anything about adding the cLogger area itself (not interested)
        {
            log(LOGGER, NORMAL, "Added new log area with area %s, level %s and prefix %s", sLogArea[log_list[log_list.size()-1].area], sLogLevel[log_list[log_list.size()-1].level], log_list[log_list.size()-1].prefix);
            log(LOGGER, NORMAL, "log_list now has %d entries", log_list.size());
        }
    }
    else{
        log(LOGGER, ERROR, "Attempt to register log area \"%s\" failed: Log area already registered!", sLogArea[area]);
    }
}

void cLogger::log(eLogArea area, eLogLevel text_level, char* log_text, ...)
{
    //******N.B. Don't call the "log" function in any functions that are called as part of log - causes recursion issues!*****
    
    va_list args;
    va_start(args, log_text);
    
    int idx = getLogListIndex(area);
    //If log area fully registered
    if (idx >= 0)
    {
        //Implicitly cast the text log level and area log level to ints for comparison
        int intTextLevel = text_level;
        int intLogAreaLevel = log_list[idx].level;
     
        //Compare the text's log level to the area's current log level to work out if we should print log text
        if((intTextLevel <= intLogAreaLevel) && intLogAreaLevel != SUPPRESSED)
        {
            cLogger::printf(area, log_text, args);
        }
    }
    else //Log area not registered
    {
        log(LOGGER, ERROR, "Attempt to log to an un-registered log area!");  //This doesn't cause log recursion issues...
    }
    
    va_end(args);
}

void cLogger::plainText(char* log_text, ...)
{
    char text_buffer[256];
    
    //Extract arguments
    va_list args;
    va_start(args, log_text);
    
    //Lock the stdio mutex
    stdio_mutex.lock();
    
    //Print formated log text
    vsprintf(text_buffer, log_text, args);
    pStdOut->printf(text_buffer);
    
    //Unlock the stdio mutex
    stdio_mutex.unlock();
}

void cLogger::newLine(void)
{
    pStdOut->printf("\n\r");
}

void cLogger::setLogLevel(eLogArea area, eLogLevel level)
{
    int idx = getLogListIndex(area);
    if (idx >= 0)
    {
        log_list[idx].level = level;
    }
    else
    {
        log(LOGGER, ERROR, "Attempt to set log level of un-registered log area!");
    }
}

void cLogger::setLogPrefix(eLogArea area, const char* log_prefix)
{
    int idx = getLogListIndex(area);
    if (idx >= 0)
    {
        log_list[idx].prefix = log_prefix;
    }
    else
    {
        log(LOGGER, ERROR, "Attempt to set log prefix of un-registered log area!");
    }
}

void cLogger::setAllAreaLevels(eLogLevel level)
{
    for(unsigned i=0; i<log_list.size(); i++)
    {
        log_list[i].level = level;
    }
}


//***********End public member functions************

//***********Begin private member functions************

int cLogger::getLogListIndex(eLogArea area)
{
    int idx;
    bool match_found = false;
    
    for(idx=0; idx<log_list.size(); idx++)
    {
        if(log_list[idx].area == area)
        {
            match_found = true;
            break;
        }
    }
    
    if(match_found)
    {
        return idx;
    }
    else
    {
        return -1;
    }
}

void cLogger::printf(eLogArea area, char* log_text, va_list args)
{
    char text_buffer[256];
    
    int idx = getLogListIndex(area);
    
    if(idx >=0)
    {
        //Lock the stdio mutex
        stdio_mutex.lock();
        
        //Print log area prefix
        pStdOut->printf("%s(0x%02x) ", log_list[idx].prefix, osThreadGetId());

        //Print formated log text
        vsprintf(text_buffer, log_text, args);
        pStdOut->printf(text_buffer);
        
        //New line characters
        pStdOut->printf("\n\r");
        
        //Unlock the stdio mutex
        stdio_mutex.unlock();
    }
    else
    {
        log(LOGGER, ERROR, "Attempt to log to an un-registered log area!"); //This doesn't cause log recursion issues...
    }
}
//***********End private member functions************