00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 337973 $")
00038
00039 #include "asterisk/module.h"
00040 #include "asterisk/lock.h"
00041 #include "asterisk/cdr.h"
00042 #include "asterisk/pbx.h"
00043
00044 #include <syslog.h>
00045
00046 #include "asterisk/syslog.h"
00047
00048 static const char CONFIG[] = "cdr_syslog.conf";
00049
00050 AST_THREADSTORAGE(syslog_buf);
00051
00052 static const char name[] = "cdr-syslog";
00053
00054 struct cdr_config {
00055 AST_DECLARE_STRING_FIELDS(
00056 AST_STRING_FIELD(ident);
00057 AST_STRING_FIELD(format);
00058 );
00059 int facility;
00060 int priority;
00061 ast_mutex_t lock;
00062 AST_LIST_ENTRY(cdr_config) list;
00063 };
00064
00065 static AST_RWLIST_HEAD_STATIC(sinks, cdr_config);
00066
00067 static void free_config(void)
00068 {
00069 struct cdr_config *sink;
00070 while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) {
00071 ast_mutex_destroy(&sink->lock);
00072 ast_free(sink);
00073 }
00074 }
00075
00076 static int syslog_log(struct ast_cdr *cdr)
00077 {
00078 struct ast_channel *dummy;
00079 struct ast_str *str;
00080 struct cdr_config *sink;
00081
00082
00083
00084 if (!(str = ast_str_thread_get(&syslog_buf, 16))) {
00085 return -1;
00086 }
00087
00088 if (!(dummy = ast_dummy_channel_alloc())) {
00089 ast_log(AST_LOG_ERROR, "Unable to allocate channel for variable substitution.\n");
00090 return -1;
00091 }
00092
00093
00094
00095
00096 dummy->cdr = ast_cdr_dup(cdr);
00097
00098 AST_RWLIST_RDLOCK(&sinks);
00099
00100 AST_LIST_TRAVERSE(&sinks, sink, list) {
00101
00102 ast_str_substitute_variables(&str, 0, dummy, sink->format);
00103
00104
00105
00106
00107
00108 ast_mutex_lock(&sink->lock);
00109
00110 openlog(sink->ident, LOG_CONS, sink->facility);
00111 syslog(sink->priority, "%s", ast_str_buffer(str));
00112 closelog();
00113
00114 ast_mutex_unlock(&sink->lock);
00115 }
00116
00117 AST_RWLIST_UNLOCK(&sinks);
00118
00119 ast_channel_unref(dummy);
00120
00121 return 0;
00122 }
00123
00124 static int load_config(int reload)
00125 {
00126 struct ast_config *cfg;
00127 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00128 int default_facility = LOG_LOCAL4;
00129 int default_priority = LOG_INFO;
00130 const char *catg = NULL, *tmp;
00131
00132 cfg = ast_config_load(CONFIG, config_flags);
00133 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
00134 ast_log(AST_LOG_ERROR,
00135 "Unable to load %s. Not logging custom CSV CDRs to syslog.\n", CONFIG);
00136 return -1;
00137 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00138 return 0;
00139 }
00140
00141 if (reload) {
00142 free_config();
00143 }
00144
00145 if (!(ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "general", "facility")))) {
00146 int facility = ast_syslog_facility(tmp);
00147 if (facility < 0) {
00148 ast_log(AST_LOG_WARNING,
00149 "Invalid facility '%s' specified, defaulting to '%s'\n",
00150 tmp, ast_syslog_facility_name(default_facility));
00151 } else {
00152 default_facility = facility;
00153 }
00154 }
00155
00156 if (!(ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "general", "priority")))) {
00157 int priority = ast_syslog_priority(tmp);
00158 if (priority < 0) {
00159 ast_log(AST_LOG_WARNING,
00160 "Invalid priority '%s' specified, defaulting to '%s'\n",
00161 tmp, ast_syslog_priority_name(default_priority));
00162 } else {
00163 default_priority = priority;
00164 }
00165 }
00166
00167 while ((catg = ast_category_browse(cfg, catg))) {
00168 struct cdr_config *sink;
00169
00170 if (!strcasecmp(catg, "general")) {
00171 continue;
00172 }
00173
00174 if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "template"))) {
00175 ast_log(AST_LOG_WARNING,
00176 "No 'template' parameter found for '%s'. Skipping.\n", catg);
00177 continue;
00178 }
00179
00180 sink = ast_calloc_with_stringfields(1, struct cdr_config, 1024);
00181
00182 if (!sink) {
00183 ast_log(AST_LOG_ERROR,
00184 "Unable to allocate memory for configuration settings.\n");
00185 free_config();
00186 break;
00187 }
00188
00189 ast_mutex_init(&sink->lock);
00190 ast_string_field_set(sink, ident, catg);
00191 ast_string_field_set(sink, format, tmp);
00192
00193 if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "facility"))) {
00194 sink->facility = default_facility;
00195 } else {
00196 int facility = ast_syslog_facility(tmp);
00197 if (facility < 0) {
00198 ast_log(AST_LOG_WARNING,
00199 "Invalid facility '%s' specified for '%s,' defaulting to '%s'\n",
00200 tmp, catg, ast_syslog_facility_name(default_facility));
00201 } else {
00202 sink->facility = facility;
00203 }
00204 }
00205
00206 if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "priority"))) {
00207 sink->priority = default_priority;
00208 } else {
00209 int priority = ast_syslog_priority(tmp);
00210 if (priority < 0) {
00211 ast_log(AST_LOG_WARNING,
00212 "Invalid priority '%s' specified for '%s,' defaulting to '%s'\n",
00213 tmp, catg, ast_syslog_priority_name(default_priority));
00214 } else {
00215 sink->priority = priority;
00216 }
00217 }
00218
00219 AST_RWLIST_INSERT_TAIL(&sinks, sink, list);
00220 }
00221
00222 ast_config_destroy(cfg);
00223
00224 return AST_RWLIST_EMPTY(&sinks) ? -1 : 0;
00225 }
00226
00227 static int unload_module(void)
00228 {
00229 ast_cdr_unregister(name);
00230
00231 if (AST_RWLIST_WRLOCK(&sinks)) {
00232 ast_cdr_register(name, ast_module_info->description, syslog_log);
00233 ast_log(AST_LOG_ERROR, "Unable to lock sink list. Unload failed.\n");
00234 return -1;
00235 }
00236
00237 free_config();
00238 AST_RWLIST_UNLOCK(&sinks);
00239 return 0;
00240 }
00241
00242 static enum ast_module_load_result load_module(void)
00243 {
00244 int res;
00245
00246 if (AST_RWLIST_WRLOCK(&sinks)) {
00247 ast_log(AST_LOG_ERROR, "Unable to lock sink list. Load failed.\n");
00248 return AST_MODULE_LOAD_DECLINE;
00249 }
00250
00251 res = load_config(0);
00252 AST_RWLIST_UNLOCK(&sinks);
00253 if (res) {
00254 return AST_MODULE_LOAD_DECLINE;
00255 }
00256 ast_cdr_register(name, ast_module_info->description, syslog_log);
00257 return AST_MODULE_LOAD_SUCCESS;
00258 }
00259
00260 static int reload(void)
00261 {
00262 int res;
00263 if (AST_RWLIST_WRLOCK(&sinks)) {
00264 ast_log(AST_LOG_ERROR, "Unable to lock sink list. Load failed.\n");
00265 return AST_MODULE_LOAD_DECLINE;
00266 }
00267
00268 if ((res = load_config(1))) {
00269 free_config();
00270 }
00271
00272 AST_RWLIST_UNLOCK(&sinks);
00273
00274 return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00275 }
00276
00277 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Customizable syslog CDR Backend",
00278 .load = load_module,
00279 .unload = unload_module,
00280 .reload = reload,
00281 .load_pri = AST_MODPRI_CDR_DRIVER,
00282 );