log.cpp 7.49 KB
/* ****************************************************************************
 * Copyright 2019 Open Systems Development BV                                 *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    *
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        *
 * DEALINGS IN THE SOFTWARE.                                                  *
 * ***************************************************************************/

// std
#include <ios>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>

#include "log.h"
#include "threadcontext.h"

namespace osdev      {
namespace components {
namespace log        {

int toInt( LogLevel level )
{
    switch( level )
    {
    case LogLevel::Emergency:
        return 0;
    case LogLevel::Alert:
        return 1;
    case LogLevel::Critical:
        return 2;
    case LogLevel::Error:
        return 3;
    case LogLevel::Warning:
        return 4;
    case LogLevel::Notice:
        return 5;
    case LogLevel::Info:
        return 6;
    case LogLevel::Debug:
        return 7;
    }
    return -1;
}

std::string     Log::s_context  = std::string();
std::string     Log::s_fileName = std::string();
LogLevel        Log::s_logLevel = LogLevel::Error;
LogMask         Log::s_logMask  = LogMask::None;

std::mutex      Log::m_mutex = std::mutex();

void Log::init( const std::string& context, const std::string& logFile, LogLevel logDepth )
{
    s_logLevel = logDepth;
    s_context = context;

    if ( !logFile.empty() )
    {
        s_fileName = logFile;
    }
}

void Log::terminate()
{
    s_context.clear();
    s_fileName.clear();
    s_logLevel = LogLevel::Debug;
    s_logMask = LogMask::None;
}

void Log::write( const int &priority, const std::string &message, const std::string& context )
{
    switch( s_logMask )
    {
        case LogMask::Mask:
            setlogmask( LOG_MASK( toInt( s_logLevel ) ) );
            break;
        case LogMask::Upto:
            setlogmask( LOG_UPTO( toInt( s_logLevel ) ) );
            break;
        case LogMask::None:
            setlogmask( LOG_UPTO( toInt( LogLevel::Debug ) ) );
            break;
    default:
        break;
    }

    if( !context.empty() )
    {
        s_context = context;
        openlog( s_context.c_str(), LOG_PID, LOG_USER );
    }
    else
    {
        openlog( NULL, LOG_PID, LOG_USER );
    }

    syslog( priority, "%s", message.c_str() );
    closelog();
}

std::string Log::fileinfoMessage( const char* file, int line, const std::string& message )
{
    (void)file;
    (void)line;

//    static const std::string templ("%1:%2| %3");
//    QFileInfo fi(file);
//    return templ.arg( fi.fileName() ).arg(line).arg(message);

    return message;
}

void Log::log( const std::string &category, const std::string &message, LogLevel level )
{
    std::lock_guard<std::mutex> lock(m_mutex);

    std::string logCategory = category;
    std::string logMessage = message;
    if( logMessage.empty() )
    {
        static const std::string emptyMessage( "--" );
        logMessage = emptyMessage;
    }
    else
    {
        // Replace % signs
        ReplaceAll( logMessage, "%", "%%" );
    }

    write( toInt( level ), logCategory, logMessage );
}

// Static functions
void Log::emergency( const char *file, int line, const std::string &category, const std::string &message )
{
    log( category, fileinfoMessage( file, line, message ), LogLevel::Emergency );
}

void Log::alert( const char *file, int line, const std::string &category, const std::string &message )
{
    log( category, fileinfoMessage( file, line, message ), LogLevel::Alert );
}

void Log::critical( const char *file, int line, const std::string &category, const std::string &message )
{
    log( category, fileinfoMessage( file, line, message ), LogLevel::Critical );
}

void Log::error( const char *file, int line, const std::string &category, const std::string &message )
{
    log( category, fileinfoMessage( file, line, message ), LogLevel::Error );
}

void Log::warning( const char *file, int line, const std::string &category, const std::string &message )
{
    log( category, fileinfoMessage( file, line, message ), LogLevel::Warning );
}

void Log::notice( const char *file, int line, const std::string &category, const std::string &message )
{
    log( category, fileinfoMessage( file, line, message ), LogLevel::Notice );
}

void Log::info( const char *file, int line, const std::string &category, const std::string &message )
{
    log( category, fileinfoMessage( file, line, message ), LogLevel::Info );
}

void Log::debug( const char *file, int line, const std::string &category, const std::string &message )
{
    log( category, fileinfoMessage( file, line, message ), LogLevel::Debug );
}

// Protected functions
void Log::emergency( const std::string &category, const std::string &message )
{
    write( toInt( LogLevel::Emergency ), message, category );
}

void Log::alert( const std::string &category, const std::string &message )
{
    write( toInt( LogLevel::Alert ), message, category );
}

void Log::critical( const std::string &category, const std::string &message )
{
    write( toInt( LogLevel::Critical ), message, category );
}

void Log::error( const std::string &category, const std::string &message )
{
    write( toInt( LogLevel::Error ), message, category );
}

void Log::warning( const std::string &category, const std::string &message )
{
    write( toInt( LogLevel::Warning ), message, category );
}

void Log::notice( const std::string &category, const std::string &message )
{
    write( toInt( LogLevel::Notice ), message, category );
}

void Log::info( const std::string &category, const std::string &message )
{
    write( toInt( LogLevel::Info ), message, category );
}

void Log::debug( const std::string &category, const std::string &message )
{
    write( toInt( LogLevel::Debug ), message, category );
}

void Log::ReplaceAll( std::string &strToReplace, const std::string& from_chars, const std::string& to_chars )
{
    size_t start_pos = 0;
    while( ( start_pos = strToReplace.find( from_chars, start_pos ) ) != std::string::npos )
    {
        strToReplace.replace( start_pos, from_chars.length(), to_chars );
        start_pos += to_chars.length(); // Handles case where 'to' is a substring of 'from'
    }
}

}   /* End namespace log          */
}   /* End namespace components   */
}   /* End namespace osdev        */