Untitled

 avatar
unknown
plain_text
6 months ago
3.8 kB
7
Indexable
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <map>
#include <memory>
#include <vector>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <filesystem>
#include <zlib.h>  // For gzip compression, external library needed

enum class LogLevel { DEBUG, INFO, WARN, ERROR, FATAL };

std::string getCurrentTimestamp(const std::string& format) {
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);
    std::ostringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), format.c_str());
    return ss.str();
}

class Message {
public:
    std::string content;
    LogLevel level;
    std::string ns;
    std::string timestamp;

    Message(const std::string& content, LogLevel level, const std::string& ns, const std::string& timestamp)
        : content(content), level(level), ns(ns), timestamp(timestamp) {}
};

class Sink {
public:
    virtual ~Sink() = default;
    virtual void log(const Message& message) = 0;
    virtual bool shouldRotate() const { return false; }
    virtual void rotate() {}
};

class FileSink : public Sink {
private:
    std::ofstream logFile;
    std::string filePath;
    size_t maxFileSize;
    size_t currentFileSize;

public:
    FileSink(const std::string& filePath, size_t maxFileSize = 1024 * 1024) 
        : filePath(filePath), maxFileSize(maxFileSize), currentFileSize(0) {
        openLogFile();
    }

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

    void log(const Message& message) override {
        if (shouldRotate()) rotate();
        std::string logEntry = "[" + message.timestamp + "] " + message.content + "\n";
        logFile << logEntry;
        currentFileSize += logEntry.size();
    }

    bool shouldRotate() const override {
        return currentFileSize >= maxFileSize;
    }

    void rotate() override {
        logFile.close();
        for (int i = 2; i >= 0; --i) {
            std::string oldFile = filePath + (i == 0 ? "" : ("." + std::to_string(i) + ".gz"));
            std::string newFile = filePath + "." + std::to_string(i + 1) + ".gz";
            if (std::filesystem::exists(oldFile)) {
                std::filesystem::rename(oldFile, newFile);
            }
        }
        openLogFile();
        currentFileSize = 0;
    }

private:
    void openLogFile() {
        logFile.open(filePath, std::ios::out | std::ios::app);
        if (!logFile.is_open()) {
            throw std::runtime_error("Unable to open log file");
        }
    }
};

class LoggerConfig {
public:
    std::string timestampFormat;
    LogLevel logLevel;
    std::shared_ptr<Sink> sink;

    LoggerConfig(const std::string& tsFormat, LogLevel logLevel, std::shared_ptr<Sink> sink)
        : timestampFormat(tsFormat), logLevel(logLevel), sink(std::move(sink)) {}
};

class Logger {
private:
    LoggerConfig config;

public:
    Logger(const LoggerConfig& config) : config(config) {}

    void log(const std::string& messageContent, LogLevel level, const std::string& ns) {
        if (level >= config.logLevel) {
            std::string timestamp = getCurrentTimestamp(config.timestampFormat);
            Message message(messageContent, level, ns, timestamp);
            config.sink->log(message);
        }
    }
};

int main() {
    try {
        auto fileSink = std::make_shared<FileSink>("/var/log/app/info.log", 1024 * 10); // 10 KB for testing
        LoggerConfig config("ddmmyyyyhhmmss", LogLevel::INFO, fileSink);
        Logger logger(config);

        logger.log("Starting application", LogLevel::INFO, "App");
        logger.log("No user found for the phone number", LogLevel::WARN, "UserModule");

    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}
Editor is loading...
Leave a Comment