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