Return to file_logger.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / bus / listeners |
1.1 misho 1: /* 2: * Copyright (C) 2012-2015 Tobias Brunner 3: * Copyright (C) 2006 Martin Willi 4: * HSR Hochschule fuer Technik Rapperswil 5: * 6: * This program is free software; you can redistribute it and/or modify it 7: * under the terms of the GNU General Public License as published by the 8: * Free Software Foundation; either version 2 of the License, or (at your 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 10: * 11: * This program is distributed in the hope that it will be useful, but 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14: * for more details. 15: */ 16: 17: #include <stdio.h> 18: #include <string.h> 19: #include <time.h> 20: #include <errno.h> 21: #include <unistd.h> 22: #include <sys/types.h> 23: 24: #include "file_logger.h" 25: 26: #include <daemon.h> 27: #include <threading/mutex.h> 28: #include <threading/rwlock.h> 29: 30: typedef struct private_file_logger_t private_file_logger_t; 31: 32: /** 33: * Private data of a file_logger_t object 34: */ 35: struct private_file_logger_t { 36: 37: /** 38: * Public data. 39: */ 40: file_logger_t public; 41: 42: /** 43: * File name of the target 44: */ 45: char *filename; 46: 47: /** 48: * Current output file 49: */ 50: FILE *out; 51: 52: /** 53: * Flush after writing a line? 54: */ 55: bool flush_line; 56: 57: /** 58: * Maximum level to log, for each group 59: */ 60: level_t levels[DBG_MAX]; 61: 62: /** 63: * strftime() format of time prefix, if any 64: */ 65: char *time_format; 66: 67: /** 68: * Add milliseconds after the time string 69: */ 70: bool add_ms; 71: 72: /** 73: * Print the name/# of the IKE_SA? 74: */ 75: bool ike_name; 76: 77: /** 78: * Mutex to ensure multi-line log messages are not torn apart 79: */ 80: mutex_t *mutex; 81: 82: /** 83: * Lock to read/write options (FD, levels, time_format, etc.) 84: */ 85: rwlock_t *lock; 86: }; 87: 88: METHOD(logger_t, log_, void, 89: private_file_logger_t *this, debug_t group, level_t level, int thread, 90: ike_sa_t* ike_sa, const char *message) 91: { 92: char timestr[128], namestr[128] = ""; 93: const char *current = message, *next; 94: struct tm tm; 95: timeval_t tv; 96: time_t s; 97: u_int ms = 0; 98: 99: this->lock->read_lock(this->lock); 100: if (!this->out) 101: { /* file is not open */ 102: this->lock->unlock(this->lock); 103: return; 104: } 105: if (this->time_format) 106: { 107: gettimeofday(&tv, NULL); 108: s = tv.tv_sec; 109: ms = tv.tv_usec / 1000; 110: localtime_r(&s, &tm); 111: strftime(timestr, sizeof(timestr), this->time_format, &tm); 112: } 113: if (this->ike_name && ike_sa) 114: { 115: if (ike_sa->get_peer_cfg(ike_sa)) 116: { 117: snprintf(namestr, sizeof(namestr), " <%s|%d>", 118: ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); 119: } 120: else 121: { 122: snprintf(namestr, sizeof(namestr), " <%d>", 123: ike_sa->get_unique_id(ike_sa)); 124: } 125: } 126: else 127: { 128: namestr[0] = '\0'; 129: } 130: 131: /* prepend a prefix in front of every line */ 132: this->mutex->lock(this->mutex); 133: while (TRUE) 134: { 135: next = strchr(current, '\n'); 136: if (this->time_format) 137: { 138: if (this->add_ms) 139: { 140: fprintf(this->out, "%s.%03u %.2d[%N]%s ", 141: timestr, ms, thread, debug_names, group, namestr); 142: } 143: else 144: { 145: fprintf(this->out, "%s %.2d[%N]%s ", 146: timestr, thread, debug_names, group, namestr); 147: } 148: } 149: else 150: { 151: fprintf(this->out, "%.2d[%N]%s ", 152: thread, debug_names, group, namestr); 153: } 154: if (next == NULL) 155: { 156: fprintf(this->out, "%s\n", current); 157: break; 158: } 159: fprintf(this->out, "%.*s\n", (int)(next - current), current); 160: current = next + 1; 161: } 162: #ifndef HAVE_SETLINEBUF 163: if (this->flush_line) 164: { 165: fflush(this->out); 166: } 167: #endif /* !HAVE_SETLINEBUF */ 168: this->mutex->unlock(this->mutex); 169: this->lock->unlock(this->lock); 170: } 171: 172: METHOD(logger_t, get_level, level_t, 173: private_file_logger_t *this, debug_t group) 174: { 175: level_t level; 176: 177: this->lock->read_lock(this->lock); 178: level = this->levels[group]; 179: this->lock->unlock(this->lock); 180: return level; 181: } 182: 183: METHOD(file_logger_t, set_level, void, 184: private_file_logger_t *this, debug_t group, level_t level) 185: { 186: this->lock->write_lock(this->lock); 187: if (group < DBG_ANY) 188: { 189: this->levels[group] = level; 190: } 191: else 192: { 193: for (group = 0; group < DBG_MAX; group++) 194: { 195: this->levels[group] = level; 196: } 197: } 198: this->lock->unlock(this->lock); 199: } 200: 201: METHOD(file_logger_t, set_options, void, 202: private_file_logger_t *this, char *time_format, bool add_ms, bool ike_name) 203: { 204: this->lock->write_lock(this->lock); 205: free(this->time_format); 206: this->time_format = strdupnull(time_format); 207: this->add_ms = add_ms; 208: this->ike_name = ike_name; 209: this->lock->unlock(this->lock); 210: } 211: 212: /** 213: * Close the current file, if any 214: */ 215: static void close_file(private_file_logger_t *this) 216: { 217: if (this->out && this->out != stdout && this->out != stderr) 218: { 219: fclose(this->out); 220: this->out = NULL; 221: } 222: } 223: 224: METHOD(file_logger_t, open_, void, 225: private_file_logger_t *this, bool flush_line, bool append) 226: { 227: FILE *file; 228: 229: if (streq(this->filename, "stderr")) 230: { 231: file = stderr; 232: } 233: else if (streq(this->filename, "stdout")) 234: { 235: file = stdout; 236: } 237: else 238: { 239: file = fopen(this->filename, append ? "a" : "w"); 240: if (file == NULL) 241: { 242: DBG1(DBG_DMN, "opening file %s for logging failed: %s", 243: this->filename, strerror(errno)); 244: return; 245: } 246: #ifdef HAVE_SETLINEBUF 247: if (flush_line) 248: { 249: setlinebuf(file); 250: } 251: #endif /* HAVE_SETLINEBUF */ 252: } 253: this->lock->write_lock(this->lock); 254: close_file(this); 255: this->out = file; 256: this->flush_line = flush_line; 257: this->lock->unlock(this->lock); 258: } 259: 260: METHOD(file_logger_t, destroy, void, 261: private_file_logger_t *this) 262: { 263: this->lock->write_lock(this->lock); 264: close_file(this); 265: this->lock->unlock(this->lock); 266: this->mutex->destroy(this->mutex); 267: this->lock->destroy(this->lock); 268: free(this->time_format); 269: free(this->filename); 270: free(this); 271: } 272: 273: /* 274: * Described in header. 275: */ 276: file_logger_t *file_logger_create(char *filename) 277: { 278: private_file_logger_t *this; 279: 280: INIT(this, 281: .public = { 282: .logger = { 283: .log = _log_, 284: .get_level = _get_level, 285: }, 286: .set_level = _set_level, 287: .set_options = _set_options, 288: .open = _open_, 289: .destroy = _destroy, 290: }, 291: .filename = strdup(filename), 292: .mutex = mutex_create(MUTEX_TYPE_DEFAULT), 293: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), 294: ); 295: 296: set_level(this, DBG_ANY, LEVEL_SILENT); 297: 298: return &this->public; 299: }