forked from lix-project/lix
Compare commits
6 commits
main
...
jade/loggi
Author | SHA1 | Date | |
---|---|---|---|
jade | 6e34a4d30f | ||
jade | cf5df9bc4a | ||
jade | 14e390e679 | ||
jade | 25c0f18b9f | ||
jade | c40c572e52 | ||
jade | 2c60ac102a |
|
@ -222,7 +222,8 @@ brotli = [
|
||||||
|
|
||||||
openssl = dependency('libcrypto', 'openssl', required : true)
|
openssl = dependency('libcrypto', 'openssl', required : true)
|
||||||
|
|
||||||
aws_sdk = dependency('aws-cpp-sdk-core', required : false)
|
# FIXME: confirm we actually support such old versions of aws-sdk-cpp
|
||||||
|
aws_sdk = dependency('aws-cpp-sdk-core', required : false, version : '>=1.8')
|
||||||
aws_sdk_transfer = dependency('aws-cpp-sdk-transfer', required : aws_sdk.found(), fallback : ['aws_sdk', 'aws_cpp_sdk_transfer_dep'])
|
aws_sdk_transfer = dependency('aws-cpp-sdk-transfer', required : aws_sdk.found(), fallback : ['aws_sdk', 'aws_cpp_sdk_transfer_dep'])
|
||||||
if aws_sdk.found()
|
if aws_sdk.found()
|
||||||
# The AWS pkg-config adds -std=c++11.
|
# The AWS pkg-config adds -std=c++11.
|
||||||
|
@ -234,12 +235,6 @@ if aws_sdk.found()
|
||||||
links : true,
|
links : true,
|
||||||
sources : true,
|
sources : true,
|
||||||
)
|
)
|
||||||
s = aws_sdk.version().split('.')
|
|
||||||
configdata += {
|
|
||||||
'AWS_VERSION_MAJOR': s[0].to_int(),
|
|
||||||
'AWS_VERSION_MINOR': s[1].to_int(),
|
|
||||||
'AWS_VERSION_PATCH': s[2].to_int(),
|
|
||||||
}
|
|
||||||
aws_sdk_transfer = aws_sdk_transfer.partial_dependency(
|
aws_sdk_transfer = aws_sdk_transfer.partial_dependency(
|
||||||
compile_args : false,
|
compile_args : false,
|
||||||
includes : true,
|
includes : true,
|
||||||
|
|
|
@ -60,7 +60,7 @@ static bool allSupportedLocally(Store & store, const std::set<std::string>& requ
|
||||||
static int main_build_remote(int argc, char * * argv)
|
static int main_build_remote(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
logger = makeJSONLogger(*logger);
|
logger.replace(makeJSONLogger(*logger));
|
||||||
|
|
||||||
/* Ensure we don't get any SSH passphrase or host key popups. */
|
/* Ensure we don't get any SSH passphrase or host key popups. */
|
||||||
unsetenv("DISPLAY");
|
unsetenv("DISPLAY");
|
||||||
|
|
|
@ -20,14 +20,14 @@ LogFormat parseLogFormat(const std::string & logFormatStr) {
|
||||||
throw Error("option 'log-format' has an invalid value '%s'", logFormatStr);
|
throw Error("option 'log-format' has an invalid value '%s'", logFormatStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger * makeDefaultLogger() {
|
std::shared_ptr<Logger> makeDefaultLogger() {
|
||||||
switch (defaultLogFormat) {
|
switch (defaultLogFormat) {
|
||||||
case LogFormat::raw:
|
case LogFormat::raw:
|
||||||
return makeSimpleLogger(false);
|
return makeSimpleLogger(false);
|
||||||
case LogFormat::rawWithLogs:
|
case LogFormat::rawWithLogs:
|
||||||
return makeSimpleLogger(true);
|
return makeSimpleLogger(true);
|
||||||
case LogFormat::internalJSON:
|
case LogFormat::internalJSON:
|
||||||
return makeJSONLogger(*makeSimpleLogger(true));
|
return makeJSONLogger(makeSimpleLogger(true));
|
||||||
case LogFormat::bar:
|
case LogFormat::bar:
|
||||||
return makeProgressBar();
|
return makeProgressBar();
|
||||||
case LogFormat::barWithLogs: {
|
case LogFormat::barWithLogs: {
|
||||||
|
@ -50,7 +50,7 @@ void setLogFormat(const LogFormat & logFormat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void createDefaultLogger() {
|
void createDefaultLogger() {
|
||||||
logger = makeDefaultLogger();
|
logger.replace(makeDefaultLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include "progress-bar.hh"
|
#include "progress-bar.hh"
|
||||||
|
#include "file-system.hh"
|
||||||
|
#include "strings.hh"
|
||||||
#include "sync.hh"
|
#include "sync.hh"
|
||||||
#include "store-api.hh"
|
|
||||||
#include "names.hh"
|
#include "names.hh"
|
||||||
#include "terminal.hh"
|
#include "terminal.hh"
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -119,7 +119,18 @@ public:
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto state(state_.lock());
|
auto state(state_.lock());
|
||||||
if (!state->active) return;
|
if (!state->active) {
|
||||||
|
// Unlock immediately so we don't deadlock.
|
||||||
|
{
|
||||||
|
auto _ = std::move(state);
|
||||||
|
}
|
||||||
|
// Even if the thread is inactive, the handle needs to be
|
||||||
|
// explicitly joined to not call terminate if it is destructed.
|
||||||
|
if (updateThread.joinable()) {
|
||||||
|
updateThread.join();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
state->active = false;
|
state->active = false;
|
||||||
writeToStderr("\r\e[K");
|
writeToStderr("\r\e[K");
|
||||||
updateCV.notify_one();
|
updateCV.notify_one();
|
||||||
|
@ -531,19 +542,19 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger * makeProgressBar()
|
std::shared_ptr<Logger> makeProgressBar()
|
||||||
{
|
{
|
||||||
return new ProgressBar(shouldANSI());
|
return std::make_shared<ProgressBar>(shouldANSI());
|
||||||
}
|
}
|
||||||
|
|
||||||
void startProgressBar()
|
void startProgressBar()
|
||||||
{
|
{
|
||||||
logger = makeProgressBar();
|
logger.replace(makeProgressBar());
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopProgressBar()
|
void stopProgressBar()
|
||||||
{
|
{
|
||||||
auto progressBar = dynamic_cast<ProgressBar *>(logger);
|
auto progressBar = dynamic_cast<ProgressBar *>(&**logger);
|
||||||
if (progressBar) progressBar->stop();
|
if (progressBar) progressBar->stop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
Logger * makeProgressBar();
|
std::shared_ptr<Logger> makeProgressBar();
|
||||||
|
|
||||||
void startProgressBar();
|
void startProgressBar();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace nix {
|
||||||
|
|
||||||
void commonChildInit()
|
void commonChildInit()
|
||||||
{
|
{
|
||||||
logger = makeSimpleLogger();
|
logger.replace(makeSimpleLogger());
|
||||||
|
|
||||||
const static std::string pathNullDevice = "/dev/null";
|
const static std::string pathNullDevice = "/dev/null";
|
||||||
restoreProcessContext(false);
|
restoreProcessContext(false);
|
||||||
|
|
|
@ -873,9 +873,9 @@ void DerivationGoal::cleanupPostOutputsRegisteredModeNonCheck()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void runPostBuildHook(
|
static void runPostBuildHook(
|
||||||
Store & store,
|
Store & store,
|
||||||
Logger & logger,
|
std::shared_ptr<Logger> logger,
|
||||||
const StorePath & drvPath,
|
const StorePath & drvPath,
|
||||||
const StorePathSet & outputPaths)
|
const StorePathSet & outputPaths)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2156,7 +2156,7 @@ void LocalDerivationGoal::runChild()
|
||||||
/* Execute the program. This should not return. */
|
/* Execute the program. This should not return. */
|
||||||
if (drv->isBuiltin()) {
|
if (drv->isBuiltin()) {
|
||||||
try {
|
try {
|
||||||
logger = makeJSONLogger(*logger);
|
logger.replace(makeJSONLogger(*logger));
|
||||||
|
|
||||||
BasicDerivation & drv2(*drv);
|
BasicDerivation & drv2(*drv);
|
||||||
for (auto & e : drv2.env)
|
for (auto & e : drv2.env)
|
||||||
|
|
|
@ -263,7 +263,7 @@ struct ClientSettings
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void performOp(TunnelLogger * logger, ref<Store> store,
|
static void performOp(std::shared_ptr<TunnelLogger> logger, ref<Store> store,
|
||||||
TrustedFlag trusted, RecursiveFlag recursive, WorkerProto::Version clientVersion,
|
TrustedFlag trusted, RecursiveFlag recursive, WorkerProto::Version clientVersion,
|
||||||
Source & from, BufferedSink & to, WorkerProto::Op op)
|
Source & from, BufferedSink & to, WorkerProto::Op op)
|
||||||
{
|
{
|
||||||
|
@ -1014,11 +1014,11 @@ void processConnection(
|
||||||
if (clientVersion < 0x10a)
|
if (clientVersion < 0x10a)
|
||||||
throw Error("the Nix client version is too old");
|
throw Error("the Nix client version is too old");
|
||||||
|
|
||||||
auto tunnelLogger = new TunnelLogger(to, clientVersion);
|
auto tunnelLogger = std::make_shared<TunnelLogger>(to, clientVersion);
|
||||||
auto prevLogger = nix::logger;
|
auto prevLogger = *nix::logger;
|
||||||
// FIXME
|
// FIXME
|
||||||
if (!recursive)
|
if (!recursive)
|
||||||
logger = tunnelLogger;
|
prevLogger = nix::logger.replace(tunnelLogger);
|
||||||
|
|
||||||
unsigned int opCount = 0;
|
unsigned int opCount = 0;
|
||||||
|
|
||||||
|
|
|
@ -55,12 +55,14 @@ class AwsLogger : public Aws::Utils::Logging::FormattedLogSystem
|
||||||
|
|
||||||
void ProcessFormattedStatement(Aws::String && statement) override
|
void ProcessFormattedStatement(Aws::String && statement) override
|
||||||
{
|
{
|
||||||
|
// FIXME: workaround for truly excessive log spam in debug level: https://github.com/aws/aws-sdk-cpp/pull/3003
|
||||||
|
if ((statement.find("(SSLDataIn)") != std::string::npos || statement.find("(SSLDataOut)") != std::string::npos) && verbosity <= lvlDebug) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
debug("AWS: %s", chomp(statement));
|
debug("AWS: %s", chomp(statement));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !(AWS_VERSION_MAJOR <= 1 && AWS_VERSION_MINOR <= 7 && AWS_VERSION_PATCH <= 115)
|
|
||||||
void Flush() override {}
|
void Flush() override {}
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void initAWS()
|
static void initAWS()
|
||||||
|
@ -100,12 +102,7 @@ S3Helper::S3Helper(
|
||||||
: std::dynamic_pointer_cast<Aws::Auth::AWSCredentialsProvider>(
|
: std::dynamic_pointer_cast<Aws::Auth::AWSCredentialsProvider>(
|
||||||
std::make_shared<Aws::Auth::ProfileConfigFileAWSCredentialsProvider>(profile.c_str())),
|
std::make_shared<Aws::Auth::ProfileConfigFileAWSCredentialsProvider>(profile.c_str())),
|
||||||
*config,
|
*config,
|
||||||
// FIXME: https://github.com/aws/aws-sdk-cpp/issues/759
|
|
||||||
#if AWS_VERSION_MAJOR == 1 && AWS_VERSION_MINOR < 3
|
|
||||||
false,
|
|
||||||
#else
|
|
||||||
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never,
|
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never,
|
||||||
#endif
|
|
||||||
endpoint.empty()))
|
endpoint.empty()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -792,17 +792,31 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m
|
||||||
|
|
||||||
auto doQuery = [&](const StorePath & path) {
|
auto doQuery = [&](const StorePath & path) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
auto state(state_.lock());
|
|
||||||
|
bool exists = false;
|
||||||
|
std::optional<std::exception_ptr> newExc;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto info = queryPathInfo(path);
|
queryPathInfo(path);
|
||||||
state->valid.insert(path);
|
exists = true;
|
||||||
} catch (InvalidPath &) {
|
} catch (InvalidPath &) {
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
state->exc = std::current_exception();
|
newExc = std::current_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto state(state_.lock());
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
state->valid.insert(path);
|
||||||
|
}
|
||||||
|
if (newExc.has_value()) {
|
||||||
|
state->exc = *newExc;
|
||||||
}
|
}
|
||||||
assert(state->left);
|
assert(state->left);
|
||||||
if (!--state->left)
|
if (!--state->left)
|
||||||
wakeup.notify_one();
|
wakeup.notify_one();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto & path : paths)
|
for (auto & path : paths)
|
||||||
|
@ -1163,22 +1177,27 @@ std::map<StorePath, StorePath> copyPaths(
|
||||||
ValidPathInfo infoForDst = *info;
|
ValidPathInfo infoForDst = *info;
|
||||||
infoForDst.path = storePathForDst;
|
infoForDst.path = storePathForDst;
|
||||||
|
|
||||||
auto source = sinkToSource([&](Sink & sink) {
|
auto source =
|
||||||
|
sinkToSource([&srcStore, &dstStore, missingPath = missingPath, info = std::move(info)](Sink & sink) {
|
||||||
// We can reasonably assume that the copy will happen whenever we
|
// We can reasonably assume that the copy will happen whenever we
|
||||||
// read the path, so log something about that at that point
|
// read the path, so log something about that at that point
|
||||||
auto srcUri = srcStore.getUri();
|
auto srcUri = srcStore.getUri();
|
||||||
auto dstUri = dstStore.getUri();
|
auto dstUri = dstStore.getUri();
|
||||||
auto storePathS = srcStore.printStorePath(missingPath);
|
auto storePathS = srcStore.printStorePath(missingPath);
|
||||||
Activity act(*logger, lvlInfo, actCopyPath,
|
Activity act(
|
||||||
|
*logger,
|
||||||
|
lvlInfo,
|
||||||
|
actCopyPath,
|
||||||
makeCopyPathMessage(srcUri, dstUri, storePathS),
|
makeCopyPathMessage(srcUri, dstUri, storePathS),
|
||||||
{storePathS, srcUri, dstUri});
|
{storePathS, srcUri, dstUri}
|
||||||
|
);
|
||||||
PushActivity pact(act.id);
|
PushActivity pact(act.id);
|
||||||
|
|
||||||
LambdaSink progressSink([&, total = 0ULL](std::string_view data) mutable {
|
LambdaSink progressSink([&, total = 0ULL](std::string_view data) mutable {
|
||||||
total += data.size();
|
total += data.size();
|
||||||
act.progress(total, info->narSize);
|
act.progress(total, info->narSize);
|
||||||
});
|
});
|
||||||
TeeSink tee { sink, progressSink };
|
TeeSink tee{sink, progressSink};
|
||||||
|
|
||||||
srcStore.narFromPath(missingPath, tee);
|
srcStore.narFromPath(missingPath, tee);
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,8 +26,6 @@ void setCurActivity(const ActivityId activityId)
|
||||||
curActivity = activityId;
|
curActivity = activityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger * logger = makeSimpleLogger(true);
|
|
||||||
|
|
||||||
void Logger::warn(const std::string & msg)
|
void Logger::warn(const std::string & msg)
|
||||||
{
|
{
|
||||||
log(lvlWarn, ANSI_WARNING "warning:" ANSI_NORMAL " " + msg);
|
log(lvlWarn, ANSI_WARNING "warning:" ANSI_NORMAL " " + msg);
|
||||||
|
@ -108,6 +106,38 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// XXX: We have to leak this so that we can not destroy the damned thing on
|
||||||
|
// shutdown because of destructor ordering. Bad evil horrible.
|
||||||
|
LoggerWrapper &logger = *(new LoggerWrapper(makeSimpleLogger(true)));
|
||||||
|
|
||||||
|
class NullLogger : public Logger
|
||||||
|
{
|
||||||
|
void log(Verbosity lvl, std::string_view s) override {}
|
||||||
|
|
||||||
|
void logEI(const ErrorInfo & ei) override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
Logger * globalNullLogger = new NullLogger();
|
||||||
|
Logger * globalSimpleLogger = new SimpleLogger(false);
|
||||||
|
|
||||||
|
[[gnu::destructor(65535)]]
|
||||||
|
void switchToShutdownLogger()
|
||||||
|
{
|
||||||
|
static auto dontDelete = [](auto d) {};
|
||||||
|
|
||||||
|
// XXX: Replace the logger with a global logger that is leaked at the end of the process
|
||||||
|
// This is so that custom loggers with meaningful destructors are guaranteed to actually be destroyed.
|
||||||
|
// Genuinely I am so sorry for this code.
|
||||||
|
//
|
||||||
|
// If there's a tty on the other end, we assume it's probably ok if the log
|
||||||
|
// format regresses to basic, and we consider it more important that the
|
||||||
|
// logs get out at all.
|
||||||
|
//
|
||||||
|
// FIXME: Replace this madness with explicitly passing around a shared
|
||||||
|
// pointer to const LoggerWrapper, because holy cow globals are broken.
|
||||||
|
logger.replace(std::shared_ptr<Logger>(isatty(STDERR_FILENO) ? globalSimpleLogger : globalNullLogger, dontDelete));
|
||||||
|
}
|
||||||
|
|
||||||
Verbosity verbosity = lvlInfo;
|
Verbosity verbosity = lvlInfo;
|
||||||
|
|
||||||
void writeToStderr(std::string_view s)
|
void writeToStderr(std::string_view s)
|
||||||
|
@ -122,18 +152,18 @@ void writeToStderr(std::string_view s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger * makeSimpleLogger(bool printBuildLogs)
|
std::shared_ptr<Logger> makeSimpleLogger(bool printBuildLogs)
|
||||||
{
|
{
|
||||||
return new SimpleLogger(printBuildLogs);
|
return std::make_shared<SimpleLogger>(printBuildLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::atomic<uint64_t> nextId{0};
|
std::atomic<uint64_t> nextId{0};
|
||||||
|
|
||||||
Activity::Activity(Logger & logger, Verbosity lvl, ActivityType type,
|
Activity::Activity(std::shared_ptr<Logger> logger, Verbosity lvl, ActivityType type,
|
||||||
const std::string & s, const Logger::Fields & fields, ActivityId parent)
|
const std::string & s, const Logger::Fields & fields, ActivityId parent)
|
||||||
: logger(logger), id(nextId++ + (((uint64_t) getpid()) << 32))
|
: logger(logger), id(nextId++ + (((uint64_t) getpid()) << 32))
|
||||||
{
|
{
|
||||||
logger.startActivity(id, lvl, type, s, fields, parent);
|
logger->startActivity(id, lvl, type, s, fields, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void to_json(nlohmann::json & json, std::shared_ptr<Pos> pos)
|
void to_json(nlohmann::json & json, std::shared_ptr<Pos> pos)
|
||||||
|
@ -152,9 +182,9 @@ void to_json(nlohmann::json & json, std::shared_ptr<Pos> pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JSONLogger : Logger {
|
struct JSONLogger : Logger {
|
||||||
Logger & prevLogger;
|
std::shared_ptr<Logger> prevLogger;
|
||||||
|
|
||||||
JSONLogger(Logger & prevLogger) : prevLogger(prevLogger) { }
|
JSONLogger(std::shared_ptr<Logger> prevLogger) : prevLogger(prevLogger) { }
|
||||||
|
|
||||||
bool isVerbose() override {
|
bool isVerbose() override {
|
||||||
return true;
|
return true;
|
||||||
|
@ -175,7 +205,7 @@ struct JSONLogger : Logger {
|
||||||
|
|
||||||
void write(const nlohmann::json & json)
|
void write(const nlohmann::json & json)
|
||||||
{
|
{
|
||||||
prevLogger.log(lvlError, "@nix " + json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace));
|
prevLogger->log(lvlError, "@nix " + json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace));
|
||||||
}
|
}
|
||||||
|
|
||||||
void log(Verbosity lvl, std::string_view s) override
|
void log(Verbosity lvl, std::string_view s) override
|
||||||
|
@ -247,9 +277,9 @@ struct JSONLogger : Logger {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger * makeJSONLogger(Logger & prevLogger)
|
std::shared_ptr<Logger> makeJSONLogger(std::shared_ptr<Logger> prevLogger)
|
||||||
{
|
{
|
||||||
return new JSONLogger(prevLogger);
|
return std::make_shared<JSONLogger>(std::move(prevLogger));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Logger::Fields getFields(nlohmann::json & json)
|
static Logger::Fields getFields(nlohmann::json & json)
|
||||||
|
@ -325,7 +355,7 @@ bool handleJSONLogMessage(const std::string & msg,
|
||||||
Activity::~Activity()
|
Activity::~Activity()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
logger.stopActivity(id);
|
logger->stopActivity(id);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
ignoreException();
|
ignoreException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "types.hh"
|
|
||||||
#include "error.hh"
|
#include "error.hh"
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
|
|
||||||
|
@ -132,14 +131,14 @@ void setCurActivity(const ActivityId activityId);
|
||||||
|
|
||||||
struct Activity
|
struct Activity
|
||||||
{
|
{
|
||||||
Logger & logger;
|
std::shared_ptr<Logger> logger;
|
||||||
|
|
||||||
const ActivityId id;
|
const ActivityId id;
|
||||||
|
|
||||||
Activity(Logger & logger, Verbosity lvl, ActivityType type, const std::string & s = "",
|
Activity(std::shared_ptr<Logger> logger, Verbosity lvl, ActivityType type, const std::string & s = "",
|
||||||
const Logger::Fields & fields = {}, ActivityId parent = getCurActivity());
|
const Logger::Fields & fields = {}, ActivityId parent = getCurActivity());
|
||||||
|
|
||||||
Activity(Logger & logger, ActivityType type,
|
Activity(std::shared_ptr<Logger> logger, ActivityType type,
|
||||||
const Logger::Fields & fields = {}, ActivityId parent = getCurActivity())
|
const Logger::Fields & fields = {}, ActivityId parent = getCurActivity())
|
||||||
: Activity(logger, lvlError, type, "", fields, parent) { };
|
: Activity(logger, lvlError, type, "", fields, parent) { };
|
||||||
|
|
||||||
|
@ -163,7 +162,7 @@ struct Activity
|
||||||
|
|
||||||
void result(ResultType type, const Logger::Fields & fields) const
|
void result(ResultType type, const Logger::Fields & fields) const
|
||||||
{
|
{
|
||||||
logger.result(id, type, fields);
|
logger->result(id, type, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class Logger;
|
friend class Logger;
|
||||||
|
@ -176,11 +175,39 @@ struct PushActivity
|
||||||
~PushActivity() { setCurActivity(prevAct); }
|
~PushActivity() { setCurActivity(prevAct); }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Logger * logger;
|
/** Wrapper to make replacing the global logger object thread-safe, since we do
|
||||||
|
* that in various places.
|
||||||
|
*
|
||||||
|
* The actual usage of shared_ptr across threads is ok, only replacing it is
|
||||||
|
* not thread safe.
|
||||||
|
*/
|
||||||
|
struct LoggerWrapper
|
||||||
|
{
|
||||||
|
std::atomic<std::shared_ptr<Logger>> inner;
|
||||||
|
|
||||||
Logger * makeSimpleLogger(bool printBuildLogs = true);
|
explicit LoggerWrapper(std::shared_ptr<Logger> inner) : inner(inner) {}
|
||||||
|
|
||||||
Logger * makeJSONLogger(Logger & prevLogger);
|
const std::shared_ptr<Logger> operator->() const {
|
||||||
|
return inner.load(std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<Logger> operator*() const {
|
||||||
|
return inner.load(std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the logger with a new one atomically.
|
||||||
|
*/
|
||||||
|
const std::shared_ptr<Logger> replace(std::shared_ptr<Logger> newInner) {
|
||||||
|
return inner.exchange(std::move(newInner), std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern LoggerWrapper& logger;
|
||||||
|
|
||||||
|
std::shared_ptr<Logger> makeSimpleLogger(bool printBuildLogs = true);
|
||||||
|
|
||||||
|
std::shared_ptr<Logger> makeJSONLogger(std::shared_ptr<Logger> prevLogger);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* suppress msgs > this
|
* suppress msgs > this
|
||||||
|
|
|
@ -190,7 +190,7 @@ static int childEntry(void * arg)
|
||||||
pid_t startProcess(std::function<void()> fun, const ProcessOptions & options)
|
pid_t startProcess(std::function<void()> fun, const ProcessOptions & options)
|
||||||
{
|
{
|
||||||
std::function<void()> wrapper = [&]() {
|
std::function<void()> wrapper = [&]() {
|
||||||
logger = makeSimpleLogger();
|
logger.replace(makeSimpleLogger());
|
||||||
try {
|
try {
|
||||||
#if __linux__
|
#if __linux__
|
||||||
if (options.dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
|
if (options.dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
|
||||||
|
|
|
@ -40,50 +40,96 @@ public:
|
||||||
class Lock
|
class Lock
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
// Non-owning pointer. This would be an
|
||||||
|
// optional<reference_wrapper<Sync>> if it didn't break gdb accessing
|
||||||
|
// Lock values (as of 2024-06-15, gdb 14.2)
|
||||||
Sync * s;
|
Sync * s;
|
||||||
std::unique_lock<M> lk;
|
std::unique_lock<M> lk;
|
||||||
friend Sync;
|
friend Sync;
|
||||||
Lock(Sync * s) : s(s), lk(s->mutex) { }
|
Lock(Sync &s) : s(&s), lk(s.mutex) { }
|
||||||
public:
|
|
||||||
Lock(Lock && l) : s(l.s) { abort(); }
|
|
||||||
Lock(const Lock & l) = delete;
|
|
||||||
~Lock() { }
|
|
||||||
T * operator -> () { return &s->data; }
|
|
||||||
T & operator * () { return s->data; }
|
|
||||||
|
|
||||||
void wait(std::condition_variable & cv)
|
inline void checkLockingInvariants()
|
||||||
{
|
{
|
||||||
assert(s);
|
assert(s);
|
||||||
|
assert(lk.owns_lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Lock(Lock && l) : s(l.s), lk(std::move(l.lk))
|
||||||
|
{
|
||||||
|
l.s = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock(const Lock & l) = delete;
|
||||||
|
|
||||||
|
~Lock() { }
|
||||||
|
|
||||||
|
T * operator -> ()
|
||||||
|
{
|
||||||
|
checkLockingInvariants();
|
||||||
|
return &s->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
T & operator * ()
|
||||||
|
{
|
||||||
|
checkLockingInvariants();
|
||||||
|
return s->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the given condition variable with no timeout.
|
||||||
|
*
|
||||||
|
* May spuriously wake up.
|
||||||
|
*/
|
||||||
|
void wait(std::condition_variable & cv)
|
||||||
|
{
|
||||||
|
checkLockingInvariants();
|
||||||
cv.wait(lk);
|
cv.wait(lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the given condition variable for a maximum elapsed time of \p duration.
|
||||||
|
*
|
||||||
|
* May spuriously wake up.
|
||||||
|
*/
|
||||||
template<class Rep, class Period>
|
template<class Rep, class Period>
|
||||||
std::cv_status wait_for(std::condition_variable & cv,
|
std::cv_status wait_for(std::condition_variable & cv,
|
||||||
const std::chrono::duration<Rep, Period> & duration)
|
const std::chrono::duration<Rep, Period> & duration)
|
||||||
{
|
{
|
||||||
assert(s);
|
checkLockingInvariants();
|
||||||
return cv.wait_for(lk, duration);
|
return cv.wait_for(lk, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the given condition variable for a maximum elapsed time of \p duration.
|
||||||
|
* Calls \p pred to check if the wakeup should be heeded: \p pred
|
||||||
|
* returning false will ignore the wakeup.
|
||||||
|
*/
|
||||||
template<class Rep, class Period, class Predicate>
|
template<class Rep, class Period, class Predicate>
|
||||||
bool wait_for(std::condition_variable & cv,
|
bool wait_for(std::condition_variable & cv,
|
||||||
const std::chrono::duration<Rep, Period> & duration,
|
const std::chrono::duration<Rep, Period> & duration,
|
||||||
Predicate pred)
|
Predicate pred)
|
||||||
{
|
{
|
||||||
assert(s);
|
checkLockingInvariants();
|
||||||
return cv.wait_for(lk, duration, pred);
|
return cv.wait_for(lk, duration, pred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the given condition variable or until the time point \p duration.
|
||||||
|
*/
|
||||||
template<class Clock, class Duration>
|
template<class Clock, class Duration>
|
||||||
std::cv_status wait_until(std::condition_variable & cv,
|
std::cv_status wait_until(std::condition_variable & cv,
|
||||||
const std::chrono::time_point<Clock, Duration> & duration)
|
const std::chrono::time_point<Clock, Duration> & duration)
|
||||||
{
|
{
|
||||||
assert(s);
|
checkLockingInvariants();
|
||||||
return cv.wait_until(lk, duration);
|
return cv.wait_until(lk, duration);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Lock lock() { return Lock(this); }
|
/**
|
||||||
|
* Lock this Sync and return a RAII guard object.
|
||||||
|
*/
|
||||||
|
Lock lock() { return Lock(*this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,16 +27,15 @@ namespace nix {
|
||||||
};
|
};
|
||||||
|
|
||||||
class CaptureLogging {
|
class CaptureLogging {
|
||||||
Logger * oldLogger;
|
std::shared_ptr<Logger> oldLogger;
|
||||||
std::unique_ptr<CaptureLogger> tempLogger;
|
std::shared_ptr<CaptureLogger> tempLogger;
|
||||||
public:
|
public:
|
||||||
CaptureLogging() : tempLogger(std::make_unique<CaptureLogger>()) {
|
CaptureLogging() : tempLogger(std::make_shared<CaptureLogger>()) {
|
||||||
oldLogger = logger;
|
oldLogger = logger.replace(tempLogger);
|
||||||
logger = tempLogger.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~CaptureLogging() {
|
~CaptureLogging() {
|
||||||
logger = oldLogger;
|
logger.replace(oldLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get() const {
|
std::string get() const {
|
||||||
|
|
Loading…
Reference in a new issue