Annotation of embedaddon/strongswan/src/libcharon/bus/listeners/file_logger.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>