Search code examples
c++c++11loggingmingw-w64

I am trying to make a logging framework in c++ but information is not being passed to the logger's subcomponents, what am i doing wrong?


here is my code, when i try running this, main does output the information placed into the LoggerComponent, but not the Logger itself. I don't know why, what could be preventing the logger from passing information into the underlying loggercomponent?

i tried using information from http://www.cplusplus.com/reference/map/map/ and from https://www.geeksforgeeks.org/map-associative-containers-the-c-standard-template-library-stl/

logger.cpp:

#include "logger.hpp"

Logger::Logger(bool verbose, bool fileoutput)
{
    if(verbose)
    {
        LoggerComponent c1(LoggerLevel::DEBUG, &std::cout);
        addLogger (LoggerType::CONSOLE, &c1);
        c1.output (LoggerLevel::DEBUG, "This is the start of console output");
    }
    if(fileoutput)
    {

    }
}

void Logger::output(LoggerLevel level, std::string message)
{
    for(auto& x : components)
    {
        x.second->output (level, message);
    }
}

void Logger::addLogger(LoggerType type, LoggerComponent* component)
{
    if(components.find (type) == components.end ())
        components.emplace(type, component);
}

LoggerComponent* Logger::getLogger (LoggerType type)
{
    if(components.find (type) != components.end ())
        return components.at (type);
    return nullptr;
}

void Logger::clearLoggers()
{
    components.clear ();
}

void Logger::removeLogger(LoggerType type)
{
    if(components.find (type) != components.end ())
        components.erase (type);
}

logger.hpp

#ifndef LOGGER_HPP
#define LOGGER_HPP

#include "loggercomponent.hpp"

#include <map>

enum class LoggerType
{
    CONSOLE,
    FILE
};

class Logger
{
public:
    explicit Logger(bool verbose, bool fileoutput);

    void output(LoggerLevel level, std::string message);

    void addLogger(LoggerType type, LoggerComponent* component);
    void removeLogger(LoggerType type);
    void clearLoggers();
    LoggerComponent* getLogger(LoggerType type);

private:
    std::map<LoggerType, LoggerComponent*> components;
};

#endif // LOGGER_HPP

main.cpp

#include "logger.hpp"

int main()
{
    int* p;
    int i = 5;
    int j = 5;
    p = &i;
    std::cout << p << std::endl;
    p = &j;
    std::cout << p << std::endl;

    LoggerComponent c(LoggerLevel::DEBUG, &std::cout);

    c.output (LoggerLevel::INFO, "Hello World!");
    c.output (LoggerLevel::CRITICAL, "Hello World!");

    Logger c2(true, true);

    std::cout << c.getOutputStream () << std::endl;
    std::cout << c2.getLogger (LoggerType::CONSOLE)->getOutputStream () << std::endl;

    c2.output (LoggerLevel::INFO, "Hello World!");
    c2.output (LoggerLevel::CRITICAL, "Hello World!");
}

loggercomponent.hpp

#ifndef LOGGERCOMPONENT_HPP
#define LOGGERCOMPONENT_HPP

#include <iostream>
#include <string>
#include <ctime>

enum class LoggerLevel
{
    INFO,
    DEBUG,
    WARNING,
    ERROR,
    CRITICAL
};

class LoggerComponent
{
public:
    explicit LoggerComponent(LoggerLevel level, std::ostream* output);

    LoggerLevel getMinimumLevel();
    std::ostream* getOutputStream();
    void setMinimumLevel(LoggerLevel level);
    void setOutputStream(std::ostream* output);

    void output(LoggerLevel level, std::string outputMessage);

private:
    std::string getLevelString(LoggerLevel level);

    LoggerLevel minimumLevel;
    std::ostream* outputStream;
};

#endif // LOGGERCOMPONENT_HPP

loggercomponent.cpp

#include "loggercomponent.hpp"

LoggerComponent::LoggerComponent(LoggerLevel level,
                                 std::ostream* output)
{
    setMinimumLevel (level);
    setOutputStream (output);
}

void LoggerComponent::setMinimumLevel(LoggerLevel level)
{
    if(minimumLevel != level)
        minimumLevel = level;
}

void LoggerComponent::setOutputStream(std::ostream *output)
{
    if(outputStream != output)
        outputStream = output;
}

LoggerLevel LoggerComponent::getMinimumLevel()
{
    return minimumLevel;
}

std::ostream* LoggerComponent::getOutputStream()
{
    return outputStream;
}

std::string LoggerComponent::getLevelString(LoggerLevel level)
{
    switch (level) {
    case LoggerLevel::INFO:
        return "INFO";
    case LoggerLevel::DEBUG:
        return "DEBUG";
    case LoggerLevel::WARNING:
        return "WARNING";
    case LoggerLevel::ERROR:
        return "ERROR";
    case LoggerLevel::CRITICAL:
        return "CRITICAL";
    }
    return nullptr;
}

void LoggerComponent::output(LoggerLevel level, std::string outputMessage)
{
    if(level >= minimumLevel)
    {
        time_t now = time(nullptr);
        *outputStream << ctime(&now)
                      << (getLevelString (level) + " >> " + outputMessage)
                      << std::endl << std::endl;
    }
}

output:

0x60fda8 0x60fdac Tue Oct 01 12:29:14 2019 CRITICAL >> Hello World!

Tue Oct 01 12:29:14 2019 DEBUG >> This is the start of console output

0x6fd0cd00 0x60fdb0


Solution

  • You are storing a pointer to an object local to the constructor (c1) in components. It will be destroyed and the pointer invalid when you try to use it later.

    Store the object itself (or a std::unique_ptr to it if you have a good reason not to store the object itself) in the map instead.