#include <cstdio>
#include <cstdarg>
#include <iostream>

class Logger
{
public:
    Logger(){}
    ~Logger(){}
    
    void info(const char* messageFormat, ...)
    {
        va_list args;
        va_start(args, messageFormat);
        std::string infoFormat = this->format<512>("[INFO] %s", messageFormat).c_str();
        vlog(infoFormat.c_str(), args);
        va_end(args);
    }
    
    void vlog(const char* format, va_list args)
    {
        std::string logMessage = vFormat<512>(format, args);
        std::cout<<logMessage<<std::endl;
    }
    
    template <size_t BufferSize>
    std::string format(const char* format, ...)
    {
        va_list args;
        va_start(args, format);
        std::string message = vFormat<BufferSize>(format, args).c_str();
        va_end(args);
        return message;
    }
    
    template <size_t BufferSize>
    std::string vFormat(const char* format, va_list args)
    {
        char buffer[BufferSize];
        vsprintf(buffer, format, args);
        return std::string(buffer);
    }
};

int main()
{
    Logger log;
    log.info("This is a test with no args!");
    log.info("This is a %s with args!", "test");
    int n = 3;
    double dVal = 22.0/7.0;
    log.info("This is a test with %d args (double: %f, string: '%s')", n, dVal, "testString");
    return 0;
}