blob: 4af96e521901aeb825fd124c2d1acb1d3dcecdba [file] [log] [blame]
// Copyright 2018 Google LLC
//
// Licensed 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
//
// https://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.
// A helper tool to perform various transformations on traces, notably
// protobuf-to-JSON conversion and trace truncation.
#include <cstdint>
#include <iostream>
#include <istream>
#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/util/json_util.h"
#include "quic_trace/quic_trace.pb.h"
ABSL_FLAG(bool, whitespace, true, "Add whitespace to the JSON output");
ABSL_FLAG(std::string,
input_format,
"protobuf",
"Can be 'protobuf' or 'json'.");
ABSL_FLAG(std::string,
output_format,
"protobuf",
"Can be 'protobuf' or 'json'.");
ABSL_FLAG(int64_t,
truncate_after_time_us,
-1,
"If positive, removes all events after the specified point in "
"time (us) from the trace.");
namespace {
using google::protobuf::util::JsonOptions;
using google::protobuf::util::JsonStringToMessage;
using google::protobuf::util::MessageToJsonString;
bool IsValidFormatString(absl::string_view format) {
return format == "protobuf" || format == "json";
}
bool InputTrace(quic_trace::Trace* trace) {
if (absl::GetFlag(FLAGS_input_format) == "protobuf") {
return trace->ParseFromIstream(&std::cin);
}
std::istreambuf_iterator<char> it(std::cin);
std::istreambuf_iterator<char> end;
auto status = JsonStringToMessage(std::string(it, end), trace);
return status.ok();
}
void OutputTrace(const quic_trace::Trace& trace) {
if (absl::GetFlag(FLAGS_output_format) == "protobuf") {
trace.SerializeToOstream(&std::cout);
return;
}
std::string output;
JsonOptions options;
options.add_whitespace = absl::GetFlag(FLAGS_whitespace);
MessageToJsonString(trace, &output, options);
std::cout << output;
}
void MaybeTruncateTrace(quic_trace::Trace* trace) {
if (absl::GetFlag(FLAGS_truncate_after_time_us) <= 0) {
return;
}
auto* events = trace->mutable_events();
while (!events->empty() &&
events->rbegin()->time_us() > static_cast<uint64_t>(absl::GetFlag(
FLAGS_truncate_after_time_us))) {
events->RemoveLast();
}
}
} // namespace
int main(int argc, char* argv[]) {
absl::ParseCommandLine(argc, argv);
if (!IsValidFormatString(absl::GetFlag(FLAGS_input_format))) {
std::cerr << "Invalid format specified: "
<< absl::GetFlag(FLAGS_input_format) << std::endl;
return 1;
}
if (!IsValidFormatString(absl::GetFlag(FLAGS_output_format))) {
std::cerr << "Invalid format specified: "
<< absl::GetFlag(FLAGS_output_format) << std::endl;
return 1;
}
quic_trace::Trace trace;
bool success = InputTrace(&trace);
if (!success) {
std::cerr << "Failed to parse input." << std::endl;
return 1;
}
MaybeTruncateTrace(&trace);
OutputTrace(trace);
return 0;
}