lix/src/libutil/logging.hh

159 lines
3.7 KiB
C++
Raw Normal View History

#pragma once
#include "types.hh"
namespace nix {
typedef enum {
lvlError = 0,
lvlInfo,
lvlTalkative,
lvlChatty,
lvlDebug,
lvlVomit
} Verbosity;
2017-08-14 13:28:16 +00:00
typedef enum {
actUnknown = 0,
2017-08-14 13:28:16 +00:00
actCopyPath = 100,
actDownload = 101,
actRealise = 102,
actCopyPaths = 103,
2017-08-15 13:31:59 +00:00
actBuilds = 104,
actBuild = 105,
actOptimiseStore = 106,
actVerifyPaths = 107,
actSubstitute = 108,
2017-08-14 13:28:16 +00:00
} ActivityType;
typedef enum {
resFileLinked = 100,
resBuildLogLine = 101,
resUntrustedPath = 102,
resCorruptedPath = 103,
resSetPhase = 104,
2017-08-25 19:26:37 +00:00
resProgress = 105,
2017-08-28 12:30:35 +00:00
resSetExpected = 106,
} ResultType;
2017-08-16 14:38:23 +00:00
typedef uint64_t ActivityId;
class Logger
{
friend class Activity;
public:
struct Field
{
// FIXME: use std::variant.
enum { tInt = 0, tString = 1 } type;
uint64_t i = 0;
std::string s;
Field(const std::string & s) : type(tString), s(s) { }
Field(const char * s) : type(tString), s(s) { }
Field(const uint64_t & i) : type(tInt), i(i) { }
};
typedef std::vector<Field> Fields;
virtual ~Logger() { }
virtual void log(Verbosity lvl, const FormatOrString & fs) = 0;
void log(const FormatOrString & fs)
{
log(lvlInfo, fs);
}
2017-04-12 12:53:10 +00:00
virtual void warn(const std::string & msg);
virtual void startActivity(ActivityId act, ActivityType type,
const std::string & s, const Fields & fields, ActivityId parent) { };
2017-08-16 14:38:23 +00:00
virtual void stopActivity(ActivityId act) { };
virtual void result(ActivityId act, ResultType type, const Fields & fields) { };
2017-08-16 14:38:23 +00:00
};
extern thread_local ActivityId curActivity;
2017-08-16 14:38:23 +00:00
struct Activity
{
Logger & logger;
const ActivityId id;
Activity(Logger & logger, ActivityType type, const std::string & s = "",
const Logger::Fields & fields = {}, ActivityId parent = curActivity);
2017-08-16 14:38:23 +00:00
2017-08-21 10:00:41 +00:00
Activity(const Activity & act) = delete;
2017-08-16 14:38:23 +00:00
~Activity()
{ logger.stopActivity(id); }
void progress(uint64_t done = 0, uint64_t expected = 0, uint64_t running = 0, uint64_t failed = 0) const
2017-08-25 19:26:37 +00:00
{ result(resProgress, done, expected, running, failed); }
2017-08-16 14:38:23 +00:00
void setExpected(ActivityType type2, uint64_t expected) const
2017-08-28 12:30:35 +00:00
{ result(resSetExpected, type2, expected); }
template<typename... Args>
2017-08-25 19:26:37 +00:00
void result(ResultType type, const Args & ... args) const
{
Logger::Fields fields;
nop{(fields.emplace_back(Logger::Field(args)), 1)...};
2017-08-25 19:26:37 +00:00
result(type, fields);
}
void result(ResultType type, const Logger::Fields & fields) const
{
logger.result(id, type, fields);
}
2017-08-16 14:38:23 +00:00
friend class Logger;
};
struct PushActivity
{
const ActivityId prevAct;
PushActivity(ActivityId act) : prevAct(curActivity) { curActivity = act; }
~PushActivity() { curActivity = prevAct; }
};
extern Logger * logger;
Logger * makeDefaultLogger();
extern Verbosity verbosity; /* suppress msgs > this */
/* Print a message if the current log level is at least the specified
level. Note that this has to be implemented as a macro to ensure
that the arguments are evaluated lazily. */
#define printMsg(level, args...) \
do { \
if (level <= nix::verbosity) { \
logger->log(level, fmt(args)); \
} \
} while (0)
#define printError(args...) printMsg(lvlError, args)
#define printInfo(args...) printMsg(lvlInfo, args)
#define printTalkative(args...) printMsg(lvlTalkative, args)
#define debug(args...) printMsg(lvlDebug, args)
#define vomit(args...) printMsg(lvlVomit, args)
2017-04-12 12:53:10 +00:00
template<typename... Args>
inline void warn(const std::string & fs, Args... args)
{
boost::format f(fs);
2017-05-11 15:06:07 +00:00
nop{boost::io::detail::feed(f, args)...};
2017-04-12 12:53:10 +00:00
logger->warn(f.str());
}
void warnOnce(bool & haveWarned, const FormatOrString & fs);
void writeToStderr(const string & s);
}