|  | // 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; | 
|  | } | 
|  | } |