blob: ccbdf84d3bf9183fdfa94007e7270eb0fcf4a789 [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.
#include <algorithm>
#include <cerrno>
#include <fstream> // IWYU pragma: keep
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <gflags/gflags_declare.h>
#include "kudu/gutil/strings/substitute.h"
#include "kudu/tools/diagnostics_log_parser.h"
#include "kudu/tools/tool_action.h"
#include "kudu/util/errno.h"
#include "kudu/util/status.h"
DECLARE_int64(timeout_ms);
DECLARE_string(format);
using std::ifstream;
using std::string;
using std::unique_ptr;
using std::unordered_map;
using std::vector;
using strings::Substitute;
namespace kudu {
namespace tools {
namespace {
constexpr const char* const kLogPathArg = "path";
constexpr const char* const kLogPathArgDesc =
"Path(s) to log file(s) to parse, separated by a whitespace, if many";
Status ParseStacksFromPath(const string& path) {
errno = 0;
ifstream in(path);
if (!in.is_open()) {
return Status::IOError(ErrnoToString(errno));
}
StackDumpingLogVisitor dlv;
LogParser lp(&dlv);
string line;
int line_number = 0;
while (std::getline(in, line)) {
line_number++;
RETURN_NOT_OK_PREPEND(lp.ParseLine(std::move(line)),
Substitute("at line $0", line_number));
}
return Status::OK();
}
Status ParseStacks(const RunnerContext& context) {
vector<string> paths = context.variadic_args;
// The file names are such that lexicographic sorting reflects
// timestamp-based sorting.
std::sort(paths.begin(), paths.end());
for (const auto& path : paths) {
RETURN_NOT_OK_PREPEND(ParseStacksFromPath(path),
Substitute("failed to parse stacks from $0", path));
}
return Status::OK();
}
} // anonymous namespace
unique_ptr<Mode> BuildDiagnoseMode() {
unique_ptr<Action> parse_stacks =
ActionBuilder("parse_stacks", &ParseStacks)
.Description("Parse sampled stack traces out of a diagnostics log")
.AddRequiredVariadicParameter({ kLogPathArg, kLogPathArgDesc })
.Build();
return ModeBuilder("diagnose")
.Description("Diagnostic tools for Kudu servers and clusters")
.AddAction(std::move(parse_stacks))
.Build();
}
} // namespace tools
} // namespace kudu