Open leonardt opened 5 years ago
I would definitely be open to adding this.
I wrote a very simple version of GLOG once. Here are the files...not sure where you want them to go.
logging_lite.hpp:
// Copyright: Raj Setaluri 2017
// Author: Raj Setaluri (raj.setaluri@gmail.com)
// This file include a lightweight implementation of the glog LOG macro.
#ifndef COMMON_LOG_LOGGING_LITE_HPP_
#define COMMON_LOG_LOGGING_LITE_HPP_
#include <iostream>
enum LogSeverity {
INFO = 0,
FATAL
};
namespace common {
namespace internal {
// LoggerWrapper is a thread safe class.
class LoggerWrapper {
public:
LoggerWrapper() = default;
explicit LoggerWrapper(bool abort) : abort_(abort) {}
bool abort() const { return abort_; }
private:
bool abort_ = false;
};
class Logger {
public:
Logger(bool alive, bool abort) : alive_(alive), abort_(abort) {}
Logger(Logger&& that) : alive_(true), abort_(that.abort_) {
that.alive_ = false;
}
Logger(const Logger& that) = delete;
~Logger() {
if (alive_) {
EndLine();
if (abort_) {
Write("Check failed! aborting.");
EndLine();
abort();
}
}
}
template<typename T>
static void Write(const T& x) { std::cout << x; }
static void EndLine() { std::cout << std::endl; }
private:
bool alive_;
bool abort_;
};
template<typename T> Logger operator<<(Logger&& l, const T& x) {
Logger::Write(x);
return std::move(l);
}
template<typename T> Logger operator<<(LoggerWrapper l, const T& x) {
return std::move(Logger(true, l.abort()) << x);
}
class LoggerVoidify {
public:
LoggerVoidify() {}
template<class T> void operator&(T& x) {}
template<class T> void operator&(T&& x) {}
};
} // namespace internal
} // namespace common
#define LOG(severity) \
::common::internal::LoggerWrapper(severity == FATAL) \
<< __FILE__ << ":" << __LINE__ << " "
#define LOG_IF(severity, condition) \
(!condition) ? ((void) 0) : \
::common::internal::LoggerVoidify() & LOG(severity)
#define CHECK(condition) LOG_IF(FATAL, !(condition))
#ifndef NDEBUG
#define DCHECK(condition) CHECK(condition)
#else // !NDEBUG
#define DCHECK(condition) while(false) CHECK(condition)
#endif // NDEBUG
#endif // COMMON_LOG_LOGGING_LITE_HPP_
Hopefully doesn't depend on c++14...
sample usage:
LOG(INFO) << "some message";
LOG_IF(INFO, true) << "should see this";
LOG_IF(INFO, false) << "shouldn't see this";
CHECK(true) << "shouldn't see this";
CHECK(false) << "should see this and crash!";
One features that would more useful that I use often in Python is a logger hierarchy or namespace. This allows you to set log parameters for specific portions of the code base. For example, it would be nice to configure, say via an environment variable, COREIR_LOG_DEBUG_VERILOG=1
, which would name debug logging just for the verilog backend namespace, but wouldn't turn on debug logging for the entire code base.
How do you achieve that in magma/python? we could likely do something similar if we use scoped objects (or use defer pattern) and a global stack.
In magma.logging
, we define a top level logger
import logging
import os
log = logging.getLogger("magma")
level = os.getenv("MAGMA_LOG_LEVEL", "INFO")
if level in ["DEBUG", "WARN", "INFO"]:
log.setLevel(getattr(logging, level))
elif level is not None:
logging.warning(f"Unsupported value for MAGMA_LOG_LEVEL: {level}")
Then in the coreir backend, we define a child logger
import logging
import os
logger = logging.getLogger('magma').getChild('coreir_backend')
level = os.getenv("MAGMA_COREIR_BACKEND_LOG_LEVEL", "WARN")
# TODO: Factor this with magma.logging code for debug level validation
if level in ["DEBUG", "WARN", "INFO"]:
logger.setLevel(getattr(logging, level))
elif level is not None:
logger.warning("Unsupported value for MAGMA_COREIR_BACKEND_LOG_LEVEL:"
f" {level}")
So we can set MAGMA_LOG_LEVEL=DEBUG
to turn on debug logging everywhere, or MAGMA_COREIR_BACKEND_LOG_LEVEL=DEBUG
to only turn it on in the coreir backend.
The main mechanism is to grabbing logger objects (that have a hierarchy)
logger = logging.getLogger('magma').getChild('coreir_backend')
and then the ability to configure specific objects
logger.setLevel
Then the code in the module only refers to the logger available to them (therefor using the configuration set for the logger that was referenced for that module)
Added by #645
I'd like to add some logging infrastructure so we can more easily develop/debug with something more flexible than using
std::cout
and comments.My initial search reveals: https://github.com/gabime/spdlog as a header file library option.
I have no experience with C++ loggers, so welcome to suggestions.