diff --git a/swift/README.md b/swift/README.md index f341f481b07..bbf0ef30dc6 100644 --- a/swift/README.md +++ b/swift/README.md @@ -50,14 +50,15 @@ You can also run `../misc/codegen/codegen.py`, as long as you are beneath the `s A log file is produced for each run under `CODEQL_EXTRACTOR_SWIFT_LOG_DIR` (the usual DB log directory). You can use the environment variable `CODEQL_EXTRACTOR_SWIFT_LOG_LEVELS` to configure levels for -loggers and outputs. This must have the form of a comma separated `spec:level` list, where +loggers and outputs. This must have the form of a comma separated `spec:min_level` list, where `spec` is either a glob pattern (made up of alphanumeric, `/`, `*` and `.` characters) for -matching logger names or one of `out:bin`, `out:text` or `out:console`, and `level` is one of `trace`, `debug`, `info`, -`warning`, `error`, `critical` or `no_logs` to turn logs completely off. +matching logger names or one of `out:bin`, `out:text` or `out:console`, and `min_level` is one +of `trace`, `debug`, `info`, `warning`, `error`, `critical` or `no_logs` to turn logs completely off. + Current output default levels are no binary logs, `info` logs or higher in the text file and `warning` logs or higher on -standard error. By default, all loggers are configured with the lowest output level. Logger names are visible in the -textual logs between `[...]`. Examples are `extractor/dispatcher` or `extractor/.trap`. An example -of `CODEQL_EXTRACTOR_SWIFT_LOG_LEVELS` usage is the following: +standard error. By default, all loggers are configured with the lowest logging level of all outputs (`info` by default). +Logger names are visible in the textual logs between `[...]`. Examples are `extractor/dispatcher` +or `extractor/.trap`. An example of `CODEQL_EXTRACTOR_SWIFT_LOG_LEVELS` usage is the following: ```bash export CODEQL_EXTRACTOR_SWIFT_LOG_LEVELS=out:console:trace,out:text:no_logs,*:warning,*.trap:trace @@ -109,4 +110,5 @@ In particular for breakpoints to work you might need to setup the following remo | `bazel-out` | `/absolute/path/to/codeql/bazel-out` | ### Thread safety + The extractor is single-threaded, and there was no effort to make anything in it thread-safe. diff --git a/swift/extractor/infra/SwiftDispatcher.h b/swift/extractor/infra/SwiftDispatcher.h index 69b4cc110bc..2cb928c967a 100644 --- a/swift/extractor/infra/SwiftDispatcher.h +++ b/swift/extractor/infra/SwiftDispatcher.h @@ -152,11 +152,7 @@ class SwiftDispatcher { return *l; } waitingForNewLabel = e; - // TODO: more generic and informational visiting one-line log - if constexpr (std::is_convertible_v) { - const swift::ValueDecl* x = e; - LOG_TRACE("{}", x->getName().getBaseIdentifier().str()); - } + // TODO: add tracing logs for visited stuff, maybe within the translators? visit(e, std::forward(args)...); Log::flush(); // TODO when everything is moved to structured C++ classes, this should be moved to createEntry diff --git a/swift/extractor/infra/log/SwiftLogging.cpp b/swift/extractor/infra/log/SwiftLogging.cpp index f916b556f00..a8052ed2013 100644 --- a/swift/extractor/infra/log/SwiftLogging.cpp +++ b/swift/extractor/infra/log/SwiftLogging.cpp @@ -23,11 +23,11 @@ Log::Level getLevelFor(std::string_view name, const LevelRules& rules, Log::Leve return dflt; } -const char* getEnvOr(const char* var, const char* deflt) { +const char* getEnvOr(const char* var, const char* dflt) { if (const char* ret = getenv(var)) { return ret; } - return deflt; + return dflt; } std::string_view matchToView(std::csub_match m) { @@ -48,16 +48,11 @@ Log::Level matchToLevel(std::csub_match m) { return stringToLevel(matchToView(m)); } -struct LevelConfiguration { - LevelRules& sourceRules; - Log::Level& binSeverity; - Log::Level& textSeverity; - Log::Level& consoleSeverity; - std::vector& problems; -}; +} // namespace -void collectSeverityRules(const char* var, LevelConfiguration&& configuration) { - if (auto levels = getEnvOr(var, nullptr)) { +std::vector Log::collectSeverityRulesAndReturnProblems(const char* envVar) { + std::vector problems; + if (auto levels = getEnvOr(envVar, nullptr)) { // expect comma-separated : std::regex comma{","}; std::regex levelAssignment{R"((?:([*./\w]+)|(?:out:(bin|text|console))):()" LEVEL_REGEX_PATTERN @@ -76,31 +71,28 @@ void collectSeverityRules(const char* var, LevelConfiguration&& configuration) { pattern.insert(pos, (pattern[pos] == '*') ? "." : "\\"); pos += 2; } - configuration.sourceRules.emplace_back(pattern, level); + sourceRules.emplace_back(pattern, level); } else { auto out = matchToView(match[2]); if (out == "bin") { - configuration.binSeverity = level; + binary.level = level; } else if (out == "text") { - configuration.textSeverity = level; + text.level = level; } else if (out == "console") { - configuration.consoleSeverity = level; + console.level = level; } } } else { - configuration.problems.emplace_back("Malformed log level rule: " + it->str()); + problems.emplace_back("Malformed log level rule: " + it->str()); } } } + return problems; } -} // namespace - void Log::configure() { // as we are configuring logging right now, we collect problems and log them at the end - std::vector problems; - collectSeverityRules("CODEQL_EXTRACTOR_SWIFT_LOG_LEVELS", - {sourceRules, binary.level, text.level, console.level, problems}); + auto problems = collectSeverityRulesAndReturnProblems("CODEQL_EXTRACTOR_SWIFT_LOG_LEVELS"); if (text || binary) { std::filesystem::path logFile = getEnvOr("CODEQL_EXTRACTOR_SWIFT_LOG_DIR", "."); logFile /= logRootName; @@ -144,7 +136,7 @@ void Log::flushImpl() { } Log::LoggerConfiguration Log::getLoggerConfigurationImpl(std::string_view name) { - LoggerConfiguration ret{session, logRootName}; + LoggerConfiguration ret{session, std::string{logRootName}}; ret.fullyQualifiedName += '/'; ret.fullyQualifiedName += name; ret.level = std::min({binary.level, text.level, console.level}); diff --git a/swift/extractor/infra/log/SwiftLogging.h b/swift/extractor/infra/log/SwiftLogging.h index 522fdab1eb8..41ace7648e4 100644 --- a/swift/extractor/infra/log/SwiftLogging.h +++ b/swift/extractor/infra/log/SwiftLogging.h @@ -68,7 +68,7 @@ namespace codeql { // tools should define this to tweak the root name of all loggers -extern const char* const logRootName; +extern const std::string_view logRootName; // This class is responsible for the global log state (outputs, log level rules, flushing) // State is stored in the singleton `Log::instance()`. @@ -152,6 +152,7 @@ class Log { FilteredOutput text{Level::info, textFile, format}; FilteredOutput console{Level::warning, std::cerr, format}; LevelRules sourceRules; + std::vector collectSeverityRulesAndReturnProblems(const char* envVar); }; // This class represent a named domain-specific logger, responsible for pushing logs using the diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp index e65f08a9a63..084f98b2c0f 100644 --- a/swift/extractor/main.cpp +++ b/swift/extractor/main.cpp @@ -20,7 +20,7 @@ using namespace std::string_literals; -const char* const codeql::logRootName = "extractor"; +const std::string_view codeql::logRootName = "extractor"; // must be called before processFrontendOptions modifies output paths static void lockOutputSwiftModuleTraps(codeql::SwiftExtractorState& state, @@ -182,6 +182,7 @@ codeql::SwiftExtractorConfiguration configure(int argc, char** argv) { return configuration; } +// TODO: use `absl::StrJoin` or `boost::algorithm::join` static auto argDump(int argc, char** argv) { std::string ret; for (auto arg = argv + 1; arg < argv + argc; ++arg) { @@ -192,13 +193,13 @@ static auto argDump(int argc, char** argv) { return ret; } +// TODO: use `absl::StrJoin` or `boost::algorithm::join` static auto envDump(char** envp) { std::string ret; for (auto env = envp; *env; ++env) { ret += *env; ret += '\n'; } - ret.pop_back(); return ret; } diff --git a/swift/extractor/trap/TrapLabel.h b/swift/extractor/trap/TrapLabel.h index d487f9f2238..abf757b921a 100644 --- a/swift/extractor/trap/TrapLabel.h +++ b/swift/extractor/trap/TrapLabel.h @@ -55,6 +55,7 @@ class UntypedTrapLabel { size_t strSize() const { if (id_ == undefined) return 17; // #ffffffffffffffff if (id_ == 0) return 2; // #0 + // TODO: use absl::bit_width or C+20 std::bit_width instead of this ugly formula return /* # */ 1 + /* hex digits */ static_cast(ceil(log2(id_ + 1) / 4)); } };