Skip to content

Commit 64aa567

Browse files
Alramechfacebook-github-bot
authored andcommitted
Update eden logger to support strvec
Summary: # Context Adds support for vector<string> inside eden's logger object. This is done to support a new logEvent. # Code decisions Vector<string> is converted to a folly::dynamic via the function folly::toDynamic instead of using the preexisting dynamicMap due to issues with getting the types to play nice. We may want to look at using it for the other fields as well rather than using a homegrown function. Reviewed By: jdelliot Differential Revision: D73214290 fbshipit-source-id: 48b3ea0647f444da960bb1eade02f521a05968ed
1 parent 8c9ecda commit 64aa567

File tree

5 files changed

+87
-3
lines changed

5 files changed

+87
-3
lines changed

eden/common/telemetry/DynamicEvent.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,18 @@ void DynamicEvent::addDouble(std::string name, double value) {
7070
}
7171
}
7272

73+
void DynamicEvent::addStringVec(
74+
std::string name,
75+
std::vector<std::string> value) {
76+
for (auto& vref : value) {
77+
validateUtf8(vref);
78+
}
79+
auto [iter, inserted] =
80+
stringVecs_.emplace(std::move(name), std::move(value));
81+
if (!inserted) {
82+
throw_<std::logic_error>(
83+
"Attempted to insert duplicate string vector: ", iter->first);
84+
}
85+
}
86+
7387
} // namespace facebook::eden

eden/common/telemetry/DynamicEvent.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <cstdint>
1212
#include <string>
1313
#include <unordered_map>
14+
#include <vector>
1415

1516
namespace facebook::eden {
1617

@@ -19,6 +20,8 @@ class DynamicEvent {
1920
using IntMap = std::unordered_map<std::string, int64_t>;
2021
using StringMap = std::unordered_map<std::string, std::string>;
2122
using DoubleMap = std::unordered_map<std::string, double>;
23+
using StringVecMap =
24+
std::unordered_map<std::string, std::vector<std::string>>;
2225

2326
DynamicEvent() = default;
2427
DynamicEvent(const DynamicEvent&) = default;
@@ -38,6 +41,7 @@ class DynamicEvent {
3841
void addInt(std::string name, int64_t value);
3942
void addString(std::string name, std::string value);
4043
void addDouble(std::string name, double value);
44+
void addStringVec(std::string name, std::vector<std::string> value);
4145

4246
/**
4347
* Convenience function that adds boolean values as integer 0 or 1.
@@ -55,14 +59,17 @@ class DynamicEvent {
5559
const DoubleMap& getDoubleMap() const {
5660
return doubles_;
5761
}
62+
const StringVecMap& getStringVecMap() const {
63+
return stringVecs_;
64+
}
5865

5966
private:
6067
// Due to limitations in the underlying log database, limit the field types to
6168
// int64_t, double, string, and vector<string>
62-
// TODO: add vector<string> support if needed.
6369
IntMap ints_;
6470
StringMap strings_;
6571
DoubleMap doubles_;
72+
StringVecMap stringVecs_;
6673
};
6774

6875
} // namespace facebook::eden

eden/common/telemetry/ScubaStructuredLogger.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
*/
77

88
#include "eden/common/telemetry/ScubaStructuredLogger.h"
9+
#include "eden/common/telemetry/SubprocessScribeLogger.h"
910

1011
#include <folly/json/json.h>
11-
12-
#include "eden/common/telemetry/SubprocessScribeLogger.h"
12+
#include "folly/json/DynamicConverter.h"
1313

1414
namespace facebook::eden {
1515

@@ -50,6 +50,12 @@ void ScubaStructuredLogger::logDynamicEvent(DynamicEvent event) {
5050
document["double"] = dynamicMap(doubleMap);
5151
}
5252

53+
const auto& stringVecMap = event.getStringVecMap();
54+
if (!stringVecMap.empty()) {
55+
// Special case handling for array
56+
document["normvector"] = folly::toDynamic(stringVecMap);
57+
}
58+
5359
scribeLogger_->log(folly::toJson(document));
5460
}
5561

eden/common/telemetry/test/DynamicEventTest.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,13 @@ TEST(DynamicEventTest, ValidateUtf8) {
8383
EXPECT_THROW(
8484
event.addString("test_invalid_utf8", "\xFF\xFF"), std::exception);
8585
}
86+
TEST(DynamicEventTest, AddStringVec) {
87+
DynamicEvent event;
88+
std::vector<std::string> test = {"a", "b", "c"};
89+
event.addStringVec("stringvec", test);
90+
const auto& stringVecMap = event.getStringVecMap();
91+
EXPECT_EQ(stringVecMap.size(), 1);
92+
EXPECT_EQ(stringVecMap.at("stringvec"), test);
93+
EXPECT_THROW(event.addStringVec("stringvec", {"qq"}), std::logic_error);
94+
}
8695
} // namespace facebook::eden

eden/common/telemetry/test/ScubaStructuredLoggerTest.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,21 @@ struct TypelessTestLogEvent : public TypelessTestEvent {
5656
}
5757
};
5858

59+
struct VectorTestLogEvent : public TestEvent {
60+
std::vector<std::string> strvec;
61+
62+
explicit VectorTestLogEvent(std::vector<std::string> strvec)
63+
: strvec(std::move(strvec)) {}
64+
65+
void populate(DynamicEvent& event) const override {
66+
event.addStringVec("strvec", strvec);
67+
}
68+
69+
char const* getType() const override {
70+
return "vector_test_event";
71+
}
72+
};
73+
5974
struct ScubaStructuredLoggerTest : public ::testing::Test {
6075
std::shared_ptr<TestScribeLogger> scribe{
6176
std::make_shared<TestScribeLogger>()};
@@ -138,3 +153,36 @@ TEST_F(
138153
UnorderedElementsAre("str", "user", "host", "os", "osver"));
139154
#endif
140155
}
156+
157+
TEST_F(ScubaStructuredLoggerTest, empty_stringvec_test) {
158+
VectorTestLogEvent event({});
159+
logger.logEvent(event);
160+
EXPECT_EQ(1, scribe->lines.size());
161+
const auto& line = scribe->lines[0];
162+
auto doc = folly::parseJson(line);
163+
EXPECT_TRUE(doc.isObject());
164+
EXPECT_THAT(keysOf(doc), UnorderedElementsAre("int", "normal", "normvector"));
165+
166+
auto normvecs = doc["normvector"];
167+
EXPECT_TRUE(normvecs.isObject());
168+
EXPECT_THAT(keysOf(normvecs), UnorderedElementsAre("strvec"));
169+
EXPECT_TRUE(normvecs["strvec"].empty());
170+
}
171+
172+
TEST_F(ScubaStructuredLoggerTest, stringvec_test) {
173+
VectorTestLogEvent event({"a", "b", "c"});
174+
logger.logEvent(event);
175+
EXPECT_EQ(1, scribe->lines.size());
176+
const auto& line = scribe->lines[0];
177+
auto doc = folly::parseJson(line);
178+
EXPECT_TRUE(doc.isObject());
179+
EXPECT_THAT(keysOf(doc), UnorderedElementsAre("int", "normal", "normvector"));
180+
181+
auto normvecs = doc["normvector"];
182+
EXPECT_TRUE(normvecs.isObject());
183+
EXPECT_THAT(keysOf(normvecs), UnorderedElementsAre("strvec"));
184+
EXPECT_FALSE(normvecs["strvec"].empty());
185+
EXPECT_EQ(normvecs["strvec"][0].asString(), "a");
186+
EXPECT_EQ(normvecs["strvec"][1].asString(), "b");
187+
EXPECT_EQ(normvecs["strvec"][2].asString(), "c");
188+
}

0 commit comments

Comments
 (0)