blob: 6ec72262d017395dddc15ecb062f70a0124510b0 [file] [log] [blame]
Darin Petkov65b01462010-04-14 13:32:20 -07001// 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
3// found in the LICENSE file.
4
Darin Petkov65b01462010-04-14 13:32:20 -07005#include "metrics_library.h"
6
7#include <errno.h>
8#include <sys/file.h>
Darin Petkov4fcb2ac2010-04-15 16:40:23 -07009
10#include <cstdarg>
11#include <cstdio>
12#include <cstring>
Darin Petkov65b01462010-04-14 13:32:20 -070013
14#define READ_WRITE_ALL_FILE_FLAGS \
15 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
16
Darin Petkovc2526a12010-04-21 14:24:04 -070017static const char kAutotestPath[] =
18 "/var/log/metrics/autotest-events";
Darin Petkov11b8eb32010-05-18 11:00:59 -070019static const char kUMAEventsPath[] =
Darin Petkovc2526a12010-04-21 14:24:04 -070020 "/var/log/metrics/uma-events";
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070021static const int32_t kBufferSize = 1024;
Darin Petkov65b01462010-04-14 13:32:20 -070022
23using namespace std;
24
25// TODO(sosa@chromium.org) - use Chromium logger instead of stderr
Darin Petkov11b8eb32010-05-18 11:00:59 -070026static void PrintError(const char* message, const char* file,
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070027 int code) {
Darin Petkov11b8eb32010-05-18 11:00:59 -070028 static const char *kProgramName = "libmetrics";
Darin Petkov65b01462010-04-14 13:32:20 -070029 if (code == 0) {
30 fprintf(stderr, "%s: %s\n", kProgramName, message);
31 } else if (file == NULL) {
32 fprintf(stderr, "%s: ", kProgramName);
33 perror(message);
34 } else {
35 fprintf(stderr, "%s: %s: ", kProgramName, file);
36 perror(message);
37 }
38}
39
Darin Petkov11b8eb32010-05-18 11:00:59 -070040MetricsLibrary::MetricsLibrary()
41 : uma_events_file_(NULL) {}
42
43bool MetricsLibrary::SendMessageToChrome(int32_t length, const char* message) {
44 int chrome_fd = open(uma_events_file_,
Darin Petkov65b01462010-04-14 13:32:20 -070045 O_WRONLY | O_APPEND | O_CREAT,
46 READ_WRITE_ALL_FILE_FLAGS);
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070047 // If we failed to open it, return.
Darin Petkov65b01462010-04-14 13:32:20 -070048 if (chrome_fd < 0) {
Darin Petkov11b8eb32010-05-18 11:00:59 -070049 PrintError("open", uma_events_file_, errno);
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070050 return false;
Darin Petkov65b01462010-04-14 13:32:20 -070051 }
52
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070053 // Need to chmod because open flags are anded with umask. Ignore the
54 // exit code -- a chronos process may fail chmoding because the file
55 // has been created by a root process but that should be OK.
56 fchmod(chrome_fd, READ_WRITE_ALL_FILE_FLAGS);
Darin Petkov65b01462010-04-14 13:32:20 -070057
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070058 // Grab an exclusive lock to protect Chrome from truncating
59 // underneath us. Keep the file locked as briefly as possible.
Darin Petkov65b01462010-04-14 13:32:20 -070060 if (flock(chrome_fd, LOCK_EX) < 0) {
Darin Petkov11b8eb32010-05-18 11:00:59 -070061 PrintError("flock", uma_events_file_, errno);
Darin Petkov65b01462010-04-14 13:32:20 -070062 close(chrome_fd);
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070063 return false;
Darin Petkov65b01462010-04-14 13:32:20 -070064 }
65
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070066 bool success = true;
67 if (write(chrome_fd, message, length) != length) {
Darin Petkov11b8eb32010-05-18 11:00:59 -070068 PrintError("write", uma_events_file_, errno);
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070069 success = false;
70 }
Darin Petkov65b01462010-04-14 13:32:20 -070071
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070072 // Release the file lock and close file.
73 if (flock(chrome_fd, LOCK_UN) < 0) {
Darin Petkov11b8eb32010-05-18 11:00:59 -070074 PrintError("unlock", uma_events_file_, errno);
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070075 success = false;
76 }
Darin Petkov65b01462010-04-14 13:32:20 -070077 close(chrome_fd);
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070078 return success;
79}
80
Darin Petkov11b8eb32010-05-18 11:00:59 -070081int32_t MetricsLibrary::FormatChromeMessage(int32_t buffer_size, char* buffer,
82 const char* format, ...) {
Darin Petkov4fcb2ac2010-04-15 16:40:23 -070083 int32_t message_length;
84 size_t len_size = sizeof(message_length);
85
86 // Format the non-LENGTH contents in the buffer by leaving space for
87 // LENGTH at the start of the buffer.
88 va_list args;
89 va_start(args, format);
90 message_length = vsnprintf(&buffer[len_size], buffer_size - len_size,
91 format, args);
92 va_end(args);
93
94 if (message_length < 0) {
95 PrintError("chrome message format error", NULL, 0);
96 return -1;
97 }
98
99 // +1 to account for the trailing \0.
100 message_length += len_size + 1;
101 if (message_length > buffer_size) {
102 PrintError("chrome message too long", NULL, 0);
103 return -1;
104 }
105
106 // Prepend LENGTH to the message.
107 memcpy(buffer, &message_length, len_size);
108 return message_length;
109}
110
Darin Petkovfc91b422010-05-12 13:05:45 -0700111void MetricsLibrary::Init() {
Darin Petkov11b8eb32010-05-18 11:00:59 -0700112 uma_events_file_ = kUMAEventsPath;
Darin Petkovfc91b422010-05-12 13:05:45 -0700113}
114
Darin Petkovc2526a12010-04-21 14:24:04 -0700115bool MetricsLibrary::SendToAutotest(const string& name, int value) {
Darin Petkov4fcb2ac2010-04-15 16:40:23 -0700116 FILE *autotest_file = fopen(kAutotestPath, "a+");
117 if (autotest_file == NULL) {
118 PrintError("fopen", kAutotestPath, errno);
119 return false;
120 }
121
122 fprintf(autotest_file, "%s=%d\n", name.c_str(), value);
123 fclose(autotest_file);
124 return true;
125}
126
Darin Petkov21cd2c52010-05-12 15:26:16 -0700127bool MetricsLibrary::SendToUMA(const string& name, int sample,
128 int min, int max, int nbuckets) {
Darin Petkov4fcb2ac2010-04-15 16:40:23 -0700129 // Format the message.
130 char message[kBufferSize];
131 int32_t message_length =
132 FormatChromeMessage(kBufferSize, message,
Darin Petkovc2526a12010-04-21 14:24:04 -0700133 "histogram%c%s %d %d %d %d", '\0',
134 name.c_str(), sample, min, max, nbuckets);
Darin Petkov4fcb2ac2010-04-15 16:40:23 -0700135
136 if (message_length < 0)
137 return false;
138
139 // Send the message.
140 return SendMessageToChrome(message_length, message);
Darin Petkov65b01462010-04-14 13:32:20 -0700141}
Darin Petkov5b7dce12010-04-21 15:45:10 -0700142
Darin Petkov21cd2c52010-05-12 15:26:16 -0700143bool MetricsLibrary::SendEnumToUMA(const std::string& name, int sample,
144 int max) {
Darin Petkov5b7dce12010-04-21 15:45:10 -0700145 // Format the message.
146 char message[kBufferSize];
147 int32_t message_length =
148 FormatChromeMessage(kBufferSize, message,
149 "linearhistogram%c%s %d %d", '\0',
150 name.c_str(), sample, max);
151
152 if (message_length < 0)
153 return false;
154
155 // Send the message.
156 return SendMessageToChrome(message_length, message);
157}