Sun, 17 Mar 2013 19:19:57 +0100
some fixes
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef __gnu_linux__ #define _GNU_SOURCE #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <aio.h> #include <time.h> #include "log.h" #include "../util/strbuf.h" #include "../util/io.h" #include "../ucx/map.h" static int is_initialized = 0; static int log_file_fd; static int log_level = 0; /* * if the log file is uninitialized, output is written to the ui_buffer */ static sbuf_t *ui_buffer = NULL; /* * access logfile map */ static UcxMap *access_log_files; // map of AccessLog* static AccessLog *default_access_log; char *log_date_month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char *log_levels[] = { "error", "warning", "info" }; int init_log_file(LogConfig *cfg) { if(is_initialized) { return 0; } /* open the log file */ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; log_file_fd = open(cfg->file, O_WRONLY | O_CREAT | O_APPEND, mode); if(log_file_fd == -1) { return -1; } if(!strcmp(cfg->level, "ERROR")) { log_level = LOG_LEVEL_ERROR; } else if(!strcmp(cfg->level, "WARNING")) { log_level = LOG_LEVEL_WARNING; } else if(!strcmp(cfg->level, "INFO")) { log_level = LOG_LEVEL_INFO; } if(cfg->log_stdout) { // TODO } if(cfg->log_stderr) { // TODO } is_initialized = 1; /* if ui_buffer is not NULL, write it to the log file */ if(ui_buffer) { size_t len = ui_buffer->length; size_t r; while(len > 0) { r = write(log_file_fd, ui_buffer->ptr, ui_buffer->length); len -= r; } sbuf_free(ui_buffer); } return 0; } void log_uninitialized_writeln(char *str, size_t len) { if(ui_buffer == NULL) { ui_buffer = sbuf_new(1024); if(ui_buffer == NULL) { return; /* TODO: critical error, exit */ } } sstr_t s; s.ptr = str; s.length = len; sbuf_append(ui_buffer, s); sbuf_put(ui_buffer, '\n'); } void log_file_writeln(char *str, size_t len) { if(!is_initialized) { log_uninitialized_writeln(str, len); } struct iovec io[] = { { str, len }, { "\n", 1} }; writev(log_file_fd, io, 2); /* TODO: aio */ } sstr_t log_get_prefix(int level) { time_t t = time(NULL); sstr_t d; d.ptr = NULL; d.length = 0; struct tm date; localtime_r(&t, &date); char *buf = malloc(64); int len = snprintf( buf, 64, "[%02d/%s/%d:%02d:%02d:%02d] %s : ", date.tm_mday, log_date_month[date.tm_mon], 1900 + date.tm_year, date.tm_hour, date.tm_min, date.tm_sec, log_levels[level]); if(len > 0) { d.ptr = buf; d.length = len; } return d; } /* * log api functions */ int log_ereport(int degree, const char *format, ...) { if(degree > log_level) { return 0; } sstr_t lmsg; lmsg.ptr = NULL; va_list ap; va_start(ap, format); /* create log message prefix */ sstr_t lpre = log_get_prefix(degree); /* format message */ int len = vasprintf(&lmsg.ptr, format, ap); lmsg.length = len; /* create message string */ sstr_t message; message.length = lpre.length + len; message.ptr = malloc(message.length + 1); message = sstrncat(2, message, lpre, lmsg); /* write message to the log file */ log_file_writeln(message.ptr, message.length); /* cleanup */ free(lmsg.ptr); free(message.ptr); return 0; } /* * access log * This source file only manages access log files. IO is performed directly * by AddLog safs. */ AccessLog* get_access_log(sstr_t file, sstr_t format) { if(!access_log_files) { access_log_files = ucx_map_new(4); } if(file.ptr == NULL || file.length == 0) { return NULL; } AccessLog *log = ucx_map_sstr_get(access_log_files, file); if(log != NULL) { // TODO: ref return log; } // the log file is not opened // check first if we can open it sstr_t path = sstrdup(file); FILE *out = fopen(path.ptr, "a"); if(out == NULL) { free(path.ptr); return NULL; } // create access log object log = calloc(1, sizeof(AccessLog)); log->file = path; if(format.ptr != NULL) { log->format = sstrdup(format); } log->log = out; // TODO: log->ref = 1; // add access log to the map ucx_map_sstr_put(access_log_files, file, log); if(!default_access_log) { default_access_log = log; } return log; } AccessLog* get_default_access_log() { // TODO: ref return default_access_log; }