1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cstdio>
18 #include <cstdlib>
19
20 #include "constants.h"
21 #include "metrics/metrics_library.h"
22
23 enum Mode {
24 kModeDumpHistograms,
25 kModeSendSample,
26 kModeSendEnumSample,
27 kModeSendSparseSample,
28 kModeSendCrosEvent,
29 kModeHasConsent,
30 kModeIsGuestMode,
31 };
32
ShowUsage()33 void ShowUsage() {
34 fprintf(stderr,
35 "Usage: metrics_client [-t] name sample min max nbuckets\n"
36 " metrics_client -e name sample max\n"
37 " metrics_client -s name sample\n"
38 " metrics_client -v event\n"
39 " metrics_client [-cdg]\n"
40 "\n"
41 " default: send metric with integer values \n"
42 " |min| > 0, |min| <= sample < |max|\n"
43 " -c: return exit status 0 if user consents to stats, 1 otherwise,\n"
44 " in guest mode always return 1\n"
45 " -d: dump the histograms recorded by metricsd to stdout\n"
46 " -e: send linear/enumeration histogram data\n"
47 " -g: return exit status 0 if machine in guest mode, 1 otherwise\n"
48 " -s: send a sparse histogram sample\n"
49 " -t: convert sample from double seconds to int milliseconds\n"
50 " -v: send a Platform.CrOSEvent enum histogram sample\n");
51 exit(1);
52 }
53
ParseInt(const char * arg)54 static int ParseInt(const char *arg) {
55 char *endptr;
56 int value = strtol(arg, &endptr, 0);
57 if (*endptr != '\0') {
58 fprintf(stderr, "metrics client: bad integer \"%s\"\n", arg);
59 ShowUsage();
60 }
61 return value;
62 }
63
ParseDouble(const char * arg)64 static double ParseDouble(const char *arg) {
65 char *endptr;
66 double value = strtod(arg, &endptr);
67 if (*endptr != '\0') {
68 fprintf(stderr, "metrics client: bad double \"%s\"\n", arg);
69 ShowUsage();
70 }
71 return value;
72 }
73
DumpHistograms()74 static int DumpHistograms() {
75 MetricsLibrary metrics_lib;
76 metrics_lib.Init();
77
78 std::string dump;
79 if (!metrics_lib.GetHistogramsDump(&dump)) {
80 printf("Failed to dump the histograms.");
81 return 1;
82 }
83
84 printf("%s\n", dump.c_str());
85 return 0;
86 }
87
SendStats(char * argv[],int name_index,enum Mode mode,bool secs_to_msecs)88 static int SendStats(char* argv[],
89 int name_index,
90 enum Mode mode,
91 bool secs_to_msecs) {
92 const char* name = argv[name_index];
93 int sample;
94 if (secs_to_msecs) {
95 sample = static_cast<int>(ParseDouble(argv[name_index + 1]) * 1000.0);
96 } else {
97 sample = ParseInt(argv[name_index + 1]);
98 }
99
100 MetricsLibrary metrics_lib;
101 metrics_lib.Init();
102 if (mode == kModeSendSparseSample) {
103 metrics_lib.SendSparseToUMA(name, sample);
104 } else if (mode == kModeSendEnumSample) {
105 int max = ParseInt(argv[name_index + 2]);
106 metrics_lib.SendEnumToUMA(name, sample, max);
107 } else {
108 int min = ParseInt(argv[name_index + 2]);
109 int max = ParseInt(argv[name_index + 3]);
110 int nbuckets = ParseInt(argv[name_index + 4]);
111 metrics_lib.SendToUMA(name, sample, min, max, nbuckets);
112 }
113 return 0;
114 }
115
SendCrosEvent(char * argv[],int action_index)116 static int SendCrosEvent(char* argv[], int action_index) {
117 const char* event = argv[action_index];
118 bool result;
119 MetricsLibrary metrics_lib;
120 metrics_lib.Init();
121 result = metrics_lib.SendCrosEventToUMA(event);
122 if (!result) {
123 fprintf(stderr, "metrics_client: could not send event %s\n", event);
124 return 1;
125 }
126 return 0;
127 }
128
HasConsent()129 static int HasConsent() {
130 MetricsLibrary metrics_lib;
131 metrics_lib.Init();
132 return metrics_lib.AreMetricsEnabled() ? 0 : 1;
133 }
134
IsGuestMode()135 static int IsGuestMode() {
136 MetricsLibrary metrics_lib;
137 metrics_lib.Init();
138 return metrics_lib.IsGuestMode() ? 0 : 1;
139 }
140
main(int argc,char ** argv)141 int main(int argc, char** argv) {
142 enum Mode mode = kModeSendSample;
143 bool secs_to_msecs = false;
144
145 // Parse arguments
146 int flag;
147 while ((flag = getopt(argc, argv, "abcdegstv")) != -1) {
148 switch (flag) {
149 case 'c':
150 mode = kModeHasConsent;
151 break;
152 case 'd':
153 mode = kModeDumpHistograms;
154 break;
155 case 'e':
156 mode = kModeSendEnumSample;
157 break;
158 case 'g':
159 mode = kModeIsGuestMode;
160 break;
161 case 's':
162 mode = kModeSendSparseSample;
163 break;
164 case 't':
165 secs_to_msecs = true;
166 break;
167 case 'v':
168 mode = kModeSendCrosEvent;
169 break;
170 default:
171 ShowUsage();
172 break;
173 }
174 }
175 int arg_index = optind;
176
177 int expected_args = 0;
178 if (mode == kModeSendSample)
179 expected_args = 5;
180 else if (mode == kModeSendEnumSample)
181 expected_args = 3;
182 else if (mode == kModeSendSparseSample)
183 expected_args = 2;
184 else if (mode == kModeSendCrosEvent)
185 expected_args = 1;
186
187 if ((arg_index + expected_args) != argc) {
188 ShowUsage();
189 }
190
191 switch (mode) {
192 case kModeDumpHistograms:
193 return DumpHistograms();
194 case kModeSendSample:
195 case kModeSendEnumSample:
196 case kModeSendSparseSample:
197 if ((mode != kModeSendSample) && secs_to_msecs) {
198 ShowUsage();
199 }
200 return SendStats(argv,
201 arg_index,
202 mode,
203 secs_to_msecs);
204 case kModeSendCrosEvent:
205 return SendCrosEvent(argv, arg_index);
206 case kModeHasConsent:
207 return HasConsent();
208 case kModeIsGuestMode:
209 return IsGuestMode();
210 default:
211 ShowUsage();
212 return 0;
213 }
214 }
215