//------------------------------------------------------------------------------
// @file: com_proto_io.cc
// @author: Fabio Luchetti - CERN
//------------------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2018 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your token) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "common/StringTokenizer.hh"
#include "common/Path.hh"
#include "console/ConsoleMain.hh"
#include "console/commands/ICmdHelper.hh"
extern int com_io(char*);
void com_io_help();
//------------------------------------------------------------------------------
//! Class IoHelper
//------------------------------------------------------------------------------
class IoHelper : public ICmdHelper
{
public:
//----------------------------------------------------------------------------
//! Constructor
//!
//! @param opts global options
//----------------------------------------------------------------------------
IoHelper(const GlobalOptions& opts):
ICmdHelper(opts)
{}
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
~IoHelper() override = default;
//----------------------------------------------------------------------------
//! Parse command line input
//!
//! @param arg input
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
bool ParseCommand(const char* arg) override;
};
//------------------------------------------------------------------------------
// Parse command line input
//------------------------------------------------------------------------------
bool IoHelper::ParseCommand(const char* arg)
{
eos::console::IoProto* io = mReq.mutable_io();
eos::common::StringTokenizer tokenizer(arg);
tokenizer.GetLine();
std::string token;
if (!tokenizer.NextToken(token)) {
return false;
}
// one of { stat, ns, report, enable, disable }
if (token == "stat") {
eos::console::IoProto_StatProto* stat = io->mutable_stat();
while (tokenizer.NextToken(token)) {
if (token == "-a") {
stat->set_details(true);
} else if (token == "-m") {
stat->set_monitoring(true);
} else if (token == "-n") {
stat->set_numerical(true);
} else if (token == "-t") {
stat->set_top(true);
} else if (token == "-d") {
stat->set_domain(true);
} else if (token == "-x") {
stat->set_apps(true);
} else if (token == "--ss") {
stat->set_sample_stat(true);
} else if (token == "--sa") {
if (!(tokenizer.NextToken(token))) {
continue;
} else {
// Parse
bool not_numeric = (token.find_first_not_of("0123456789") !=
std::string::npos);
if (not_numeric) {
std::cerr << "error: --sa value needs to be numeric (seconds ago)" << std::endl;
return false;
} else {
try {
uint64_t tago = std::stoull(token);
stat->set_time_ago(tago);
} catch (const std::exception& e) {
std::cerr << "error: --sa value needs to be numeric (seconds ago)" << std::endl;
return false;
}
}
}
} else if (token == "--si") {
if (!(tokenizer.NextToken(token))) {
continue;
} else {
// Parse
bool not_numeric = (token.find_first_not_of("0123456789") !=
std::string::npos);
if (not_numeric) {
std::cerr << "error: --si value needs to be numeric (interval in seconds)" <<
std::endl;
return false;
} else {
try {
uint64_t tint = std::stoull(token);
stat->set_time_interval(tint);
} catch (const std::exception& e) {
std::cerr << "error: --si value needs to be numeric (interval in seconds)" <<
std::endl;
return false;
}
}
}
} else if (token == "-l") {
stat->set_summary(true);
} else {
return false;
}
}
} else if (token == "ns") {
eos::console::IoProto_NsProto* ns = io->mutable_ns();
while (tokenizer.NextToken(token)) {
if (token == "-m") {
ns->set_monitoring(true);
} else if (token == "-b") {
ns->set_rank_by_byte(true);
} else if (token == "-n") {
ns->set_rank_by_access(true);
} else if (token == "-w") {
ns->set_last_week(true);
} else if (token == "-f") {
ns->set_hotfiles(true);
/* (token == "-100" || token == "-1000" || token == "-10000" || token == "-a" ) */
} else if (token == "-100") {
ns->set_count(eos::console::IoProto_NsProto::ONEHUNDRED);
} else if (token == "-1000") {
ns->set_count(eos::console::IoProto_NsProto::ONETHOUSAND);
} else if (token == "-10000") {
ns->set_count(eos::console::IoProto_NsProto::TENTHOUSAND);
} else if (token == "-a") {
ns->set_count(eos::console::IoProto_NsProto::ALL);
} else {
return false;
}
}
} else if (token == "report") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::IoProto_ReportProto* report = io->mutable_report();
report->set_path(token);
} else if (token == "enable" || token == "disable") {
eos::console::IoProto_EnableProto* enable = io->mutable_enable();
enable->set_switchx(token == "enable");
while (tokenizer.NextToken(token)) {
if (token == "-r") {
enable->set_reports(true);
} else if (token == "-p") {
enable->set_popularity(true);
} else if (token == "-n") {
enable->set_namespacex(true);
} else if (token == "--udp") {
if (!(tokenizer.NextToken(token)) || (token.find('-') == 0)) {
return false;
} else {
enable->set_upd_address(token);
}
} else {
return false;
}
}
} else { // no proper subcommand
return false;
}
return true;
}
//------------------------------------------------------------------------------
// io command entry point
//------------------------------------------------------------------------------
int com_protoio(char* arg)
{
if (wants_help(arg)) {
com_io_help();
global_retc = EINVAL;
return EINVAL;
}
IoHelper io(gGlobalOpts);
if (!io.ParseCommand(arg)) {
com_io_help();
global_retc = EINVAL;
return EINVAL;
}
global_retc = io.Execute();
return global_retc;
}
//------------------------------------------------------------------------------
// Print help message
//------------------------------------------------------------------------------
void com_io_help()
{
std::ostringstream oss;
oss
<< " usage:\n"
<< std::endl
<< "io stat [-l] [-a] [-m] [-n] [-t] [-d] [-x] [--ss] [--sa] [--si] : print io statistics\n"
<< "\t -l : show summary information (this is the default if -a,-t,-d,-x is not selected)\n"
<< "\t -a : break down by uid/gid\n"
<< "\t -m : print in = monitoring format\n"
<< "\t -n : print numerical uid/gids\n"
<< "\t -t : print top user stats\n"
<< "\t -d : break down by domains\n"
<< "\t -x : break down by application\n"
<< "\t --ss : show table with transfer sample statistics\n"
<< "\t --sa : start collection of statistics given number of seconds ago\n"
<< "\t --si : collect statistics over given interval of seconds\n"
<< "\t Note: this tool shows data for finished transfers only (using storage node reports)\n"
<< "\t Example: asking for data of finished transfers which were transferred during interval [now - 180s, now - 120s]:\n"
<< "\t eos io stat -x --sa 120 --si 60\n"
<< std::endl
<< "io enable [-r] [-p] [-n] [--udp ] : enable collection of io statistics\n"
<< "\t -r : enable collection of io reports\n"
<< "\t -p : enable popularity accounting\n"
<< "\t -n : enable report namespace\n"
<< "\t --udp : add a UDP message target for io UDP packtes (the configured targets are shown by 'io stat -l)\n"
<< std::endl
<< "io disable [-r] [-p] [-n] [--udp ] : disable collection of io statistics\n"
<< "\t -r : disable collection of io reports\n"
<< "\t -p : disable popularity accounting\n"
<< "\t -n : disable report namespace\n"
<< "\t --udp : remove a UDP message target for io UDP packtes (the configured targets are shown by 'io stat -l)\n"
<< std::endl
<< "io report : show contents of report namespace for \n"
<< std::endl
<< "io ns [-a] [-n] [-b] [-100|-1000|-10000] [-w] [-f] : show namespace IO ranking (popularity)\n"
<< "\t -a : don't limit the output list\n"
<< "\t -n : show ranking by number of accesses\n"
<< "\t -b : show ranking by number of bytes\n"
<< "\t -100 : show the first 100 in the ranking\n"
<< "\t -1000 : show the first 1000 in the ranking\n"
<< "\t -10000 : show the first 10000 in the ranking\n"
<< "\t -w : show history for the last 7 days\n"
<< "\t -f : show the 'hotfiles' which are the files with highest number of present file opens\n"
<< std::endl;
std::cerr << oss.str() << std::endl;
}