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 #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
00082
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
00093
00094
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
00104
00105
00106
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 );