Skip to content

Simple Logger #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 18, 2025
95 changes: 95 additions & 0 deletions src/utility/Logger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* @file Logger.cpp
* @author Anand Doshi
* @date 2025-01-08
*
* @copyright Copyright (c) 2025
*
*/


#include "Logger.hpp"
#include <cstdio>
#include <ctime>
#include <iterator>
#include <stdexcept>
#include <string>
#include <string_view>

bool Logger::isLoggable(Level level)
{
if (filter == Filter::quiet)
{
return false;
}

if (filter == Filter::important)
{
return level == Level::error || level == Level::warning || level == Level::severe;
}

if (filter == Filter::verbose)
{
return true;
}

return true; // unknown filter, everything logged
}

constexpr std::string_view Logger::getLevelName(Logger::Level level)
{
switch (level)
{
case Logger::Level::error:
return "error";
case Logger::Level::warning:
return "warning";
case Logger::Level::severe:
return "severe";
case Logger::Level::info:
return "info";
case Logger::Level::fine:
return "fine";
default:
throw std::invalid_argument("Invalid Level enum.");
}
}

void Logger::log(Level level, std::string_view message)
{
if (isLoggable(level))
{

std::time_t now = std::time(nullptr);

char timestamp[std::size(Logger::timestampFormat)];
std::strftime(timestamp, std::size(Logger::timestampFormat),
"%FT%TZ", std::localtime(&now));
logStream << '[' << timestamp << "] " << '(' << name << ") " << '[' << getLevelName(level) << "] " << message << '\n';
}
}

void Logger::error(std::string_view message)
{
log(Level::error, message);
}

void Logger::warning(std::string_view message)
{
log(Level::warning, message);
}

void Logger::severe(std::string_view message)
{
log(Level::severe, message);
}

void Logger::info(std::string_view message)
{
log(Level::info, message);
}

void Logger::fine(std::string_view message)
{
log(Level::fine, message);
}
68 changes: 68 additions & 0 deletions src/utility/Logger.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @file Logger.hpp
* @author Anand Doshi
* @date 2025-01-08
*
* @copyright Copyright (c) 2025
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done some more thinking. I think the logger should be a singleton. We need an instance() public method and the constructor should be protected to prevent initialisation by the user. Then the info, error, ... methods become static methods calling instance().log(...)

*
*/


#include <iostream>
#include <string_view>

class Logger
{
public:
enum class Filter
{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the Filter is overkill. Personally, I would just use a second Level variable. Then you can compare the level of the message being passed in to the level of our Level variable since enum values are just increasing integers.

quiet,
verbose,
important
};

enum class Level
{
error,
warning,
severe,
info,
fine,
};

Logger(std::string_view name)
: Logger{name, Filter::important, std::cout}
{
}

Logger(std::string_view name, Filter filter)
: Logger{name, filter, std::cout}
{
}

Logger(std::string_view name, Filter filter, std::ostream &logStream)
: name{name}, filter{filter}, logStream{logStream}
{
}

void setFilter(Filter filterToSet) { filter = filterToSet; }

void log(Level level, std::string_view message);
void error(std::string_view message);
void warning(std::string_view message);
void severe(std::string_view message);
void info(std::string_view message);
void fine(std::string_view message);

private:
std::string name;
Filter filter;
std::ostream &logStream;

// ISO 8601 date time format
inline static const std::string timestampFormat{"yyyy-mm-ddThh:mm:ssZ"};

bool isLoggable(Level level);

static constexpr std::string_view getLevelName(Level level);
};
Loading