[commit] r5250 - freeswitch/branches/anthonyl/log2file-branch/src/mod/loggers/mod_log2file
Author: anthonyl Date: Sat Jun 2 19:52:16 2007 New Revision: 5250 Added: freeswitch/branches/anthonyl/log2file-branch/src/mod/loggers/mod_log2file/ freeswitch/branches/anthonyl/log2file-branch/src/mod/loggers/mod_log2file/mod_log2file.c Log: updating with the latest mod_log2file code. Added: freeswitch/branches/anthonyl/log2file-branch/src/mod/loggers/mod_log2file/mod_log2file.c ============================================================================== --- (empty file) +++ freeswitch/branches/anthonyl/log2file-branch/src/mod/loggers/mod_log2file/mod_log2file.c Sat Jun 2 19:52:16 2007 @@ -0,0 +1,395 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II <anthmct@yahoo.com> + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony LaMantia <anthony@petabit.net> + * + * + * mod_log2file.c -- Filesystem Logging + * + */ +#include <switch.h> +#include <stdlib.h> +#include <syslog.h> + +#define MAX_LENGTH 1024 +#define DEFAULT_FORMAT "${data}" +#define DEFAULT_LOGFILE "/var/log/freeswitch" +#define DEFAULT_LIMIT 0x7FFFFFFF +#define WARM_FUZZY_OFFSET 64 +#define MAX_ROT 4096 /* why not */ +static const uint8_t STATIC_LEVELS[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; +static const char modname[] = "mod_log2file"; + +static switch_status_t load_config(void); +static switch_status_t mod_log2file_check(void); + +static switch_memory_pool_t *module_pool = NULL; +static switch_hash_t *log_hash = NULL; +static switch_hash_t *name_hash = NULL; +static int8_t all_level = -1; + +static struct { + unsigned int log_fd; + unsigned int log_size; /* keep the log size in check for rotation */ + unsigned int roll_size; /* the size that we want to rotate the file at */ + unsigned char *logfile; + unsigned char *format; + switch_file_t *log_afd; +} globals; + +SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_logfile, globals.logfile) +SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_format, globals.format) + +/* i know this is strange but it's the fastest way i could think of managing log levels. */ +/* i'd rather not try to search something each time we get a message to log */ +struct level_set { + int level; + int on; +}static levels[] = { + {SWITCH_LOG_EMERG, 0}, /* 0 */ + {SWITCH_LOG_ALERT, 0}, /* 1 */ + {SWITCH_LOG_CRIT, 0}, /* 2 */ + {SWITCH_LOG_ERROR, 0}, /* 3 */ + {SWITCH_LOG_WARNING, 0}, /* 4 */ + {SWITCH_LOG_NOTICE, 0}, /* 5 */ + {SWITCH_LOG_INFO, 0}, /* 6 */ + {SWITCH_LOG_DEBUG, 0}, /* 7 */ + {SWITCH_LOG_CONSOLE, 0}, /* 8 */ +}; +static switch_loadable_module_interface_t log2file_module_interface = { + /*.module_name */ modname, + /*.endpoint_interface */ NULL, + /*.timer_interface */ NULL, + /*.dialplan_interface */ NULL, + /*.codec_interface */ NULL, + /*.application_interface */ NULL, + /*.api_interface */ NULL, + /*.file_interface */ NULL, + /*.speech_interface */ NULL, + /*.directory_interface */ NULL +}; + +/* this may exist somewhere else in the code? */ +static void log_type2str(switch_log_level_t type) +{ + switch(type) { + case SWITCH_LOG_CONSOLE: + printf("[CONSOLE] "); + break; + case SWITCH_LOG_DEBUG: + printf("[DEBUG] "); + break; + case SWITCH_LOG_INFO: + printf("[INFO] "); + break; + case SWITCH_LOG_NOTICE: + printf("[NOTICE] "); + break; + case SWITCH_LOG_WARNING: + printf("[WARNING] "); + break; + case SWITCH_LOG_ERROR: + printf("[ERROR] "); + break; + case SWITCH_LOG_CRIT: + printf("[CRIT] "); + break; + case SWITCH_LOG_ALERT: + printf("[ALERT] "); + break; + case SWITCH_LOG_EMERG: + printf("[EMERG] "); + break; + default: + break; + } + return; +} + +void process_levels(char *p) +{ + char *q; + + while (q = strsep(&p, ",")) { + if (!strncasecmp(q, "emerg", strlen(q))) { + levels[SWITCH_LOG_EMERG].on = 1; + } else if (!strncasecmp(q, "alert", strlen(q))) { + levels[SWITCH_LOG_ALERT].on = 1; + } else if (!strncasecmp(q, "crit", strlen(q))) { + levels[SWITCH_LOG_CRIT].on = 1; + } else if (!strncasecmp(q, "error", strlen(q))) { + levels[SWITCH_LOG_ERROR].on = 1; + } else if (!strncasecmp(q, "warn", strlen(q))) { + levels[SWITCH_LOG_WARNING].on = 1; + } else if (!strncasecmp(q, "notice", strlen(q))) { + levels[SWITCH_LOG_NOTICE].on = 1; + } else if (!strncasecmp(q, "info", strlen(q))) { + levels[SWITCH_LOG_INFO].on = 1; + } else if (!strncasecmp(q, "debug", strlen(q))) { + levels[SWITCH_LOG_DEBUG].on = 1; + } else if (!strncasecmp(q, "console", strlen(q))) { + levels[SWITCH_LOG_CONSOLE].on = 1; + } else if (!strncasecmp(q, "all", strlen(q))) { + int i; + printf("all option!\n"); + for (i=0; i < (sizeof(levels) / sizeof(struct level_set)); i++) { + levels[i].on = 1; + } + } + + } + return; +} +static switch_status_t mod_log2file_openlogfile(void) +{ + int fd; + switch_file_t *afd; + switch_status_t stat; + + stat = switch_file_open(&afd, globals.logfile, + APR_CREATE| APR_READ | APR_WRITE | APR_APPEND, NULL, NULL); + + if (stat != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + globals.log_afd = afd; + mod_log2file_check(); + return SWITCH_STATUS_SUCCESS; +} + +/* rotate the log file */ +static switch_status_t mod_log2file_rotate(void) +{ + unsigned int i = 0; + unsigned char *p = NULL; + unsigned char *q = NULL; + switch_status_t stat = 0; + switch_size_t nbytes = 1024; + switch_file_t *l_afd = NULL; + + globals.log_size = 0; + stat = switch_file_seek(globals.log_afd, APR_SET, 0); + + if (stat != SWITCH_STATUS_SUCCESS) + return SWITCH_STATUS_FALSE; + + p = malloc(strlen(globals.logfile)+WARM_FUZZY_OFFSET); + if (!p) { + return SWITCH_STATUS_FALSE; + } + q = malloc(1024); + if (!q) { + free(p); + return SWITCH_STATUS_FALSE; + } + memset(p, '\0', strlen(globals.logfile)+WARM_FUZZY_OFFSET); + for (i=1;i<MAX_ROT; i++) { + sprintf(p, "%s.%i", globals.logfile, i); + stat = switch_file_open(l_afd, p, APR_READ, NULL, NULL); + if (stat == SWITCH_STATUS_SUCCESS) { + switch_file_close(l_afd); + continue; + } + stat = switch_file_open(l_afd, p, APR_READ | APR_WRITE | APR_CREATE , NULL, NULL); + if (stat == SWITCH_STATUS_SUCCESS) + break; + } + while ((stat = switch_file_read(&globals.log_afd, q, &nbytes)) == SWITCH_STATUS_SUCCESS) { + switch_file_write(l_afd, q, &nbytes); + memset(q, '\0', 1024); + nbytes = 1024; + } + stat = switch_file_seek(&globals.log_afd, APR_SET, 0); + free(p); + free(q); + return SWITCH_STATUS_SUCCESS; +} + +/* check the size of the file for rotation */ +static switch_status_t mod_log2file_check(void) +{ + switch_status_t stat; + switch_size_t fsize; + fsize = switch_file_get_size(&globals.log_afd); + + if (stat != SWITCH_STATUS_SUCCESS) + return SWITCH_STATUS_FALSE; + + if (fsize >= globals.roll_size) { + return mod_log2file_rotate(); + } + + return SWITCH_STATUS_SUCCESS; +} + +/* write to the actual logfile */ +static switch_status_t mod_log2file_write(char *fmt, ...) +{ + unsigned int len; + char *log_data; + switch_status_t stat; + va_list args; + va_start(args, fmt); + printf("Mod Log To File Write\n"); +#ifdef WIN32 + len = _vasprintf(&log_data, fmt, args); +#else + len = vasprintf(&log_data, fmt, args); +#endif + if (len <= 0) + return SWITCH_STATUS_FALSE; + stat = switch_file_write(&globals.log_afd, log_data, len); + if (stat != SWITCH_STATUS_SUCCESS) + return SWITCH_STATUS_FALSE; + globals.log_size += len; + /* we may want to hold back on this for preformance reasons */ + mod_log2file_check(); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t mod_log2file_logger(const switch_log_node_t *node, switch_log_level_t level) +{ + uint8_t *lookup = NULL; + char line_no[sizeof(int)*8+1]; + char date[80] = ""; + switch_time_exp_t time; + switch_size_t retsize; + char *message = NULL; + + if (!levels[node->level].on) { + return SWITCH_STATUS_SUCCESS; + } + + message = (char *)malloc(strlen(globals.format)+2); + switch_copy_string(message, globals.format, strlen(globals.format)+1); + + message = switch_string_replace(message, "${message}", node->content); + + if (switch_time_exp_lt(&time, node->timestamp) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + + switch_strftime(date, &retsize, sizeof(date), "%Y-%m-%d %T", &time); + + message = switch_string_replace(message, "${time}", date); + message = switch_string_replace(message, "${file}", node->file); + message = switch_string_replace(message, "${func}", node->func); + + snprintf(line_no, sizeof(line_no), "%d", node->line); + message = switch_string_replace(message, "${line}", line_no); + + /* work with the log type */ + log_type2str(node->level); + printf("\n"); + printf("Type: (%i)\n", node->level); + if (node->file) + printf("File: %s\n", node->file); + if (node->line) + printf("Line: %i\n", node->line); + if (node->func) + printf("Func: %s\n", node->func); + if (node->data) + printf("Data: %s\n", node->data); + if (node->content) + printf("Cont: %s\n", node->content); + + + if (!switch_strlen_zero(message)) { + mod_log2file_write("%s", message); + } + + return SWITCH_STATUS_SUCCESS; +} +static switch_status_t load_config(void) +{ + char *cf = "log2file.conf"; + switch_xml_t cfg, xml, settings, param; + + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); + } else { + if ((settings = switch_xml_child(cfg, "settings"))) { + for (param = switch_xml_child(settings, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + if (!strcmp(var, "logfile")) { + set_global_logfile(val); + } else if (!strcmp(var, "format")) { + set_global_format(val); + } else if (!strcmp(var, "level")) { + process_levels(val); + } else if (!strcmp(var, "rollover")) { + globals.roll_size = atoi(val); + } + } + } + switch_xml_free(xml); + } + if (globals.roll_size == 0) { + globals.roll_size = DEFAULT_LIMIT; + } + if (switch_strlen_zero(globals.logfile)) { + set_global_logfile(DEFAULT_LOGFILE); + } + if (switch_strlen_zero(globals.format)) { + set_global_format(DEFAULT_FORMAT); + } + return 0; +} + +SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **interface, char *filename) +{ + switch_status_t status; + + if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n"); + return SWITCH_STATUS_TERM; + } + + *interface = &log2file_module_interface; + + if ((status=load_config()) != SWITCH_STATUS_SUCCESS) { + return status; + } + mod_log2file_openlogfile(); + switch_log_bind_logger(mod_log2file_logger, SWITCH_LOG_DEBUG); + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MOD_DECLARE(switch_status_t) switch_module_unload(const switch_loadable_module_interface_t **interface) +{ + closelog(); + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:nil + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */
participants (1)
-
Freeswitch SVN