OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "metrics_library.h" | 5 #include "metrics_library.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <sys/file.h> | 8 #include <sys/file.h> |
9 | 9 |
10 #include <cstdarg> | 10 #include <cstdarg> |
11 #include <cstdio> | 11 #include <cstdio> |
12 #include <cstring> | 12 #include <cstring> |
13 | 13 |
14 #define READ_WRITE_ALL_FILE_FLAGS \ | 14 #define READ_WRITE_ALL_FILE_FLAGS \ |
15 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) | 15 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) |
16 | 16 |
17 static const char kAutotestPath[] = | 17 static const char kAutotestPath[] = |
18 "/var/log/metrics/autotest-events"; | 18 "/var/log/metrics/autotest-events"; |
19 static const char kChromePath[] = | 19 static const char kUMAEventsPath[] = |
20 "/var/log/metrics/uma-events"; | 20 "/var/log/metrics/uma-events"; |
21 static const int32_t kBufferSize = 1024; | 21 static const int32_t kBufferSize = 1024; |
22 | 22 |
23 using namespace std; | 23 using namespace std; |
24 | 24 |
25 // TODO(sosa@chromium.org) - use Chromium logger instead of stderr | 25 // TODO(sosa@chromium.org) - use Chromium logger instead of stderr |
26 static void PrintError(const char *message, const char *file, | 26 static void PrintError(const char* message, const char* file, |
27 int code) { | 27 int code) { |
28 const char *kProgramName = "metrics_library"; | 28 static const char *kProgramName = "libmetrics"; |
29 if (code == 0) { | 29 if (code == 0) { |
30 fprintf(stderr, "%s: %s\n", kProgramName, message); | 30 fprintf(stderr, "%s: %s\n", kProgramName, message); |
31 } else if (file == NULL) { | 31 } else if (file == NULL) { |
32 fprintf(stderr, "%s: ", kProgramName); | 32 fprintf(stderr, "%s: ", kProgramName); |
33 perror(message); | 33 perror(message); |
34 } else { | 34 } else { |
35 fprintf(stderr, "%s: %s: ", kProgramName, file); | 35 fprintf(stderr, "%s: %s: ", kProgramName, file); |
36 perror(message); | 36 perror(message); |
37 } | 37 } |
38 } | 38 } |
39 | 39 |
40 // Sends message of size |length| to Chrome and returns true on success. | 40 MetricsLibrary::MetricsLibrary() |
41 static bool SendMessageToChrome(int32_t length, const char *message) { | 41 : uma_events_file_(NULL) {} |
42 int chrome_fd = open(kChromePath, | 42 |
| 43 bool MetricsLibrary::SendMessageToChrome(int32_t length, const char* message) { |
| 44 int chrome_fd = open(uma_events_file_, |
43 O_WRONLY | O_APPEND | O_CREAT, | 45 O_WRONLY | O_APPEND | O_CREAT, |
44 READ_WRITE_ALL_FILE_FLAGS); | 46 READ_WRITE_ALL_FILE_FLAGS); |
45 // If we failed to open it, return. | 47 // If we failed to open it, return. |
46 if (chrome_fd < 0) { | 48 if (chrome_fd < 0) { |
47 PrintError("open", kChromePath, errno); | 49 PrintError("open", uma_events_file_, errno); |
48 return false; | 50 return false; |
49 } | 51 } |
50 | 52 |
51 // Need to chmod because open flags are anded with umask. Ignore the | 53 // Need to chmod because open flags are anded with umask. Ignore the |
52 // exit code -- a chronos process may fail chmoding because the file | 54 // exit code -- a chronos process may fail chmoding because the file |
53 // has been created by a root process but that should be OK. | 55 // has been created by a root process but that should be OK. |
54 fchmod(chrome_fd, READ_WRITE_ALL_FILE_FLAGS); | 56 fchmod(chrome_fd, READ_WRITE_ALL_FILE_FLAGS); |
55 | 57 |
56 // Grab an exclusive lock to protect Chrome from truncating | 58 // Grab an exclusive lock to protect Chrome from truncating |
57 // underneath us. Keep the file locked as briefly as possible. | 59 // underneath us. Keep the file locked as briefly as possible. |
58 if (flock(chrome_fd, LOCK_EX) < 0) { | 60 if (flock(chrome_fd, LOCK_EX) < 0) { |
59 PrintError("flock", kChromePath, errno); | 61 PrintError("flock", uma_events_file_, errno); |
60 close(chrome_fd); | 62 close(chrome_fd); |
61 return false; | 63 return false; |
62 } | 64 } |
63 | 65 |
64 bool success = true; | 66 bool success = true; |
65 if (write(chrome_fd, message, length) != length) { | 67 if (write(chrome_fd, message, length) != length) { |
66 PrintError("write", kChromePath, errno); | 68 PrintError("write", uma_events_file_, errno); |
67 success = false; | 69 success = false; |
68 } | 70 } |
69 | 71 |
70 // Release the file lock and close file. | 72 // Release the file lock and close file. |
71 if (flock(chrome_fd, LOCK_UN) < 0) { | 73 if (flock(chrome_fd, LOCK_UN) < 0) { |
72 PrintError("unlock", kChromePath, errno); | 74 PrintError("unlock", uma_events_file_, errno); |
73 success = false; | 75 success = false; |
74 } | 76 } |
75 close(chrome_fd); | 77 close(chrome_fd); |
76 return success; | 78 return success; |
77 } | 79 } |
78 | 80 |
79 // Formats a name/value message for Chrome in |buffer| and returns the | 81 int32_t MetricsLibrary::FormatChromeMessage(int32_t buffer_size, char* buffer, |
80 // length of the message or a negative value on error. | 82 const char* format, ...) { |
81 // | |
82 // Message format is: | LENGTH(binary) | NAME | \0 | VALUE | \0 | | |
83 // | |
84 // The arbitrary |format| argument covers the non-LENGTH portion of the | |
85 // message. The caller is responsible to store the \0 character | |
86 // between NAME and VALUE (e.g. "%s%c%d", name, '\0', value). | |
87 static int32_t FormatChromeMessage(int32_t buffer_size, char *buffer, | |
88 const char *format, ...) { | |
89 int32_t message_length; | 83 int32_t message_length; |
90 size_t len_size = sizeof(message_length); | 84 size_t len_size = sizeof(message_length); |
91 | 85 |
92 // Format the non-LENGTH contents in the buffer by leaving space for | 86 // Format the non-LENGTH contents in the buffer by leaving space for |
93 // LENGTH at the start of the buffer. | 87 // LENGTH at the start of the buffer. |
94 va_list args; | 88 va_list args; |
95 va_start(args, format); | 89 va_start(args, format); |
96 message_length = vsnprintf(&buffer[len_size], buffer_size - len_size, | 90 message_length = vsnprintf(&buffer[len_size], buffer_size - len_size, |
97 format, args); | 91 format, args); |
98 va_end(args); | 92 va_end(args); |
99 | 93 |
100 if (message_length < 0) { | 94 if (message_length < 0) { |
101 PrintError("chrome message format error", NULL, 0); | 95 PrintError("chrome message format error", NULL, 0); |
102 return -1; | 96 return -1; |
103 } | 97 } |
104 | 98 |
105 // +1 to account for the trailing \0. | 99 // +1 to account for the trailing \0. |
106 message_length += len_size + 1; | 100 message_length += len_size + 1; |
107 if (message_length > buffer_size) { | 101 if (message_length > buffer_size) { |
108 PrintError("chrome message too long", NULL, 0); | 102 PrintError("chrome message too long", NULL, 0); |
109 return -1; | 103 return -1; |
110 } | 104 } |
111 | 105 |
112 // Prepend LENGTH to the message. | 106 // Prepend LENGTH to the message. |
113 memcpy(buffer, &message_length, len_size); | 107 memcpy(buffer, &message_length, len_size); |
114 return message_length; | 108 return message_length; |
115 } | 109 } |
116 | 110 |
117 void MetricsLibrary::Init() { | 111 void MetricsLibrary::Init() { |
| 112 uma_events_file_ = kUMAEventsPath; |
118 } | 113 } |
119 | 114 |
120 // static | |
121 bool MetricsLibrary::SendToAutotest(const string& name, int value) { | 115 bool MetricsLibrary::SendToAutotest(const string& name, int value) { |
122 FILE *autotest_file = fopen(kAutotestPath, "a+"); | 116 FILE *autotest_file = fopen(kAutotestPath, "a+"); |
123 if (autotest_file == NULL) { | 117 if (autotest_file == NULL) { |
124 PrintError("fopen", kAutotestPath, errno); | 118 PrintError("fopen", kAutotestPath, errno); |
125 return false; | 119 return false; |
126 } | 120 } |
127 | 121 |
128 fprintf(autotest_file, "%s=%d\n", name.c_str(), value); | 122 fprintf(autotest_file, "%s=%d\n", name.c_str(), value); |
129 fclose(autotest_file); | 123 fclose(autotest_file); |
130 return true; | 124 return true; |
(...skipping 23 matching lines...) Expand all Loading... |
154 FormatChromeMessage(kBufferSize, message, | 148 FormatChromeMessage(kBufferSize, message, |
155 "linearhistogram%c%s %d %d", '\0', | 149 "linearhistogram%c%s %d %d", '\0', |
156 name.c_str(), sample, max); | 150 name.c_str(), sample, max); |
157 | 151 |
158 if (message_length < 0) | 152 if (message_length < 0) |
159 return false; | 153 return false; |
160 | 154 |
161 // Send the message. | 155 // Send the message. |
162 return SendMessageToChrome(message_length, message); | 156 return SendMessageToChrome(message_length, message); |
163 } | 157 } |
OLD | NEW |