1/* 2 * Copyright (C) 2009-2011 Julien BLACHE <jb@jblache.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <stdio.h> 24#include <unistd.h> 25#include <stdarg.h> 26#include <string.h> 27#include <time.h> 28#include <errno.h> 29#include <sys/stat.h> 30#include <pthread.h> 31 32#include <event.h> 33 34#include <libavutil/log.h> 35 36#include "conffile.h" 37#include "logger.h" 38 39 40static pthread_mutex_t logger_lck = PTHREAD_MUTEX_INITIALIZER; 41static int logdomains; 42static int threshold; 43static int console; 44static char *logfilename; 45static FILE *logfile; 46static char *labels[] = { "config", "daap", "db", "httpd", "main", "mdns", "misc", "rsp", "scan", "xcode", "event", "remote", "dacp", "ffmpeg", "artwork", "player", "raop", "laudio", "dmap", "dbperf" }; 47 48 49static int 50set_logdomains(char *domains) 51{ 52 char *ptr; 53 char *d; 54 int i; 55 56 logdomains = 0; 57 58 while ((d = strtok_r(domains, " ,", &ptr))) 59 { 60 domains = NULL; 61 62 for (i = 0; i < N_LOGDOMAINS; i++) 63 { 64 if (strcmp(d, labels[i]) == 0) 65 { 66 logdomains |= (1 << i); 67 break; 68 } 69 } 70 71 if (i == N_LOGDOMAINS) 72 { 73 fprintf(stderr, "Error: unknown log domain '%s'\n", d); 74 return -1; 75 } 76 } 77 78 return 0; 79} 80 81static void 82vlogger(int severity, int domain, const char *fmt, va_list args) 83{ 84 va_list ap; 85 char stamp[32]; 86 time_t t; 87 int ret; 88 89 90 if (!((1 << domain) & logdomains) || (severity > threshold)) 91 return; 92 93 pthread_mutex_lock(&logger_lck); 94 95 if (!logfile && !console) 96 { 97 pthread_mutex_unlock(&logger_lck); 98 return; 99 } 100 101 if (logfile) 102 { 103 t = time(NULL); 104 ret = strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&t)); 105 if (ret == 0) 106 stamp[0] = '\0'; 107 108 fprintf(logfile, "[%s] %8s: ", stamp, labels[domain]); 109 110 va_copy(ap, args); 111 vfprintf(logfile, fmt, ap); 112 va_end(ap); 113 114 fflush(logfile); 115 } 116 117 if (1) 118 { 119 fprintf(stderr, "%8s: ", labels[domain]); 120 121 va_copy(ap, args); 122 vfprintf(stderr, fmt, ap); 123 va_end(ap); 124 } 125 126 pthread_mutex_unlock(&logger_lck); 127} 128 129void 130DPRINTF(int severity, int domain, const char *fmt, ...) 131{ 132 va_list ap; 133 134 va_start(ap, fmt); 135 vlogger(severity, domain, fmt, ap); 136 va_end(ap); 137} 138 139void 140logger_ffmpeg(void *ptr, int level, const char *fmt, va_list ap) 141{ 142 int severity; 143 144 /* Can't use a switch() because some definitions have the same value */ 145 if ((level == AV_LOG_FATAL) || (level == AV_LOG_ERROR)) 146 severity = E_LOG; 147 else if ((level == AV_LOG_WARNING) || (level == AV_LOG_INFO) || (level == AV_LOG_VERBOSE)) 148 severity = E_WARN; 149 else if (level == AV_LOG_DEBUG) 150 severity = E_DBG; 151 else if (level == AV_LOG_QUIET) 152 severity = E_SPAM; 153 else 154 severity = E_LOG; 155 156 vlogger(severity, L_FFMPEG, fmt, ap); 157} 158 159void 160logger_libevent(int severity, const char *msg) 161{ 162 switch (severity) 163 { 164 case _EVENT_LOG_DEBUG: 165 severity = E_DBG; 166 break; 167 168 case _EVENT_LOG_ERR: 169 severity = E_LOG; 170 break; 171 172 case _EVENT_LOG_WARN: 173 severity = E_WARN; 174 break; 175 176 case _EVENT_LOG_MSG: 177 severity = E_INFO; 178 break; 179 180 default: 181 severity = E_LOG; 182 break; 183 } 184 185 DPRINTF(severity, L_EVENT, "%s\n", msg); 186} 187 188#ifdef LAUDIO_USE_ALSA 189void 190logger_alsa(const char *file, int line, const char *function, int err, const char *fmt, ...) 191{ 192 va_list ap; 193 194 va_start(ap, fmt); 195 vlogger(E_LOG, L_LAUDIO, fmt, ap); 196 va_end(ap); 197} 198#endif /* LAUDIO_USE_ALSA */ 199 200void 201logger_reinit(void) 202{ 203 FILE *fp; 204 205 if (!logfile) 206 return; 207 208 pthread_mutex_lock(&logger_lck); 209 210 fp = fopen(logfilename, "a"); 211 if (!fp) 212 { 213 fprintf(logfile, "Could not reopen logfile: %s\n", strerror(errno)); 214 215 goto out; 216 } 217 218 fclose(logfile); 219 logfile = fp; 220 221 out: 222 pthread_mutex_unlock(&logger_lck); 223} 224 225 226/* The functions below are used at init time with a single thread running */ 227void 228logger_domains(void) 229{ 230 int i; 231 232 fprintf(stdout, "%s", labels[0]); 233 234 for (i = 1; i < N_LOGDOMAINS; i++) 235 fprintf(stdout, ", %s", labels[i]); 236 237 fprintf(stdout, "\n"); 238} 239 240void 241logger_detach(void) 242{ 243 console = 0; 244} 245 246int 247logger_init(char *file, char *domains, int severity) 248{ 249 int ret; 250 251 if ((sizeof(labels) / sizeof(labels[0])) != N_LOGDOMAINS) 252 { 253 fprintf(stderr, "WARNING: log domains do not match\n"); 254 255 return -1; 256 } 257 258 console = 1; 259 threshold = severity; 260 261 if (domains) 262 { 263 ret = set_logdomains(domains); 264 if (ret < 0) 265 return ret; 266 } 267 else 268 logdomains = ~0; 269 270 if (!file) 271 return 0; 272 273 logfile = fopen(file, "a"); 274 if (!logfile) 275 { 276 fprintf(stderr, "Could not open logfile %s: %s\n", file, strerror(errno)); 277 278 return -1; 279 } 280 281 ret = fchown(fileno(logfile), runas_uid, 0); 282 if (ret < 0) 283 fprintf(stderr, "Failed to set ownership on logfile: %s\n", strerror(errno)); 284 285 ret = fchmod(fileno(logfile), 0644); 286 if (ret < 0) 287 fprintf(stderr, "Failed to set permissions on logfile: %s\n", strerror(errno)); 288 289 logfilename = file; 290 291 return 0; 292} 293 294void 295logger_deinit(void) 296{ 297 if (logfile) 298 fclose(logfile); 299} 300