2
\$\begingroup\$

So I'm making a logger for a program and it has 6 levels increasing severity and things I don't think its as memory efficient as it could be but I'm just getting into c++ and memory coding. I feel like if I want to put it in a file I cant view it with a text editor using something like JSON or XML.

This is the code in question

#include <iostream>
#include <fstream>
#include <ctime>

enum class LogLevel { GREY, BLUE, GREEN, YELLOW, ORANGE, RED };

std::ostream& operator<<(std::ostream& os, LogLevel level) {
    switch (level) {
    case LogLevel::GREY:
        os << "GREY";
        break;
    case LogLevel::BLUE:
        os << "BLUE";
        break;
    case LogLevel::GREEN:
        os << "GREEN";
        break;
    case LogLevel::YELLOW:
        os << "YELLOW";
        break;
    case LogLevel::ORANGE:
        os << "ORANGE";
        break;
    case LogLevel::RED:
        os << "RED";
        break;
    default:
        os << "UNKNOWN";
        break;
    }
    return os;
}


class Logger {
private:
    std::ofstream logFile;

    std::string getTimestamp() {
        std::time_t now = std::time(nullptr);
        struct tm timeInfo;
        localtime_s(&timeInfo, &now);

        char timestamp[20];
        std::strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &timeInfo);
        return timestamp;
    }

    std::string getColorCode(LogLevel level) {
        switch (level) {
        case LogLevel::GREY:
            return "\033[90m"; // Grey
        case LogLevel::BLUE:
            return "\033[94m"; // Blue
        case LogLevel::GREEN:
            return "\033[92m"; // Green
        case LogLevel::YELLOW:
            return "\033[93m"; // Yellow
        case LogLevel::ORANGE:
            return "\033[91m"; // Orange
        case LogLevel::RED:
            return "\033[31m"; // Red
        default:
            return "\033[0m"; // Reset color
        }
    }

public:
    Logger(const std::string& filename) {
        logFile.open(filename, std::ios::out | std::ios::app);
    }

    ~Logger() {
        if (logFile.is_open()) {
            logFile.close();
        }
    }

    void log(LogLevel level, const std::string& message) {
        std::string color = getColorCode(level);

        // Print to console with color
        std::cout << getTimestamp() << " " << color << message << "\033[0m" << std::endl;

        // Write to file
        if (logFile.is_open()) {
            logFile << getTimestamp() << " " << message << std::endl;
        }
    }

    void trace(const std::string& message) {
        log(LogLevel::GREY, message);
    }

    void debug(const std::string& message) {
        log(LogLevel::BLUE, message);
    }

    void info(const std::string& message) {
        log(LogLevel::GREEN, message);
    }

    void warn(const std::string& message) {
        log(LogLevel::YELLOW, message);
    }

    void error(const std::string& message) {
        log(LogLevel::ORANGE, message);
    }

    void critical(const std::string& message) {
        log(LogLevel::RED, message);
    }
};
``` 
\$\endgroup\$
3
  • \$\begingroup\$ Note- I haven't added systems like file logging yet. \$\endgroup\$
    – rrandel
    Commented Dec 5, 2023 at 22:10
  • \$\begingroup\$ Youtube just suggested me a video from a chanel called TheCherno. Since you are starting to learn coding and are particularly interested in game development, you might want to check it out. Happy coding!!!. youtube.com/@TheCherno \$\endgroup\$ Commented Dec 9, 2023 at 17:23
  • \$\begingroup\$ Don't write your own logger. Here is a simple one I use. github.com/emilk/loguru \$\endgroup\$ Commented Dec 20, 2023 at 1:07

1 Answer 1

2
\$\begingroup\$

This code does not need a lot of review. You are following most best practices. But, here are a few suggestions. I dont know of any text editors that support colors like this, but you can always use less or cat.

  1. You dont need to explicitly close the file. std::ofstream does that for you.
  2. Add a filename and line number variable to your functions. You can then wrap the function logger functions in a macro and pass FILE and LINE to these variables. This way you can log the location of your messages too.
  3. Provide operator<< overloads for the logger class. Sometimes it is easier to stream messages, specially if they have variables in them.
  4. If you are doing C++20, consider support for std::format.
  5. Consider using std::chrono for time.
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Even better than FILE and LINE: since C++20 you can use std::source_location. \$\endgroup\$
    – G. Sliepen
    Commented Dec 6, 2023 at 13:37
  • \$\begingroup\$ Should I be using C++ 20 cause right now I'm using c++ 17 are there any significant changes i should be aware of before switching? \$\endgroup\$
    – rrandel
    Commented Dec 6, 2023 at 22:15
  • \$\begingroup\$ Since you are just starting now, I does not matter as much. Yes C++20 has a lot of changes. A lot of them are to the parts of the language that is fairly advanced. For begineers, I would say the error messages are nicer. \$\endgroup\$ Commented Dec 7, 2023 at 16:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.