blob: 818d7e84900fb65f4fcb972b7a3c7197cc3b30b6 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include <iostream>
#include <optional>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>
#include <glog/logging.h>
#include <rapidjson/document.h>
#include "kudu/gutil/strings/stringpiece.h"
#include "kudu/util/jsonreader.h" // IWYU pragma: keep
#include "kudu/util/status.h"
namespace kudu {
namespace tools {
// One of the record types from the log.
// TODO(KUDU-2353) support metrics records.
enum class RecordType {
kSymbols,
kStacks,
kUnknown
};
const char* RecordTypeToString(RecordType r);
std::ostream& operator<<(std::ostream& o, RecordType r);
// A stack sample from the log.
struct StacksRecord {
// A group of threads which share the same stack trace.
struct Group {
// The thread IDs in this group.
std::vector<int> tids;
// The non-symbolized addresses forming the stack trace.
std::vector<std::string> frame_addrs;
};
// The time the stack traces were collected.
std::string date_time;
// The reason for stack trace collection.
std::string reason;
// The grouped threads with their stack traces.
std::vector<Group> groups;
};
// Interface for consuming the parsed records from a diagnostics log.
class LogVisitor {
public:
virtual ~LogVisitor() {}
virtual void VisitSymbol(const std::string& addr, const std::string& symbol) = 0;
virtual void VisitStacksRecord(const StacksRecord& sr) = 0;
};
// LogVisitor implementation which dumps the parsed stack records to cout.
class StackDumpingLogVisitor : public LogVisitor {
public:
void VisitSymbol(const std::string& addr, const std::string& symbol) override;
void VisitStacksRecord(const StacksRecord& sr) override;
private:
// True when we have not yet output any data.
bool first_ = true;
// Map from symbols to name.
std::unordered_map<std::string, std::string> symbols_;
const std::string kUnknownSymbol = "<unknown>";
};
// A parsed line from the diagnostics log.
//
// Each line contains a timestamp, a record type, and some JSON data.
class ParsedLine {
public:
// Parse a line from the diagnostics log.
Status Parse(std::string line);
RecordType type() const { return type_; }
const rapidjson::Value* json() const {
CHECK(json_);
return json_->root();
}
std::string date_time() const;
private:
std::string line_;
RecordType type_;
// date_ and time_ point to substrings of line_.
StringPiece date_;
StringPiece time_;
// A JsonReader initialized from the most recent line.
// This will be 'none' before any lines have been read.
std::optional<JsonReader> json_;
};
// Parser for a metrics log.
//
// Each line should be fed to LogParser::ParseLine().
//
// This instance follows a 'SAX' model. As records are available, the appropriate
// functions are invoked on the visitor provided in the constructor.
class LogParser {
public:
explicit LogParser(LogVisitor* visitor);
// Parse the next line of the log. This function may invoke the appropriate
// visitor functions zero or more times.
Status ParseLine(std::string line);
private:
Status ParseSymbols(const ParsedLine& lf);
static Status ParseStackGroup(const rapidjson::Value& group_json,
StacksRecord::Group* group);
Status ParseStacks(const ParsedLine& lf);
LogVisitor* visitor_;
};
} // namespace tools
} // namespace kudu