Skip to content
Snippets Groups Projects
Commit 5f3b3994 authored by Olivier BICHLER's avatar Olivier BICHLER
Browse files

Initial proposal for Aidge::Log system

parent 57dd2c6c
No related branches found
No related tags found
No related merge requests found
......@@ -18,13 +18,15 @@
#include <fmt/format.h>
#include <fmt/ranges.h>
#include "aidge/utils/Log.hpp"
#ifdef NO_EXCEPTION
#define AIDGE_THROW_OR_ABORT(ex, ...) \
do { fmt::print(__VA_ARGS__); std::abort(); } while (false)
do { Aidge::Log::fatal(__VA_ARGS__); std::abort(); } while (false)
#else
#include <stdexcept>
#define AIDGE_THROW_OR_ABORT(ex, ...) \
throw ex(fmt::format(__VA_ARGS__))
do { Aidge::Log::fatal(__VA_ARGS__); throw ex(fmt::format(__VA_ARGS__)); } while (false)
#endif
/**
......@@ -33,7 +35,7 @@ throw ex(fmt::format(__VA_ARGS__))
* If it asserts, it means an user error.
*/
#define AIDGE_ASSERT(stm, ...) \
if (!(stm)) { fmt::print("Assertion failed: " #stm " in {}:{}", __FILE__, __LINE__); \
if (!(stm)) { Aidge::Log::error("Assertion failed: " #stm " in {}:{}", __FILE__, __LINE__); \
AIDGE_THROW_OR_ABORT(std::runtime_error, __VA_ARGS__); }
/**
......
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#ifndef AIDGE_LOG_H_
#define AIDGE_LOG_H_
#include <memory>
#include <fmt/format.h>
#include <fmt/ranges.h>
namespace Aidge {
/**
* Aidge logging class, for displaying and file logging of events.
*/
class Log {
public:
enum Level {
Debug = 0,
Info,
Notice,
Warn,
Error,
Fatal
};
/**
* Detailed messages for debugging purposes, providing information helpful
* for developers to trace and identify issues.
* Detailed insights of what is appening in an operation, not useful for the
* end-user. The operation is performed nominally.
* @note This level is disabled at compile time for Release, therefore
* inducing no runtime overhead for Release.
*/
template <typename... Args>
constexpr static void debug(Args&&... args) {
#ifndef NDEBUG
// only when compiled in Debug
log(Debug, fmt::format(std::forward<Args>(args)...));
#endif
}
/**
* Messages that provide a record of the normal operation, about
* the application's state, progress, or important events.
* Reports normal start, end and key steps in an operation. The operation is
* performed nominally.
*/
template <typename... Args>
constexpr static void info(Args&&... args) {
log(Info, fmt::format(std::forward<Args>(args)...));
}
/**
* Applies to normal but significant conditions that may require monitoring,
* like unusual or normal fallback events.
* Reports specific paths in an operation. The operation can still be
* performed normally.
*/
template <typename... Args>
constexpr static void notice(Args&&... args) {
log(Notice, fmt::format(std::forward<Args>(args)...));
}
/**
* Indicates potential issues or situations that may lead to errors but do
* not necessarily cause immediate problems.
* Some specific steps of the operation could not be performed, but it can
* still provide an exploitable result.
*/
template <typename... Args>
constexpr static void warn(Args&&... args) {
log(Warn, fmt::format(std::forward<Args>(args)...));
}
/**
* Signifies a problem or unexpected condition that the application can
* recover from, but attention is needed to prevent further issues.
* The operation could not be performed, but it does not prevent potentiel
* further operations.
*/
template <typename... Args>
constexpr static void error(Args&&... args) {
log(Error, fmt::format(std::forward<Args>(args)...));
}
/**
* Represents a critical error or condition that leads to the termination of
* the application, indicating a severe and unrecoverable problem.
* The operation could not be performed and any further operation is
* impossible.
*/
template <typename... Args>
constexpr static void fatal(Args&&... args) {
log(Fatal, fmt::format(std::forward<Args>(args)...));
}
/**
* Set the minimum log level displayed in the console.
*/
constexpr static void setConsoleLevel(Level level) {
mConsoleLevel = level;
}
/**
* Set the minimum log level saved in the log file.
*/
constexpr static void setFileLevel(Level level) {
mFileLevel = level;
}
/**
* Set the log file name.
* Close the current log file and open the one with the new file name.
* If empty, stop logging into a file.
*/
static void setFileName(const std::string& fileName) {
if (fileName != mFileName) {
mFileName = fileName;
mFile.release();
if (!fileName.empty()) {
initFile(fileName);
}
}
}
private:
static void log(Level level, const std::string& msg);
static void initFile(const std::string& fileName);
static Level mConsoleLevel;
static Level mFileLevel;
static std::string mFileName;
static std::unique_ptr<FILE, decltype(&std::fclose)> mFile;
};
}
#endif //AIDGE_LOG_H_
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include "aidge/utils/Log.hpp"
#include "aidge/utils/ErrorHandling.hpp"
#include <fmt/color.h>
#include <fmt/chrono.h>
Aidge::Log::Level Aidge::Log::mConsoleLevel = Info;
Aidge::Log::Level Aidge::Log::mFileLevel = Debug;
std::string Aidge::Log::mFileName = "aidge_log.txt";
std::unique_ptr<FILE, decltype(&std::fclose)> Aidge::Log::mFile {nullptr, nullptr};
void Aidge::Log::log(Level level, const std::string& msg) {
if (level >= mConsoleLevel) {
// Apply log level style only for console.
// Styles that were already applied to msg with fmt are kept also in
// the log file.
const auto modifier
= (level == Debug) ? fmt::fg(fmt::color::gray)
: (level == Notice) ? fmt::fg(fmt::color::light_yellow)
: (level == Warn) ? fmt::fg(fmt::color::orange)
: (level == Error) ? fmt::fg(fmt::color::red)
: (level == Fatal) ? fmt::bg(fmt::color::red)
: fmt::text_style();
fmt::println("{}", fmt::styled(msg, modifier));
}
if (level >= mFileLevel && !mFileName.empty()) {
if (!mFile) {
initFile(mFileName);
}
fmt::println(mFile.get(), msg);
}
}
void Aidge::Log::initFile(const std::string& fileName) {
mFile = std::unique_ptr<FILE, decltype(&std::fclose)>(std::fopen(fileName.c_str(), "a"), &std::fclose);
if (!mFile) {
mFileName.clear(); // prevents AIDGE_THROW_OR_ABORT() to try to log into file
AIDGE_THROW_OR_ABORT(std::runtime_error,
"Could not create log file: {}", fileName);
}
const std::time_t t = std::time(nullptr);
fmt::println(mFile.get(), "###### {:%Y-%m-%d %H:%M:%S} ######", fmt::localtime(t));
}
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include <catch2/catch_test_macros.hpp>
#include "aidge/utils/Log.hpp"
#include <fmt/color.h>
using namespace Aidge;
TEST_CASE("[core/log] Log") {
SECTION("TestLog") {
Log::setConsoleLevel(Log::Debug);
Log::debug("debug");
Log::debug("{}", fmt::styled("green debug", fmt::fg(fmt::color::green)));
Log::info("info");
Log::notice("notice");
Log::warn("warn");
Log::error("error");
Log::fatal("fatal");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment