/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "constants.h" #include "metrics/metrics_library.h" #include "serialization/metric_sample.h" #include "serialization/serialization_utils.h" enum Mode { kModeDumpLogs, kModeSendSample, kModeSendEnumSample, kModeSendSparseSample, kModeSendUserAction, kModeSendCrosEvent, kModeHasConsent, kModeIsGuestMode, }; void ShowUsage() { fprintf(stderr, "Usage: metrics_client [-t] name sample min max nbuckets\n" " metrics_client -e name sample max\n" " metrics_client -s name sample\n" " metrics_client -v event\n" " metrics_client -u action\n" " metrics_client [-cdg]\n" "\n" " default: send metric with integer values \n" " |min| > 0, |min| <= sample < |max|\n" " -c: return exit status 0 if user consents to stats, 1 otherwise,\n" " in guest mode always return 1\n" " -d: dump cached logs to the console\n" " -e: send linear/enumeration histogram data\n" " -g: return exit status 0 if machine in guest mode, 1 otherwise\n" " -s: send a sparse histogram sample\n" " -t: convert sample from double seconds to int milliseconds\n" " -u: send a user action to Chrome\n" " -v: send a Platform.CrOSEvent enum histogram sample\n"); exit(1); } static 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; } static 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; } static int SendStats(char* argv[], int name_index, enum Mode mode, bool secs_to_msecs) { const char* name = argv[name_index]; int sample; if (secs_to_msecs) { sample = static_cast(ParseDouble(argv[name_index + 1]) * 1000.0); } else { sample = ParseInt(argv[name_index + 1]); } MetricsLibrary metrics_lib; metrics_lib.Init(); 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; } static 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; } static 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; } static int HasConsent() { MetricsLibrary metrics_lib; metrics_lib.Init(); return metrics_lib.AreMetricsEnabled() ? 0 : 1; } static int IsGuestMode() { MetricsLibrary metrics_lib; metrics_lib.Init(); return metrics_lib.IsGuestMode() ? 0 : 1; } static int DumpLogs() { base::FilePath events_file = base::FilePath( metrics::kMetricsDirectory).Append(metrics::kMetricsEventsFileName); printf("Metrics from %s\n\n", events_file.value().data()); ScopedVector metrics; metrics::SerializationUtils::ReadMetricsFromFile(events_file.value(), &metrics); for (ScopedVector::const_iterator i = metrics.begin(); i != metrics.end(); ++i) { const metrics::MetricSample* sample = *i; printf("name: %s\t", sample->name().c_str()); printf("type: "); switch (sample->type()) { case metrics::MetricSample::CRASH: printf("CRASH"); break; case metrics::MetricSample::HISTOGRAM: printf("HISTOGRAM"); break; case metrics::MetricSample::LINEAR_HISTOGRAM: printf("LINEAR_HISTOGRAM"); break; case metrics::MetricSample::SPARSE_HISTOGRAM: printf("SPARSE_HISTOGRAM"); break; case metrics::MetricSample::USER_ACTION: printf("USER_ACTION"); break; } printf("\n"); } return 0; } int main(int argc, char** argv) { enum Mode mode = kModeSendSample; bool secs_to_msecs = false; // Parse arguments int flag; while ((flag = getopt(argc, argv, "abcdegstuv")) != -1) { switch (flag) { case 'c': mode = kModeHasConsent; break; case 'd': mode = kModeDumpLogs; break; case 'e': mode = kModeSendEnumSample; break; case 'g': mode = kModeIsGuestMode; 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); case kModeSendUserAction: return SendUserAction(argv, arg_index); case kModeSendCrosEvent: return SendCrosEvent(argv, arg_index); case kModeHasConsent: return HasConsent(); case kModeIsGuestMode: return IsGuestMode(); case kModeDumpLogs: return DumpLogs(); default: ShowUsage(); return 0; } }