blob: 354d4c2b0df9d4eb46f9e5bd7d52f50c3a7064b3 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdlib.h>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <base/logging.h>
#include <base/message_loop/message_loop.h>
#include <base/optional.h>
#include <base/time/time.h>
#include <base/values.h>
#include <brillo/flag_helper.h>
#include "diagnostics/telem/telem_connection.h"
#include "diagnostics/telem/telemetry_group_enum.h"
#include "diagnostics/telem/telemetry_item_enum.h"
namespace {
void DisplayStringItem(const base::Value& string_item);
void DisplayIntItem(const base::Value& int_item);
void DisplayListItem(const base::Value& list_item);
bool DisplayTelemetryItem(const base::Value& telem_item);
bool DisplayOptionalTelemetryItem(
const std::string& item_name,
const base::Optional<base::Value>& telem_item);
// URI on which the gRPC interface exposed by the diagnosticsd daemon is
// listening. This is the same URI that the diagnosticsd daemon uses to
// communicate with the diagnostics_processor, so this tool should not
// be used when diagnostics_processor is running.
constexpr char kDiagnosticsdGrpcUri[] =
"unix:/run/diagnostics/grpc_sockets/diagnosticsd_socket";
struct {
const char* switch_name;
diagnostics::TelemetryItemEnum telemetry_item;
} kTelemetryItemSwitches[] = {
{"uptime", diagnostics::TelemetryItemEnum::kUptime},
{"memtotal", diagnostics::TelemetryItemEnum::kMemTotalMebibytes},
{"memfree", diagnostics::TelemetryItemEnum::kMemFreeMebibytes},
{"runnable_entities", diagnostics::TelemetryItemEnum::kNumRunnableEntities},
{"existing_entities", diagnostics::TelemetryItemEnum::kNumExistingEntities},
{"idle_time_total", diagnostics::TelemetryItemEnum::kTotalIdleTimeUserHz},
{"idle_time_per_cpu",
diagnostics::TelemetryItemEnum::kIdleTimePerCPUUserHz},
{"button", diagnostics::TelemetryItemEnum::kAcpiButton},
{"netstat", diagnostics::TelemetryItemEnum::kNetStat},
{"netdev", diagnostics::TelemetryItemEnum::kNetDev}};
struct {
const char* switch_name;
diagnostics::TelemetryGroupEnum telemetry_group;
} kTelemetryGroupSwitches[] = {
{"disk", diagnostics::TelemetryGroupEnum::kDisk}};
// Helper function to display a base::Value object which has a string
// representation.
void DisplayStringItem(const base::Value& string_item) {
DCHECK(string_item.is_string());
std::string val;
string_item.GetAsString(&val);
std::cout << val << std::endl;
}
// Helper function to display a base::Value object which has an integer
// representation.
void DisplayIntItem(const base::Value& int_item) {
DCHECK(int_item.is_int());
int val;
int_item.GetAsInteger(&val);
std::cout << val << std::endl;
}
// Helper function to display a base::Value object which has a list
// representation.
void DisplayListItem(const base::Value& list_item) {
DCHECK(list_item.is_list());
const base::ListValue* list;
list_item.GetAsList(&list);
const base::Value* item;
// Print a newline so that the first list value starts on a new line.
std::cout << std::endl;
// Print each of the list values.
for (int i = 0; i < list->GetSize(); i++) {
list->Get(i, &item);
DisplayTelemetryItem(*item);
}
}
// Helper function to display a base::Value object which has an arbitrary
// representation.
bool DisplayTelemetryItem(const base::Value& telem_item) {
if (telem_item.is_int()) {
DisplayIntItem(telem_item);
} else if (telem_item.is_string()) {
DisplayStringItem(telem_item);
} else if (telem_item.is_list()) {
DisplayListItem(telem_item);
} else {
LOG(ERROR) << "Invalid format for telemetry item.";
return false;
}
return true;
}
// Displays the telemetry item to the console. Returns
// true iff the item was successfully displayed.
bool DisplayOptionalTelemetryItem(
const std::string& item_name,
const base::Optional<base::Value>& telem_item) {
if (!telem_item) {
LOG(ERROR) << "No telemetry item received.";
return false;
}
std::cout << item_name << ": ";
return DisplayTelemetryItem(telem_item.value());
}
} // namespace
// 'telem' command-line tool:
//
// Test driver for libtelem. Only supports requesting individual telemetry
// items. This program does not exercise the caching functionality of libtelem.
int main(int argc, char** argv) {
DEFINE_string(item, "", "Telemetry item to retrieve.");
DEFINE_string(group, "", "Group of telemetry items to retrieve.");
brillo::FlagHelper::Init(argc, argv, "telem - Device telemetry tool.");
std::map<std::string, diagnostics::TelemetryItemEnum>
telemetry_switch_to_item;
std::map<diagnostics::TelemetryItemEnum, std::string>
telemetry_item_to_switch;
for (const auto& item : kTelemetryItemSwitches) {
telemetry_switch_to_item[item.switch_name] = item.telemetry_item;
telemetry_item_to_switch[item.telemetry_item] = item.switch_name;
}
std::map<std::string, diagnostics::TelemetryGroupEnum>
telemetry_switch_to_group;
for (const auto& group : kTelemetryGroupSwitches) {
telemetry_switch_to_group[group.switch_name] = group.telemetry_group;
}
logging::InitLogging(logging::LoggingSettings());
base::MessageLoopForIO message_loop;
diagnostics::TelemConnection telem_connection;
telem_connection.Connect(kDiagnosticsdGrpcUri);
// Make sure at least one item or group is specified.
if (FLAGS_item == "" && FLAGS_group == "") {
LOG(ERROR) << "No item or group specified.";
return EXIT_FAILURE;
}
// Validate the item flag.
if (FLAGS_item != "") {
if (!telemetry_switch_to_item.count(FLAGS_item)) {
LOG(ERROR) << "Invalid item: " << FLAGS_item;
return EXIT_FAILURE;
}
// Retrieve and display the telemetry item.
const base::Optional<base::Value> telem_item =
telem_connection.GetItem(telemetry_switch_to_item.at(FLAGS_item),
base::TimeDelta::FromSeconds(0));
if (!DisplayOptionalTelemetryItem(FLAGS_item, telem_item))
return EXIT_FAILURE;
}
// Validate the group flag.
if (FLAGS_group != "") {
if (!telemetry_switch_to_group.count(FLAGS_group)) {
LOG(ERROR) << "Invalid group: " << FLAGS_group;
return EXIT_FAILURE;
}
// Retrieve and display the telemetry group.
const std::vector<std::pair<diagnostics::TelemetryItemEnum,
const base::Optional<base::Value>>>
telem_items =
telem_connection.GetGroup(telemetry_switch_to_group.at(FLAGS_group),
base::TimeDelta::FromSeconds(0));
for (auto item_pair : telem_items) {
if (!DisplayOptionalTelemetryItem(
telemetry_item_to_switch.at(item_pair.first), item_pair.second))
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}