Wed Apr 6 11:29:41 2011

Asterisk developer's documentation


cdr_syslog.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2009, malleable, LLC.
00005  *
00006  * Sean Bright <sean@malleable.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief syslog CDR logger
00022  *
00023  * \author Sean Bright <sean@malleable.com>
00024  *
00025  * See also
00026  * \arg \ref Config_cdr
00027  * \ingroup cdr_drivers
00028  */
00029 
00030 /*** MODULEINFO
00031     <depend>syslog</depend>
00032 ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 278132 $")
00037 
00038 #include "asterisk/module.h"
00039 #include "asterisk/lock.h"
00040 #include "asterisk/cdr.h"
00041 #include "asterisk/pbx.h"
00042 
00043 #include <syslog.h>
00044 
00045 #include "asterisk/syslog.h"
00046 
00047 static const char CONFIG[] = "cdr_syslog.conf";
00048 
00049 AST_THREADSTORAGE(syslog_buf);
00050 
00051 static const char name[] = "cdr-syslog";
00052 
00053 struct cdr_config {
00054    AST_DECLARE_STRING_FIELDS(
00055       AST_STRING_FIELD(ident);
00056       AST_STRING_FIELD(format);
00057    );
00058    int facility;
00059    int priority;
00060    ast_mutex_t lock;
00061    AST_LIST_ENTRY(cdr_config) list;
00062 };
00063 
00064 static AST_RWLIST_HEAD_STATIC(sinks, cdr_config);
00065 
00066 static void free_config(void)
00067 {
00068    struct cdr_config *sink;
00069    while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) {
00070       ast_mutex_destroy(&sink->lock);
00071       ast_free(sink);
00072    }
00073 }
00074 
00075 static int syslog_log(struct ast_cdr *cdr)
00076 {
00077    struct ast_channel *dummy;
00078    struct ast_str *str;
00079    struct cdr_config *sink;
00080 
00081    /* Batching saves memory management here.  Otherwise, it's the same as doing an
00082       allocation and free each time. */
00083    if (!(str = ast_str_thread_get(&syslog_buf, 16))) {
00084       return -1;
00085    }
00086 
00087    if (!(dummy = ast_dummy_channel_alloc())) {
00088       ast_log(AST_LOG_ERROR, "Unable to allocate channel for variable substitution.\n");
00089       return -1;
00090    }
00091 
00092    /* We need to dup here since the cdr actually belongs to the other channel,
00093       so when we release this channel we don't want the CDR getting cleaned
00094       up prematurely. */
00095    dummy->cdr = ast_cdr_dup(cdr);
00096 
00097    AST_RWLIST_RDLOCK(&sinks);
00098 
00099    AST_LIST_TRAVERSE(&sinks, sink, list) {
00100 
00101       ast_str_substitute_variables(&str, 0, dummy, sink->format);
00102 
00103       /* Even though we have a lock on the list, we could be being chased by
00104          another thread and this lock ensures that we won't step on anyone's
00105          toes.  Once each CDR backend gets it's own thread, this lock can be
00106          removed. */
00107       ast_mutex_lock(&sink->lock);
00108 
00109       openlog(sink->ident, LOG_CONS, sink->facility);
00110       syslog(sink->priority, "%s", ast_str_buffer(str));
00111       closelog();
00112 
00113       ast_mutex_unlock(&sink->lock);
00114    }
00115 
00116    AST_RWLIST_UNLOCK(&sinks);
00117 
00118    ast_channel_release(dummy);
00119 
00120    return 0;
00121 }
00122 
00123 static int load_config(int reload)
00124 {
00125    struct ast_config *cfg;
00126    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00127    int default_facility = LOG_LOCAL4;
00128    int default_priority = LOG_INFO;
00129    const char *catg = NULL, *tmp;
00130 
00131    cfg = ast_config_load(CONFIG, config_flags);
00132    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
00133       ast_log(AST_LOG_ERROR,
00134          "Unable to load %s. Not logging custom CSV CDRs to syslog.\n", CONFIG);
00135       return -1;
00136    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00137       return 0;
00138    }
00139 
00140    if (reload) {
00141       free_config();
00142    }
00143 
00144    if (!(ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "general", "facility")))) {
00145       int facility = ast_syslog_facility(tmp);
00146       if (facility < 0) {
00147          ast_log(AST_LOG_WARNING,
00148             "Invalid facility '%s' specified, defaulting to '%s'\n",
00149             tmp, ast_syslog_facility_name(default_facility));
00150       } else {
00151          default_facility = facility;
00152       }
00153    }
00154 
00155    if (!(ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "general", "priority")))) {
00156       int priority = ast_syslog_priority(tmp);
00157       if (priority < 0) {
00158          ast_log(AST_LOG_WARNING,
00159             "Invalid priority '%s' specified, defaulting to '%s'\n",
00160             tmp, ast_syslog_priority_name(default_priority));
00161       } else {
00162          default_priority = priority;
00163       }
00164    }
00165 
00166    while ((catg = ast_category_browse(cfg, catg))) {
00167       struct cdr_config *sink;
00168 
00169       if (!strcasecmp(catg, "general")) {
00170          continue;
00171       }
00172 
00173       if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "template"))) {
00174          ast_log(AST_LOG_WARNING,
00175             "No 'template' parameter found for '%s'.  Skipping.\n", catg);
00176          continue;
00177       }
00178 
00179       sink = ast_calloc_with_stringfields(1, struct cdr_config, 1024);
00180 
00181       if (!sink) {
00182          ast_log(AST_LOG_ERROR,
00183             "Unable to allocate memory for configuration settings.\n");
00184          free_config();
00185          break;
00186       }
00187 
00188       ast_mutex_init(&sink->lock);
00189       ast_string_field_set(sink, ident, catg);
00190       ast_string_field_set(sink, format, tmp);
00191 
00192       if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "facility"))) {
00193          sink->facility = default_facility;
00194       } else {
00195          int facility = ast_syslog_facility(tmp);
00196          if (facility < 0) {
00197             ast_log(AST_LOG_WARNING,
00198                "Invalid facility '%s' specified for '%s,' defaulting to '%s'\n",
00199                tmp, catg, ast_syslog_facility_name(default_facility));
00200          } else {
00201             sink->facility = facility;
00202          }
00203       }
00204 
00205       if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "priority"))) {
00206          sink->priority = default_priority;
00207       } else {
00208          int priority = ast_syslog_priority(tmp);
00209          if (priority < 0) {
00210             ast_log(AST_LOG_WARNING,
00211                "Invalid priority '%s' specified for '%s,' defaulting to '%s'\n",
00212                tmp, catg, ast_syslog_priority_name(default_priority));
00213          } else {
00214             sink->priority = priority;
00215          }
00216       }
00217 
00218       AST_RWLIST_INSERT_TAIL(&sinks, sink, list);
00219    }
00220 
00221    ast_config_destroy(cfg);
00222 
00223    return AST_RWLIST_EMPTY(&sinks) ? -1 : 0;
00224 }
00225 
00226 static int unload_module(void)
00227 {
00228    ast_cdr_unregister(name);
00229 
00230    if (AST_RWLIST_WRLOCK(&sinks)) {
00231       ast_cdr_register(name, ast_module_info->description, syslog_log);
00232       ast_log(AST_LOG_ERROR, "Unable to lock sink list.  Unload failed.\n");
00233       return -1;
00234    }
00235 
00236    free_config();
00237    AST_RWLIST_UNLOCK(&sinks);
00238    return 0;
00239 }
00240 
00241 static enum ast_module_load_result load_module(void)
00242 {
00243    int res;
00244 
00245    if (AST_RWLIST_WRLOCK(&sinks)) {
00246       ast_log(AST_LOG_ERROR, "Unable to lock sink list.  Load failed.\n");
00247       return AST_MODULE_LOAD_DECLINE;
00248    }
00249 
00250    res = load_config(0);
00251    AST_RWLIST_UNLOCK(&sinks);
00252    if (res) {
00253       return AST_MODULE_LOAD_DECLINE;
00254    }
00255    ast_cdr_register(name, ast_module_info->description, syslog_log);
00256    return AST_MODULE_LOAD_SUCCESS;
00257 }
00258 
00259 static int reload(void)
00260 {
00261    int res;
00262    if (AST_RWLIST_WRLOCK(&sinks)) {
00263       ast_log(AST_LOG_ERROR, "Unable to lock sink list.  Load failed.\n");
00264       return AST_MODULE_LOAD_DECLINE;
00265    }
00266 
00267    free_config();
00268    res = load_config(1);
00269    AST_RWLIST_UNLOCK(&sinks);
00270 
00271    return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00272 }
00273 
00274 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Customizable syslog CDR Backend",
00275    .load = load_module,
00276    .unload = unload_module,
00277    .reload = reload,
00278    .load_pri = AST_MODPRI_CDR_DRIVER,
00279 );

Generated on Wed Apr 6 11:29:41 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7