OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifdef HAVE_CONFIG_H |
| 6 # include <config.h> |
| 7 #endif /* HAVE_CONFIG_H */ |
| 8 |
| 9 |
| 10 #include <sys/types.h> |
| 11 |
| 12 #include <stdio.h> |
| 13 #include <string.h> |
| 14 |
| 15 #include <nih/alloc.h> |
| 16 #include <nih/error.h> |
| 17 #include <nih/file.h> |
| 18 #include <nih/list.h> |
| 19 #include <nih/logging.h> |
| 20 #include <nih/string.h> |
| 21 |
| 22 #include "perf_log.h" |
| 23 |
| 24 static NihList *message_list; |
| 25 static const char *perf_log_file; |
| 26 static const char *perf_uptime_file; |
| 27 static const char *perf_diskstats_file; |
| 28 |
| 29 /** |
| 30 * load_special_file_contents: |
| 31 * @file: file to load |
| 32 * |
| 33 * Loads an ASCII text file and returns as a string. File must be less than |
| 34 * MAX_FILE_SIZE. Do not use nih_file_read as it requires reading a |
| 35 * normal file whose size is correct (unlike /proc and /sys files). |
| 36 * |
| 37 * Returns: none |
| 38 **/ |
| 39 static char * |
| 40 load_special_file_contents (void *parent, |
| 41 const char *file) |
| 42 { |
| 43 const int MAX_FILE_SIZE = 512; |
| 44 size_t len = 0; |
| 45 char *contents; |
| 46 FILE *fp = NULL; |
| 47 |
| 48 if (! file) { |
| 49 return NULL; |
| 50 } |
| 51 fp = fopen (file, "r"); |
| 52 if (! fp) { |
| 53 return NULL; |
| 54 } |
| 55 contents = NIH_MUST (nih_alloc (parent, MAX_FILE_SIZE + 1)); |
| 56 len = fread (contents, 1, MAX_FILE_SIZE, fp); |
| 57 fclose (fp); |
| 58 if (len < 0) { |
| 59 nih_free(contents); |
| 60 return NULL; |
| 61 } |
| 62 contents[len] = '\0'; |
| 63 return contents; |
| 64 } |
| 65 |
| 66 /** |
| 67 * get_file_fields: |
| 68 * @parent: parent context |
| 69 * @file: file to load and parse |
| 70 * @delimiters: NULL terminated list of characters that delimits fields |
| 71 * @fields: point to integer that is set to the number of fields found |
| 72 * |
| 73 * Loads @file and returns an array of fields delimited by the given |
| 74 * @delimiters array. Avoid nih_file_read as it requires reading a |
| 75 * normal file whose size is correct (unlike /proc and /sys files). |
| 76 * |
| 77 * Returns: array of delimited fields or NULL on error. |
| 78 **/ |
| 79 char ** |
| 80 get_file_fields (void *parent, |
| 81 const char *file, |
| 82 char *delimiters, |
| 83 int *fields) |
| 84 { |
| 85 int i; |
| 86 char *result = NULL; |
| 87 char **array = NULL; |
| 88 char *contents = NULL; |
| 89 |
| 90 nih_assert (fields != NULL); |
| 91 *fields = 0; |
| 92 contents = load_special_file_contents (NULL, |
| 93 file); |
| 94 if (! contents) { |
| 95 return NULL; |
| 96 } |
| 97 array = nih_str_split (parent, |
| 98 contents, |
| 99 delimiters, |
| 100 TRUE); |
| 101 nih_free (contents); |
| 102 if (! array) { |
| 103 return NULL; |
| 104 } |
| 105 i = 0; |
| 106 while (array[i] != NULL) { |
| 107 ++i; |
| 108 } |
| 109 *fields = i; |
| 110 return array; |
| 111 } |
| 112 |
| 113 /** |
| 114 * perf_log_init: |
| 115 * |
| 116 * Initialise the message_list list. |
| 117 * |
| 118 * Returns: none |
| 119 **/ |
| 120 void |
| 121 perf_log_init (void) |
| 122 { |
| 123 if (! message_list) { |
| 124 message_list = NIH_MUST (nih_list_new (NULL)); |
| 125 } |
| 126 } |
| 127 |
| 128 /** |
| 129 * perf_log_flush: |
| 130 * |
| 131 * Attempt to write any enqueued perf log messages. |
| 132 * |
| 133 * Returns: none |
| 134 **/ |
| 135 void |
| 136 perf_log_flush (void) |
| 137 { |
| 138 FILE *fp = NULL; |
| 139 |
| 140 if (perf_log_file) |
| 141 fp = fopen (perf_log_file, "a"); |
| 142 if (! fp) |
| 143 return; |
| 144 NIH_LIST_FOREACH_SAFE (message_list, iter) { |
| 145 NihListEntry *entry = (NihListEntry*)iter; |
| 146 int result; |
| 147 |
| 148 result = fputs (entry->str, fp); |
| 149 if (result < 0) { |
| 150 /* This is an unexpected error. We retry |
| 151 * writing the message later. |
| 152 */ |
| 153 break; |
| 154 } |
| 155 nih_list_remove (iter); |
| 156 nih_free (iter); |
| 157 } |
| 158 |
| 159 fclose (fp); |
| 160 } |
| 161 |
| 162 /** |
| 163 * perf_log_message: |
| 164 * @format: format string |
| 165 * |
| 166 * Log the given formatted message. If the file cannot be written at |
| 167 * this time, we enqueue the message and try later. We grab |
| 168 * performance stats now, and those stats are enqueued to write later. |
| 169 * If the performance stats are not readable at this time, we log "-" |
| 170 * instead. |
| 171 * |
| 172 * Returns: none |
| 173 **/ |
| 174 void |
| 175 perf_log_message (const char *format, |
| 176 ...) |
| 177 { |
| 178 NihListEntry *new_entry; |
| 179 va_list args; |
| 180 int uptime_fields = 0; |
| 181 char **uptimes; |
| 182 int diskstats_fields = 0; |
| 183 char **diskstats; |
| 184 char *uptime_busy; |
| 185 char *sectors_read; |
| 186 char *message; |
| 187 |
| 188 perf_log_init (); |
| 189 uptimes = get_file_fields (NULL, |
| 190 perf_uptime_file, |
| 191 " \n", |
| 192 &uptime_fields); |
| 193 diskstats = get_file_fields (NULL, |
| 194 perf_diskstats_file, |
| 195 " \n", |
| 196 &diskstats_fields); |
| 197 |
| 198 if (uptime_fields < 1) |
| 199 uptime_busy = "-"; |
| 200 else |
| 201 uptime_busy = uptimes[0]; |
| 202 if (diskstats_fields < 3) |
| 203 sectors_read = "-"; |
| 204 else |
| 205 sectors_read = diskstats[2]; |
| 206 |
| 207 va_start (args, format); |
| 208 message = NIH_MUST (nih_vsprintf (NULL, |
| 209 format, |
| 210 args)); |
| 211 va_end (args); |
| 212 |
| 213 /* Create a log entry and add it to the queue. */ |
| 214 new_entry = NIH_MUST (nih_list_entry_new (NULL)); |
| 215 new_entry->str = NIH_MUST (nih_sprintf (new_entry, "%s %s %s", |
| 216 uptime_busy, sectors_read, |
| 217 message)); |
| 218 nih_list_add (message_list, &new_entry->entry); |
| 219 |
| 220 nih_free (message); |
| 221 if (uptimes) |
| 222 nih_free (uptimes); |
| 223 if (diskstats) |
| 224 nih_free (diskstats); |
| 225 |
| 226 perf_log_flush (); |
| 227 } |
| 228 |
| 229 /** |
| 230 * perf_log_job_state_change: |
| 231 * @job: job whose state is changing, |
| 232 * @new_state: new state |
| 233 * |
| 234 * Causes the given job's state transition to be logged to the |
| 235 * performance log. |
| 236 * |
| 237 * Returns: none |
| 238 **/ |
| 239 void |
| 240 perf_log_job_state_change (Job *job, |
| 241 JobState new_state) |
| 242 { |
| 243 perf_log_message ("statechange %s %s\n", |
| 244 job_name (job), |
| 245 job_state_name (new_state)); |
| 246 } |
| 247 |
| 248 /** |
| 249 * perf_log_set_file: |
| 250 * @file: file to write to |
| 251 * |
| 252 * Sets the performance logging file name and writes to it if possible. |
| 253 * |
| 254 * Returns: none |
| 255 **/ |
| 256 void |
| 257 perf_log_set_files (const char *uptime_file, |
| 258 const char *diskstats_file, |
| 259 const char *log_file) |
| 260 { |
| 261 perf_log_init (); |
| 262 perf_log_file = log_file; |
| 263 perf_uptime_file = uptime_file; |
| 264 perf_diskstats_file = diskstats_file; |
| 265 perf_log_flush (); |
| 266 } |
OLD | NEW |