summaryrefslogtreecommitdiff
path: root/src/mongo/util/procparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/procparser.cpp')
-rw-r--r--src/mongo/util/procparser.cpp105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/mongo/util/procparser.cpp b/src/mongo/util/procparser.cpp
index 599608c9cc8..a9067b27899 100644
--- a/src/mongo/util/procparser.cpp
+++ b/src/mongo/util/procparser.cpp
@@ -857,5 +857,110 @@ Status parseProcVMStatFile(StringData filename,
return parseProcVMStat(keys, swString.getValue(), builder);
}
+// Here is an example of the type of string it supports:
+//
+// > cat /proc/pressure/<cpu|io|memory>
+// some avg10=0.00 avg60=0.00 avg300=0.14 total=1434509127
+// full avg10=0.00 avg60=0.00 avg300=0.14 total=1035574668
+//
+// Note: /proc/pressure/cpu only has 'some' entry
+//
+Status parseProcPressure(StringData data, BSONObjBuilder* builder) {
+ using string_split_iterator = boost::split_iterator<StringData::const_iterator>;
+
+ // Split the file by lines.
+ // token_compress_on means the iterator skips over consecutive '\n'.
+ for (string_split_iterator lineIt = string_split_iterator(
+ data.begin(),
+ data.end(),
+ boost::token_finder([](char c) { return c == '\n'; }, boost::token_compress_on));
+ lineIt != string_split_iterator();
+ ++lineIt) {
+
+ StringData line((*lineIt).begin(), (*lineIt).end());
+
+ // Split the line by spaces and equal signs since these are the delimiters for pressure
+ // files. token_compress_on means the iterator skips over consecutive ' '. This is needed
+ // for every line.
+ string_split_iterator partIt =
+ string_split_iterator(line.begin(),
+ line.end(),
+ boost::token_finder([](char c) { return c == ' ' || c == '='; },
+ boost::token_compress_on));
+
+ // Skip processing this line if we do not have a key.
+ if (partIt == string_split_iterator()) {
+ continue;
+ }
+
+ StringData time((*partIt).begin(), (*partIt).end());
+
+ ++partIt;
+
+ // Skip processing this line if we only have a key, and no arguments.
+ if (partIt == string_split_iterator()) {
+ continue;
+ }
+
+ // Share of time is either 'some' or 'full'.
+ if (time != kPressureSomeTime && time != kPressureFullTime) {
+ return Status(ErrorCodes::FailedToParse, "Couldn't find the share of time");
+ }
+
+ // Lookup for 'total' token in the parts.
+ auto totalIt = std::find_if(partIt, string_split_iterator(), [](const auto& vec) {
+ return StringData(vec.begin(), vec.end()) == "total"_sd;
+ });
+
+ // If 'total' token is not found on the row return an error.
+ if (totalIt == string_split_iterator()) {
+ return Status(ErrorCodes::NoSuchKey, "Failed to find 'total' token");
+ }
+
+ StringData totalToken((*totalIt).begin(), (*totalIt).end());
+
+ ++totalIt;
+
+ if (totalIt == string_split_iterator()) {
+ return Status(ErrorCodes::FailedToParse, "No value found for 'total' token");
+ }
+
+ StringData stringValue((*totalIt).begin(), (*totalIt).end());
+
+ double value;
+
+ if (!NumberParser{}(stringValue, &value).isOK()) {
+ return Status(ErrorCodes::FailedToParse,
+ str::stream() << "Couldn't parse '" << stringValue << "' to number");
+ }
+
+ *builder << time << BSON("totalMicros" << value);
+ }
+
+ return Status::OK();
+}
+
+// Example of BSONObjBuilder created:
+// cpu : {
+// some : {
+// totalMicros : ...
+// },
+// fulll: {
+// totalMicros : ...
+// }
+// }
+Status parseProcPressureFile(StringData key, StringData filename, BSONObjBuilder* builder) {
+ auto swString = readFileAsString(filename);
+ if (!swString.isOK()) {
+ return swString.getStatus();
+ }
+
+ BSONObjBuilder sub(builder->subobjStart(key));
+ Status status = parseProcPressure(swString.getValue(), &sub);
+ sub.doneFast();
+
+ return status;
+}
+
} // namespace procparser
} // namespace mongo