| 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 |