blob: 938cf502fde30ba5e611991b0917e4b0ae6f63bc [file] [log] [blame]
// Copyright (c) 2011 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 <cstdio>
#include <cstdlib>
#include "metrics/metrics_library.h"
namespace {
enum Mode {
kModeSendSample,
kModeSendEnumSample,
kModeSendSparseSample,
kModeSendUserAction,
kModeSendCrosEvent,
kModeHasConsent,
kModeIsGuestMode,
kModeShowConsentId,
kModeCreateConsent,
kModeDeleteConsent,
kModeReplayFile,
};
void ShowUsage() {
fprintf(
stderr,
"Usage: metrics_client [-W <file>] [-t] name sample min max nbuckets\n"
" metrics_client [-W <file>] -e name sample max\n"
" metrics_client [-W <file>] -s name sample\n"
" metrics_client [-W <file>] -v event\n"
" metrics_client [-W <file>] -u action\n"
" metrics_client [-W <file>] -R <file>\n"
" metrics_client [-cCDg]\n"
"\n"
" default: send an integer-valued histogram sample\n"
" |min| > 0, |min| <= sample < |max|\n"
" -C: Create consent file such that -c will return 0.\n"
" -D: Delete consent file such that -c will return 1.\n"
" -R <file>: Replay events from a file and truncate it.\n"
" -W <file>: Write events to a file; append to it if it exists.\n"
" -c: return exit status 0 if user consents to stats, 1 otherwise,\n"
" in guest mode always return 1\n"
" -e: send linear/enumeration histogram data\n"
" -g: return exit status 0 if machine in guest mode, 1 otherwise\n"
// The -i flag prints the client ID, if it exists and is valid.
// It is not advertised here because it is deprecated and for internal
// use only (at least by the log tool in debugd).
" -s: send a sparse histogram sample\n"
" -t: convert sample from double seconds to int milliseconds\n"
" -u: send a user action\n"
" -v: send a Platform.CrOSEvent enum histogram sample\n");
exit(1);
}
int ParseInt(const char* arg) {
char* endptr;
int value = strtol(arg, &endptr, 0);
if (*endptr != '\0') {
fprintf(stderr, "metrics client: bad integer \"%s\"\n", arg);
ShowUsage();
}
return value;
}
double ParseDouble(const char* arg) {
char* endptr;
double value = strtod(arg, &endptr);
if (*endptr != '\0') {
fprintf(stderr, "metrics client: bad double \"%s\"\n", arg);
ShowUsage();
}
return value;
}
int SendStats(char* argv[],
int name_index,
enum Mode mode,
bool secs_to_msecs,
const char* output_file) {
const char* name = argv[name_index];
int sample;
if (secs_to_msecs) {
sample = static_cast<int>(ParseDouble(argv[name_index + 1]) * 1000.0);
} else {
sample = ParseInt(argv[name_index + 1]);
}
MetricsLibrary metrics_lib;
metrics_lib.Init();
if (output_file) {
metrics_lib.SetOutputFile(output_file);
}
if (mode == kModeSendSparseSample) {
metrics_lib.SendSparseToUMA(name, sample);
} else if (mode == kModeSendEnumSample) {
int max = ParseInt(argv[name_index + 2]);
metrics_lib.SendEnumToUMA(name, sample, max);
} else {
int min = ParseInt(argv[name_index + 2]);
int max = ParseInt(argv[name_index + 3]);
int nbuckets = ParseInt(argv[name_index + 4]);
metrics_lib.SendToUMA(name, sample, min, max, nbuckets);
}
return 0;
}
int SendUserAction(char* argv[], int action_index) {
const char* action = argv[action_index];
MetricsLibrary metrics_lib;
metrics_lib.Init();
metrics_lib.SendUserActionToUMA(action);
return 0;
}
int SendCrosEvent(char* argv[], int action_index) {
const char* event = argv[action_index];
bool result;
MetricsLibrary metrics_lib;
metrics_lib.Init();
result = metrics_lib.SendCrosEventToUMA(event);
if (!result) {
fprintf(stderr, "metrics_client: could not send event %s\n", event);
return 1;
}
return 0;
}
int CreateConsent() {
MetricsLibrary metrics_lib;
metrics_lib.Init();
return metrics_lib.EnableMetrics() ? 0 : 1;
}
int DeleteConsent() {
MetricsLibrary metrics_lib;
metrics_lib.Init();
return metrics_lib.DisableMetrics() ? 0 : 1;
}
int HasConsent() {
MetricsLibrary metrics_lib;
metrics_lib.Init();
return metrics_lib.AreMetricsEnabled() ? 0 : 1;
}
int IsGuestMode() {
MetricsLibrary metrics_lib;
metrics_lib.Init();
return metrics_lib.IsGuestMode() ? 0 : 1;
}
int ShowConsentId() {
MetricsLibrary metrics_lib;
metrics_lib.Init();
std::string id;
if (metrics_lib.ConsentId(&id) == false) {
fprintf(stderr, "error: consent not given\n");
return 1;
}
printf("%s\n", id.c_str());
return 0;
}
int ReplayFile(const char* input_file, const char* output_file) {
MetricsLibrary metrics_lib;
metrics_lib.Init();
if (output_file) {
metrics_lib.SetOutputFile(output_file);
}
return metrics_lib.Replay(input_file) ? 0 : 1;
}
} // namespace
int main(int argc, char** argv) {
enum Mode mode = kModeSendSample;
bool secs_to_msecs = false;
const char* output_file = nullptr;
const char* input_file = nullptr;
// Parse arguments
int flag;
while ((flag = getopt(argc, argv, "CDR:W:cegistuv")) != -1) {
switch (flag) {
case 'C':
mode = kModeCreateConsent;
break;
case 'D':
mode = kModeDeleteConsent;
break;
case 'R':
mode = kModeReplayFile;
input_file = optarg;
break;
case 'W':
output_file = optarg;
break;
case 'c':
mode = kModeHasConsent;
break;
case 'e':
mode = kModeSendEnumSample;
break;
case 'g':
mode = kModeIsGuestMode;
break;
case 'i':
// This flag is slated for removal.
// See comment in ShowUsage().
mode = kModeShowConsentId;
break;
case 's':
mode = kModeSendSparseSample;
break;
case 't':
secs_to_msecs = true;
break;
case 'u':
mode = kModeSendUserAction;
break;
case 'v':
mode = kModeSendCrosEvent;
break;
default:
ShowUsage();
break;
}
}
int arg_index = optind;
int expected_args = 0;
if (mode == kModeSendSample)
expected_args = 5;
else if (mode == kModeSendEnumSample)
expected_args = 3;
else if (mode == kModeSendSparseSample)
expected_args = 2;
else if (mode == kModeSendUserAction)
expected_args = 1;
else if (mode == kModeSendCrosEvent)
expected_args = 1;
if ((arg_index + expected_args) != argc) {
ShowUsage();
}
switch (mode) {
case kModeSendSample:
case kModeSendEnumSample:
case kModeSendSparseSample:
if ((mode != kModeSendSample) && secs_to_msecs) {
ShowUsage();
}
return SendStats(argv, arg_index, mode, secs_to_msecs, output_file);
case kModeSendUserAction:
return SendUserAction(argv, arg_index);
case kModeSendCrosEvent:
return SendCrosEvent(argv, arg_index);
case kModeCreateConsent:
return CreateConsent();
case kModeDeleteConsent:
return DeleteConsent();
case kModeHasConsent:
return HasConsent();
case kModeIsGuestMode:
return IsGuestMode();
case kModeShowConsentId:
return ShowConsentId();
case kModeReplayFile:
return ReplayFile(input_file, output_file);
default:
ShowUsage();
return 0;
}
}