mirror of
https://github.com/NixOS/nix
synced 2025-07-01 04:18:00 +02:00
Allow separate JSON logging
If the NIX_LOG_FILE environment variable is set, Nix will write JSON log messages to that file in addition to the regular logger (e.g. the progress bar).
This commit is contained in:
parent
8ef94c1114
commit
1f702cdb01
5 changed files with 131 additions and 0 deletions
|
@ -267,6 +267,24 @@ Logger * makeJSONLogger(Descriptor fd)
|
||||||
return new JSONLogger(fd);
|
return new JSONLogger(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger * makeJSONLogger(const std::filesystem::path & path)
|
||||||
|
{
|
||||||
|
struct JSONFileLogger : JSONLogger {
|
||||||
|
AutoCloseFD fd;
|
||||||
|
|
||||||
|
JSONFileLogger(AutoCloseFD && fd)
|
||||||
|
: JSONLogger(fd.get())
|
||||||
|
, fd(std::move(fd))
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
auto fd{toDescriptor(open(path.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0644))};
|
||||||
|
if (!fd)
|
||||||
|
throw SysError("opening log file '%1%'", path);
|
||||||
|
|
||||||
|
return new JSONFileLogger(std::move(fd));
|
||||||
|
}
|
||||||
|
|
||||||
static Logger::Fields getFields(nlohmann::json & json)
|
static Logger::Fields getFields(nlohmann::json & json)
|
||||||
{
|
{
|
||||||
Logger::Fields fields;
|
Logger::Fields fields;
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
#include "file-descriptor.hh"
|
#include "file-descriptor.hh"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -185,8 +187,12 @@ extern Logger * logger;
|
||||||
|
|
||||||
Logger * makeSimpleLogger(bool printBuildLogs = true);
|
Logger * makeSimpleLogger(bool printBuildLogs = true);
|
||||||
|
|
||||||
|
Logger * makeTeeLogger(std::vector<Logger *> loggers);
|
||||||
|
|
||||||
Logger * makeJSONLogger(Descriptor fd);
|
Logger * makeJSONLogger(Descriptor fd);
|
||||||
|
|
||||||
|
Logger * makeJSONLogger(const std::filesystem::path & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param source A noun phrase describing the source of the message, e.g. "the builder".
|
* @param source A noun phrase describing the source of the message, e.g. "the builder".
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -158,6 +158,7 @@ sources = files(
|
||||||
'strings.cc',
|
'strings.cc',
|
||||||
'suggestions.cc',
|
'suggestions.cc',
|
||||||
'tarfile.cc',
|
'tarfile.cc',
|
||||||
|
'tee-logger.cc',
|
||||||
'terminal.cc',
|
'terminal.cc',
|
||||||
'thread-pool.cc',
|
'thread-pool.cc',
|
||||||
'unix-domain-socket.cc',
|
'unix-domain-socket.cc',
|
||||||
|
|
102
src/libutil/tee-logger.cc
Normal file
102
src/libutil/tee-logger.cc
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
#include "logging.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
struct TeeLogger : Logger
|
||||||
|
{
|
||||||
|
std::vector<Logger *> loggers;
|
||||||
|
|
||||||
|
TeeLogger(std::vector<Logger *> loggers)
|
||||||
|
: loggers(std::move(loggers))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
void pause() override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->pause();
|
||||||
|
};
|
||||||
|
|
||||||
|
void resume() override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->resume();
|
||||||
|
};
|
||||||
|
|
||||||
|
void log(Verbosity lvl, std::string_view s) override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->log(lvl, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void logEI(const ErrorInfo & ei) override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->logEI(ei);
|
||||||
|
}
|
||||||
|
|
||||||
|
void startActivity(
|
||||||
|
ActivityId act,
|
||||||
|
Verbosity lvl,
|
||||||
|
ActivityType type,
|
||||||
|
const std::string & s,
|
||||||
|
const Fields & fields,
|
||||||
|
ActivityId parent) override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->startActivity(act, lvl, type, s, fields, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopActivity(ActivityId act) override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->stopActivity(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
void result(ActivityId act, ResultType type, const Fields & fields) override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->result(act, type, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStdout(std::string_view s) override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers) {
|
||||||
|
/* Let only the first logger write to stdout to avoid
|
||||||
|
duplication. This means that the first logger needs to
|
||||||
|
be the one managing stdout/stderr
|
||||||
|
(e.g. `ProgressBar`). */
|
||||||
|
logger->writeToStdout(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<char> ask(std::string_view s) override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers) {
|
||||||
|
auto c = logger->ask(s);
|
||||||
|
if (c)
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPrintBuildLogs(bool printBuildLogs) override
|
||||||
|
{
|
||||||
|
for (auto & logger : loggers)
|
||||||
|
logger->setPrintBuildLogs(printBuildLogs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Logger * makeTeeLogger(std::vector<Logger *> loggers)
|
||||||
|
{
|
||||||
|
return new TeeLogger(std::move(loggers));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -485,6 +485,10 @@ void mainWrapped(int argc, char * * argv)
|
||||||
if (!args.helpRequested && !args.completions) throw;
|
if (!args.helpRequested && !args.completions) throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto logFile = getEnv("NIX_LOG_FILE")) {
|
||||||
|
logger = makeTeeLogger({logger, makeJSONLogger(*logFile)});
|
||||||
|
}
|
||||||
|
|
||||||
if (args.helpRequested) {
|
if (args.helpRequested) {
|
||||||
std::vector<std::string> subcommand;
|
std::vector<std::string> subcommand;
|
||||||
MultiCommand * command = &args;
|
MultiCommand * command = &args;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue