Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bd30335

Browse files
committed
Swift: refactor after review
1 parent a30d5f5 commit bd30335

4 files changed

Lines changed: 69 additions & 93 deletions

File tree

swift/log/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cc_library(
44
hdrs = glob(["*.h"]),
55
visibility = ["//visibility:public"],
66
deps = [
7+
"@absl//absl/strings",
78
"@binlog",
89
"@json",
910
],

swift/log/SwiftDiagnostics.cpp

Lines changed: 30 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,70 +2,53 @@
22

33
#include <binlog/Entries.hpp>
44
#include <nlohmann/json.hpp>
5+
#include "absl/strings/str_join.h"
6+
#include "absl/strings/str_cat.h"
7+
#include "absl/strings/str_split.h"
58

69
namespace codeql {
7-
SwiftDiagnosticsSource::SwiftDiagnosticsSource(std::string_view internalId,
8-
std::string&& name,
9-
std::vector<std::string>&& helpLinks,
10-
std::string&& action)
11-
: name{std::move(name)}, helpLinks{std::move(helpLinks)}, action{std::move(action)} {
12-
id = extractorName;
13-
id += '/';
14-
id += programName;
15-
id += '/';
16-
std::transform(internalId.begin(), internalId.end(), std::back_inserter(id),
17-
[](char c) { return c == '_' ? '-' : c; });
18-
}
19-
20-
void SwiftDiagnosticsSource::create(std::string_view id,
21-
std::string name,
22-
std::vector<std::string> helpLinks,
23-
std::string action) {
24-
auto [it, inserted] = map().emplace(
25-
id, SwiftDiagnosticsSource{id, std::move(name), std::move(helpLinks), std::move(action)});
26-
assert(inserted);
27-
}
28-
2910
void SwiftDiagnosticsSource::emit(std::ostream& out,
3011
std::string_view timestamp,
3112
std::string_view message) const {
32-
nlohmann::json entry;
33-
auto& source = entry["source"];
34-
source["id"] = id;
35-
source["name"] = name;
36-
source["extractorName"] = extractorName;
37-
38-
auto& visibility = entry["visibility"];
39-
visibility["statusPage"] = true;
40-
visibility["cliSummaryTable"] = true;
41-
visibility["telemetry"] = true;
42-
43-
entry["severity"] = "error";
44-
entry["helpLinks"] = helpLinks;
45-
std::string plaintextMessage{message};
46-
plaintextMessage += ".\n\n";
47-
plaintextMessage += action;
48-
plaintextMessage += '.';
49-
entry["plaintextMessage"] = plaintextMessage;
50-
51-
entry["timestamp"] = timestamp;
52-
13+
nlohmann::json entry = {
14+
{"source",
15+
{
16+
{"id", sourceId()},
17+
{"name", name},
18+
{"extractorName", extractorName},
19+
}},
20+
{"visibility",
21+
{
22+
{"statusPage", true},
23+
{"cliSummaryTable", true},
24+
{"telemetry", true},
25+
}},
26+
{"severity", "error"},
27+
{"helpLinks", std::vector<std::string_view>(absl::StrSplit(helpLinks, ' '))},
28+
{"plaintextMessage", absl::StrCat(message, ".\n\n", action, ".")},
29+
{"timestamp", timestamp},
30+
};
5331
out << entry << '\n';
5432
}
5533

34+
std::string SwiftDiagnosticsSource::sourceId() const {
35+
auto ret = absl::StrJoin({extractorName, programName, id}, "/");
36+
std::replace(ret.begin(), ret.end(), '_', '-');
37+
return ret;
38+
}
39+
5640
void SwiftDiagnosticsDumper::write(const char* buffer, std::size_t bufferSize) {
5741
binlog::Range range{buffer, bufferSize};
5842
binlog::RangeEntryStream input{range};
5943
while (auto event = events.nextEvent(input)) {
6044
const auto& source = SwiftDiagnosticsSource::get(event->source->category);
6145
std::ostringstream oss;
6246
timestampedMessagePrinter.printEvent(oss, *event, events.writerProp(), events.clockSync());
47+
// TODO(C++20) use oss.view() directly
6348
auto data = oss.str();
6449
std::string_view view = data;
65-
auto sep = view.find(' ');
66-
assert(sep != std::string::npos);
67-
auto timestamp = view.substr(0, sep);
68-
auto message = view.substr(sep + 1);
50+
using ViewPair = std::pair<std::string_view, std::string_view>;
51+
auto [timestamp, message] = ViewPair(absl::StrSplit(view, absl::MaxSplits(' ', 1)));
6952
source.emit(output, timestamp, message);
7053
}
7154
}

swift/log/SwiftDiagnostics.h

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <cassert>
99
#include <fstream>
1010
#include <filesystem>
11+
#include <sstream>
12+
#include <mutex>
1113

1214
namespace codeql {
1315

@@ -16,16 +18,27 @@ extern const std::string_view programName;
1618
// Models a diagnostic source for Swift, holding static information that goes out into a diagnostic
1719
// These are internally stored into a map on id's. A specific error log can use binlog's category
1820
// as id, which will then be used to recover the diagnostic source while dumping.
19-
class SwiftDiagnosticsSource {
20-
public:
21-
// creates a SwiftDiagnosticsSource with the given data
22-
static void create(std::string_view id,
23-
std::string name,
24-
std::vector<std::string> helpLinks,
25-
std::string action);
21+
struct SwiftDiagnosticsSource {
22+
std::string_view id;
23+
std::string_view name;
24+
static constexpr std::string_view extractorName = "swift";
25+
std::string_view action;
26+
std::string_view helpLinks; // space separated if more than 1. Not a vector to allow constexpr
27+
28+
// for the moment, we only output errors, so no need to store the severity
2629

27-
// gets a previously created SwiftDiagnosticsSource for the given id. Will abort if none exists
28-
static const SwiftDiagnosticsSource& get(const std::string& id) { return map().at(id); }
30+
// registers a diagnostics source for later retrieval with get, if not done yet
31+
template <const SwiftDiagnosticsSource* Spec>
32+
static void inscribe() {
33+
static std::once_flag once;
34+
std::call_once(once, [] {
35+
auto [it, inserted] = map().emplace(Spec->id, Spec);
36+
assert(inserted);
37+
});
38+
}
39+
40+
// gets a previously inscribed SwiftDiagnosticsSource for the given id. Will abort if none exists
41+
static const SwiftDiagnosticsSource& get(const std::string& id) { return *map().at(id); }
2942

3043
// emit a JSON diagnostics for this source with the given timestamp and message to out
3144
// A plaintextMessage is used that includes both the message and the action to take. Dots are
@@ -34,26 +47,13 @@ class SwiftDiagnosticsSource {
3447
void emit(std::ostream& out, std::string_view timestamp, std::string_view message) const;
3548

3649
private:
37-
using Map = std::unordered_map<std::string, SwiftDiagnosticsSource>;
38-
39-
std::string id;
40-
std::string name;
41-
static constexpr std::string_view extractorName = "swift";
42-
43-
// for the moment, we only output errors, so no need to store the severity
44-
45-
std::vector<std::string> helpLinks;
46-
std::string action;
50+
std::string sourceId() const;
51+
using Map = std::unordered_map<std::string, const SwiftDiagnosticsSource*>;
4752

4853
static Map& map() {
4954
static Map ret;
5055
return ret;
5156
}
52-
53-
SwiftDiagnosticsSource(std::string_view internalId,
54-
std::string&& name,
55-
std::vector<std::string>&& helpLinks,
56-
std::string&& action);
5757
};
5858

5959
// An output modeling binlog's output stream concept that intercepts binlog entries and translates
@@ -76,18 +76,12 @@ class SwiftDiagnosticsDumper {
7676
binlog::PrettyPrinter timestampedMessagePrinter{"%u %m", "%Y-%m-%dT%H:%M:%S.%NZ"};
7777
};
7878

79-
namespace diagnostics {
80-
inline void internal_error() {
81-
SwiftDiagnosticsSource::create("internal_error", "Internal error", {},
82-
"Contact us about this issue");
83-
}
84-
} // namespace diagnostics
85-
86-
namespace detail {
87-
template <void (*Func)()>
88-
inline void createSwiftDiagnosticsSourceOnce() {
89-
static int ignore = (Func(), 0);
90-
std::ignore = ignore;
91-
}
92-
} // namespace detail
9379
} // namespace codeql
80+
81+
namespace codeql_diagnostics {
82+
constexpr codeql::SwiftDiagnosticsSource internal_error{
83+
"internal_error",
84+
"Internal error",
85+
"Contact us about this issue",
86+
};
87+
} // namespace codeql_diagnostics

swift/log/SwiftLogging.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,15 @@
4343

4444
#define LOG_WITH_LEVEL(LEVEL, ...) LOG_WITH_LEVEL_AND_CATEGORY(LEVEL, , __VA_ARGS__)
4545

46-
// Emit errors with a specified diagnostics ID. This must be the name of a function in the
47-
// codeql::diagnostics namespace, which must call SwiftDiagnosticSource::create with ID as first
48-
// argument. This function will be called at most once during the program execution.
49-
// See codeql::diagnostics::internal_error below as an example.
46+
// Emit errors with a specified diagnostics ID. This must be the name of a `SwiftDiagnosticsSource`
47+
// defined in the `codeql_diagnostics` namespace, which must have `id` equal to its name.
5048
#define DIAGNOSE_CRITICAL(ID, ...) DIAGNOSE_WITH_LEVEL(critical, ID, __VA_ARGS__)
5149
#define DIAGNOSE_ERROR(ID, ...) DIAGNOSE_WITH_LEVEL(error, ID, __VA_ARGS__)
5250

53-
#define DIAGNOSE_WITH_LEVEL(LEVEL, ID, ...) \
54-
do { \
55-
codeql::detail::createSwiftDiagnosticsSourceOnce<codeql::diagnostics::ID>(); \
56-
LOG_WITH_LEVEL_AND_CATEGORY(LEVEL, ID, __VA_ARGS__); \
51+
#define DIAGNOSE_WITH_LEVEL(LEVEL, ID, ...) \
52+
do { \
53+
codeql::SwiftDiagnosticsSource::inscribe<&codeql_diagnostics::ID>(); \
54+
LOG_WITH_LEVEL_AND_CATEGORY(LEVEL, ID, __VA_ARGS__); \
5755
} while (false)
5856

5957
// avoid calling into binlog's original macros

0 commit comments

Comments
 (0)