diff options
author | Dmitri Pal <dpal@dpal.csb> | 2009-02-23 10:38:06 -0500 |
---|---|---|
committer | Dmitri Pal <dpal@dpal.csb> | 2009-02-23 10:38:06 -0500 |
commit | d986aeb99fa33967374290bf7ce75eab76c6d446 (patch) | |
tree | e85af838cd95b43c4f1be5bc2203a1a3474ba589 /sinks | |
download | elapi_draft-d986aeb99fa33967374290bf7ce75eab76c6d446.tar.gz elapi_draft-d986aeb99fa33967374290bf7ce75eab76c6d446.tar.xz elapi_draft-d986aeb99fa33967374290bf7ce75eab76c6d446.zip |
Initial commit.
Diffstat (limited to 'sinks')
-rw-r--r-- | sinks/Makefile.am | 1 | ||||
-rw-r--r-- | sinks/elapi_sink.h | 56 | ||||
-rw-r--r-- | sinks/file/elapi_sink_file.c | 268 | ||||
-rw-r--r-- | sinks/stderr/elapi_sink_stderr.c | 135 | ||||
-rw-r--r-- | sinks/syslog/elapi_sink_syslog.c | 287 |
5 files changed, 747 insertions, 0 deletions
diff --git a/sinks/Makefile.am b/sinks/Makefile.am new file mode 100644 index 0000000..125e373 --- /dev/null +++ b/sinks/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = stderr syslog diff --git a/sinks/elapi_sink.h b/sinks/elapi_sink.h new file mode 100644 index 0000000..0c58c89 --- /dev/null +++ b/sinks/elapi_sink.h @@ -0,0 +1,56 @@ +/* Copyright */ + +#ifndef ELAPI_SINK_H +#define ELAPI_SINK_H + +#include <time.h> +#include "elapi_collection.h" + +#define ELAPI_SINK_OK 0 /* Sink can be used for logging */ +#define ELAPI_SINK_SUSPENDED 1 /* Sink is temporary disabled due to recoverable error */ +#define ELAPI_SINK_DISABLED 2 /* Sink is explicitely disabled by the application */ +#define ELAPI_SINK_PULSE 3 /* Sink is disabled for this one event */ + +#define SINK_LIB_NAME_SIZE 100 +#define SINK_ENTRY_POINT "get_sink_info" +#define SINK_NAME_TEMPLATE "libelapi_sink_%s.so" +#define SINK_NEVER_RETRY -1 + +struct data_descriptor { + char *appname; + void *config; + void *internal_data; +}; + +/* Log facility callbacks */ +typedef int (*init_fn)(struct data_descriptor *dblock); +typedef void (*cleanup_fn)(struct data_descriptor *dblock); +typedef int (*format_fn)(struct data_descriptor *dblock, struct collection_item *event); +typedef int (*submit_fn)(struct data_descriptor *dblock); +typedef void (*close_fn)(struct data_descriptor *dblock); + +struct sink_capability { + int retry_interval; + init_fn init_cb; + cleanup_fn cleanup_cb; + format_fn format_cb; + submit_fn submit_cb; + close_fn close_cb; +}; + +/* The only open function the link can expose */ +typedef void (*capability_fn)(struct sink_capability *sink_cpb_block); + +struct sink_descriptor { + struct sink_capability sink_cpb_block; + struct data_descriptor dblock; + int suspended; + time_t lasttry; + void *lib_handle; +}; + +/*Standard capability function */ +void get_sink_info(struct sink_capability *sink_cpb_block); + +#endif + diff --git a/sinks/file/elapi_sink_file.c b/sinks/file/elapi_sink_file.c new file mode 100644 index 0000000..8358854 --- /dev/null +++ b/sinks/file/elapi_sink_file.c @@ -0,0 +1,268 @@ +/* Copyright */ + +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include "log_file_facility.h" +#include "log_util.h" +#include "log_debug.h" + +/******************** MAIN MODULE FUNCTIONS ****************************/ +/* Function to fill in the facility configuration */ +int create_file_facility_config(struct file_config **config, char *path, int mode) +{ + struct file_config *cfg = (struct file_config *)(NULL); + + DEBUG_STRING("create_file_facility_config","Entry point"); + + errno = 0; + + /* Allocate memory for the structure */ + cfg = (struct file_config *)(malloc(sizeof(struct file_config))); + + if(cfg == (struct file_config *)(NULL)) return errno; + + /* Initialize. */ + if(path != NULL) { + cfg->path = strdup(path); + if(cfg->path == NULL) { + free(cfg); + return errno; + } + } + else cfg->path = NULL; + + cfg->mode = mode; + cfg->ff = NULL; + + *config = cfg; + + DEBUG_STRING("create_file_facility_config","Exit point"); + + return 0; + +} + +/* Function cleans the config */ +void clean_file_facility_config(struct file_config **config) +{ + DEBUG_STRING("clean_file_facility_config","Entry point"); + + if(config == (struct file_config **)(NULL)) return; + + if(*config != (struct file_config *)(NULL)) { + if((*config)->path != NULL) free((*config)->path); + free(*config); + } + + DEBUG_STRING("clean_file_facility_config","Exit point"); +} + +/***** Standard functions each facility has to provide *****/ +/* Initialize facility - open files, establish connnectons, etc... */ +int file_facility_init(struct data_descriptor *dblock) +{ + struct file_config *cfg; + struct file_event_data *event_data; + + DEBUG_STRING("file_facility_init","Entry point"); + + /* Prepare the block where the format function will store its data */ + errno = 0; + event_data = malloc(sizeof(struct file_event_data)); + if(event_data == NULL) return errno; + dblock->event_data = event_data; + + /* Deal with file */ + errno = 0; + cfg = (struct file_config *)(dblock->config); + + /* If we have "path" open file and trancate if needed */ + if(cfg->path != NULL) { + if(cfg->mode & EL_FILE_TRUNCATE) { + cfg->ff = fopen(cfg->path,"w"); + if(cfg->ff == (FILE *)(NULL)) return errno; + if(cfg->mode & EL_FILE_OPEN_PER_CMD) { + fclose(cfg->ff); + cfg->ff = NULL; + } + } + } + else { + cfg->ff=stderr; + cfg->mode = EL_FILE_KEEP_OPEN; + } + + DEBUG_STRING("file_facility_init","Exit point"); + return 0; +} + +/* Formatting calback */ +int file_facility_format(struct data_descriptor *dblock,struct event_handle *event) +{ + struct file_event_data *event_data; + struct event_item *item = NULL; + int length = 0; + int size = EL_FILE_BLOCK_SIZE; + int item_len = 0; + int property_len = 0; + int nest_level = 0; + int cnt = 0; + int first = 1; + + DEBUG_STRING("file_facility_format","Entry point"); + + event_data = dblock->event_data; + + /* Prepare momory */ + errno = 0; + event_data->buffer = malloc(size); + if(event_data->buffer == NULL) return errno; + + /* Loop and add data */ + start_iterate_event(event); + while((item = iterate_event(event)) != (struct event_item *)(NULL)) { + + DEBUG_STRING("file_facility_format","Top of the item processing loop"); + + /* Check the size and increase memory if needed */ + /* Expect more than one byte to express nesting */ + item_len = util_get_item_len(item) + 2 * abs(item->nest_level - nest_level) + 2 * nest_level + 1; + + DEBUG_NUMBER("expected item length",item_len); + + if(item_len+length >= size) { + size+=EL_FILE_BLOCK_SIZE; + DEBUG_NUMBER("expanding data to the given size",size); + event_data->buffer = realloc(event_data->buffer,size); + if(event_data->buffer == NULL) return errno; + } + + DEBUG_NUMBER("current nesting",nest_level); + DEBUG_NUMBER("item nesting",item->nest_level); + + /* Add nesting closing parenteces */ + cnt = 0; + while((item->nest_level + cnt) < nest_level) { + *(event_data->buffer+length)=')'; + cnt++; + length++; + } + + /* Add nesting open parenteces */ + if(item->nest_level > nest_level) { + *(event_data->buffer+length)=' '; + length++; + *(event_data->buffer+length)='('; + length++; + first = 0; + } + else { + /* Add comma between items */ + if(first) first = 0; + else { + *(event_data->buffer+length)=','; + length++; + } + } + + /* Add property data pair */ + util_add_data(event_data->buffer, &length, item); + +#ifdef ELAPI_LOG_DEBUG + *(event_data->buffer+length)='\0'; +#endif + DEBUG_STRING("Output",event_data->buffer); + + + nest_level = item->nest_level; + } + + /* Add nesting closing parenteces */ + cnt = 0; + while(cnt < nest_level) { + *(event_data->buffer+length)=')'; + cnt++; + length++; + } + + DEBUG_STRING("file_facility_format","Exit point"); + + return 0; +} + +/* Cleanup per event internal data */ +void file_facility_cleanup(struct data_descriptor *dblock) +{ + struct file_event_data *event_data; + + DEBUG_STRING("file_facility_cleanup","Entry point"); + + if(dblock->event_data != NULL) { + event_data = (struct file_event_data *)(dblock->event_data); + if(event_data->buffer != NULL) { + free(event_data->buffer); + event_data->buffer = NULL; + } + } + DEBUG_STRING("file_facility_cleanup","Exit point"); +} + +/* Logging calback */ +int file_facility_log(struct data_descriptor *dblock) +{ + struct file_event_data *event_data; + struct file_config *cfg; + + DEBUG_STRING("file_facility_log","Entry point"); + + errno = 0; + + cfg = (struct file_config *)(dblock->config); + + /* Open file if needed */ + if((cfg->path != NULL) && (cfg->mode & EL_FILE_OPEN_PER_CMD)) { + cfg->ff = fopen(cfg->path,"a"); + if(cfg->ff == (FILE *)(NULL)) return errno; + } + + event_data = (struct file_event_data *)(dblock->event_data); + fprintf(cfg->ff,"%s\n",event_data->buffer); + + /* Close file if needed */ + if((cfg->path != NULL) && (cfg->mode & EL_FILE_OPEN_PER_CMD)) { + fclose(cfg->ff); + cfg->ff = (FILE *)(NULL); + } + + DEBUG_STRING("file_facility_log","Exit point"); + return 0; +} + +/* Close facility */ +void file_facility_close(struct data_descriptor *dblock) +{ + struct file_config *cfg; + struct file_event_data *event_data; + + DEBUG_STRING("file_facility_close","Entry point"); + + /* Close file if needed */ + cfg = (struct file_config *)(dblock->config); + if((cfg->path != NULL) && (cfg->ff != (FILE *)(NULL))) { + fclose(cfg->ff); + cfg->ff = (FILE *)(NULL); + } + + /* Clean internal data storage */ + if(dblock->event_data != NULL) { + event_data = (struct file_event_data *)(dblock->event_data); + if(event_data->buffer != NULL) free(event_data->buffer); + free(event_data); + dblock->event_data = NULL; + } + + DEBUG_STRING("file_facility_close","Exit point"); +} + + diff --git a/sinks/stderr/elapi_sink_stderr.c b/sinks/stderr/elapi_sink_stderr.c new file mode 100644 index 0000000..17144ac --- /dev/null +++ b/sinks/stderr/elapi_sink_stderr.c @@ -0,0 +1,135 @@ +/* Copyright */ + +#include <stdio.h> +#include <errno.h> +#include <malloc.h> +#include "elapi_sink.h" +#include "elapi_collection.h" +#include "elapi_debug.h" +#include "elapi_util.h" + + +/***** Standard functions each facility has to provide *****/ +/* Initialize facility - open files, establish connnectons, etc... */ +static int stderr_sink_init(struct data_descriptor *dblock) +{ + struct serial_data *serialized_data; + + DEBUG_STRING("stderr_sink_init","Entry"); + + /* Prepare the block where the format function will store its data */ + errno = 0; + dblock->internal_data = NULL; + serialized_data = malloc(sizeof(struct serial_data)); + if(serialized_data == NULL) return errno; + + serialized_data->buffer = NULL; + serialized_data->size = 0; + serialized_data->length = 0; + serialized_data->nest_level = 0; + + dblock->internal_data = (void *)(serialized_data); + + + DEBUG_NUMBER("DBLOCK in init",dblock); + DEBUG_NUMBER("internal data in init",dblock->internal_data); + DEBUG_STRING("Application name in init:",dblock->appname); + + DEBUG_STRING("stderr_sink_init","Exit"); + return EOK; +} + + +/* Formatting calback */ +static int stderr_sink_format(struct data_descriptor *dblock,struct collection_item *event) +{ + struct serial_data *serialized_data; + int error = EOK; + + DEBUG_STRING("stderr_sink_format","Entry"); + DEBUG_NUMBER("DBLOCK in format",dblock); + DEBUG_NUMBER("internal data in format",dblock->internal_data); + + serialized_data = (struct serial_data *)(dblock->internal_data); + + /* Traverse collection */ + error = traverse_collection(event,ELAPI_TRAVERSE_DEFAULT | ELAPI_TRAVERSE_END ,serialize,(void *)(serialized_data)); + if(error) { + DEBUG_NUMBER("traverse_collection returned error",error); + return error; + } + + DEBUG_STRING("stderr_sink_format","Exit"); + return EOK; +} + + +/* Cleanup per event internal data after a failure */ +static void stderr_sink_cleanup(struct data_descriptor *dblock) +{ + struct serial_data *serialized_data; + DEBUG_STRING("stderr_sink_cleanup","Entry"); + + serialized_data = (struct serial_data *)(dblock->internal_data); + + if(serialized_data->buffer != NULL) { + free(serialized_data->buffer); + serialized_data->buffer = NULL; + serialized_data->size = 0; + serialized_data->length = 0; + serialized_data->nest_level = 0; + } + + DEBUG_STRING("stderr_sink_cleanup","Exit"); +} + +/* Close facility */ +static void stderr_sink_close(struct data_descriptor *dblock) +{ + DEBUG_STRING("stderr_sink_close","Entry"); + + if(dblock->internal_data != NULL) { + stderr_sink_cleanup(dblock); + free(dblock->internal_data); + dblock->internal_data=NULL; + } + + DEBUG_STRING("stderr_sink_close","Exit"); +} + + +/* Logging calback */ +static int stderr_sink_submit(struct data_descriptor *dblock) +{ + struct serial_data *serialized_data; + DEBUG_STRING("stderr_sink_submit","Entry"); + DEBUG_NUMBER("DBLOCK in submit",dblock); + DEBUG_NUMBER("internal data in submit",dblock->internal_data); + + serialized_data = (struct serial_data *)(dblock->internal_data); + + DEBUG_STRING("OUTPUT:",serialized_data->buffer); + + fprintf(stderr,"%s\n",serialized_data->buffer); + + stderr_sink_cleanup(dblock); + + DEBUG_STRING("stderr_sink_submit","Exit"); + return EOK; +} + +/* Return a filled in structure */ +void get_sink_info(struct sink_capability *sink_cpb_block) +{ + DEBUG_STRING("get_sink_info","Entry"); + + sink_cpb_block->retry_interval = SINK_NEVER_RETRY; + sink_cpb_block->init_cb = stderr_sink_init; + sink_cpb_block->cleanup_cb = stderr_sink_cleanup; + sink_cpb_block->format_cb = stderr_sink_format; + sink_cpb_block->submit_cb = stderr_sink_submit; + sink_cpb_block->close_cb = stderr_sink_close; + + DEBUG_STRING("get_sink_info","Exit"); +} + diff --git a/sinks/syslog/elapi_sink_syslog.c b/sinks/syslog/elapi_sink_syslog.c new file mode 100644 index 0000000..d3a669d --- /dev/null +++ b/sinks/syslog/elapi_sink_syslog.c @@ -0,0 +1,287 @@ +/* Copyright */ + +#include <stdio.h> +#include <errno.h> +#include <malloc.h> +#include "elapi_sink.h" +#include "elapi_collection.h" +#include "elapi_debug.h" +#include "elapi_util.h" +#include "elapi_ini.h" + +/* FIXME - this should be taken from the config.h generated by autotools */ +#define SYSLOG_RETRY 60 +#define syslog_audit_config "/home/dpal/IPA/Code/elapi/etc/syslog_defaults.conf" +#define syslog_audit_dir "/home/dpal/IPA/Code/elapi/etc/syslog_defaults.d" + +/* FIXME there is currently no code + * to make sure we do not call syslog functions from multiple dispatchers. + * We probably should create a mutext at the load of the library and + * set a flag when the init function is called the first time + * and not call the openlog any more times. + * But I guess syslog can deal with this internally. + */ + + +struct syslog_event { + struct serial_data sd; + int priority; +} + + +/* Default conmfiguration for syslog */ +struct syslog_config { + int option; + int facility; + int level; + char *ident; +}; + +/* Internal function to intialize configuration */ +static int init_config(struct data_descriptor *dblock) +{ + struct syslog_conf *conf_data; + struct collection_item *file_config = (struct collection_item *)(NULL); + int found = 0; + int *option_cfg = (int *)(NULL); + int *facility_cfg = (int *)(NULL); + int *level_cfg = (int *)(NULL); + char *ident_cfg = NULL; + + DEBUG_STRING("init_config","Entry"); + + /* Allocate configuration data */ + conf_data = (struct syslog_conf *)(malloc(sizeof(struct syslog_config))); + if(conf_data == (struct syslog_conf *)(NULL)) return errno; + + /* Read configuration from the configuration file if any */ + (void)config_to_collection(dblock->appname, syslog_audit_config, syslog_audit_dir, &file_config); + + conf_data->option = LOG_ODELAY; + conf_data->facility = LOG_USER; + conf_data->level = LOG_INFO; + conf_data->ident = NULL; + + DEBUG_NUMBER("Option",conf_data->option); + DEBUG_NUMBER("Facility",conf_data->facility); + DEBUG_NUMBER("Level",conf_data->level); + DEBUG_STRING("Identity",conf_data->ident); + + /* Update defaults with settings from the file */ + error = get_value_from_config((void *)(&option_cfg),ELAPI_TYPE_INT, INI_DEFAULT_SECTION,"option",file_config); + if(error != EOK) { + /* There is fundamentally something wrong */ + DEBUG_NUMBER("Attempt to get option returned error",error); + return error; + } + + /* Get the value */ + if(option_cfg != (int *)(NULL)) { + conf_data->option = *option_cfg; + free((void *)(option_cfg); + } + + error = get_value_from_config((void *)(&facility_cfg),ELAPI_TYPE_INT, INI_DEFAULT_SECTION,"facility",file_config); + if(error != EOK) { + /* There is fundamentally something wrong */ + DEBUG_NUMBER("Attempt to get option returned error",error); + return error; + } + + /* Get the value */ + if(facility_cfg != (int *)(NULL)) { + conf_data->facility = *facility_cfg; + free((void *)(facility_cfg); + } + + error = get_value_from_config((void *)(&level_cfg),ELAPI_TYPE_INT, INI_DEFAULT_SECTION,"level",file_config); + if(error != EOK) { + /* There is fundamentally something wrong */ + DEBUG_NUMBER("Attempt to get option returned error",error); + return error; + } + + /* Get the value */ + if(level_cfg != (int *)(NULL)) { + conf_data->level = *level_cfg; + free((void *)(level_cfg); + } + + error = get_value_from_config((void *)(&ident_cfg),ELAPI_TYPE_STRING, INI_DEFAULT_SECTION,"identity",file_config); + if(error != EOK) { + /* There is fundamentally something wrong */ + DEBUG_NUMBER("Attempt to get option returned error",error); + return error; + } + + /* Get the value */ + if(ident_cfg != (char *)(NULL)) { + conf_data->ident = *ident_cfg; + free((void *)(ident_cfg); + } + + + DEBUG_NUMBER("Option (after conf file):",conf_data->option); + DEBUG_NUMBER("Facility (after conf file):",conf_data->facility); + DEBUG_NUMBER("Level (after conf file):",conf_data->level); + DEBUG_STRING("Identity (after conf file):",conf_data->ident); + + dblock->config = (void *)(conf_data); + + openlog(conf_data->ident,conf_data->option,conf_data->facility); + + DEBUG_STRING("init_config","Entry"); + return EOK; +} + +/***** Standard functions each facility has to provide *****/ +/* Initialize facility - open files, establish connnectons, etc... */ +static int syslog_sink_init(struct data_descriptor *dblock) +{ + struct syslog_event *event_storage; + int error; + + DEBUG_STRING("syslog_sink_init","Entry"); + + /* Prepare the block where the format function will store its data */ + errno = 0; + dblock->internal_data = NULL; + event_storage = (struct syslog_event *)(malloc(sizeof(struct syslog_event))); + if(event_storage == (struct syslog_event *)(NULL)) return errno; + + event_storage->sd.buffer = NULL; + event_storage->sd.size = 0; + event_storage->sd.length = 0; + event_storage->sd.nest_level = 0; + + dblock->internal_data = (void *)(event_storage); + + /* Prepare the configuration data block */ + if((error = init_config(dblock)) { + DEBUG_NUMBER("Failed to init config",error); + free(dblock->internal_data); + dblock->internal_data = NULL; + return error; + } + + DEBUG_NUMBER("DBLOCK in init",dblock); + DEBUG_NUMBER("internal data in init",dblock->internal_data); + + DEBUG_STRING("syslog_sink_init","Exit"); + return EOK; +} + + +/* Formatting calback */ +static int syslog_sink_format(struct data_descriptor *dblock,struct collection_item *event) +{ + struct syslog_event *event_storage; + struct syslog_config *config; + + int error = EOK; + + DEBUG_STRING("syslog_sink_format","Entry"); + DEBUG_NUMBER("DBLOCK in format",dblock); + DEBUG_NUMBER("internal data in format",dblock->internal_data); + + event_storage = (struct event_storage *)(dblock->internal_data); + config = (struct event_storage *)(dblock->config); + + event_storage->priority = config->level | config->facility; + + /* FIXME form priority here */ + + + + + /* Traverse collection */ + error = traverse_collection(event,ELAPI_TRAVERSE_DEFAULT | ELAPI_TRAVERSE_END ,serialize,(void *)(event_storage->sd)); + if(error) { + DEBUG_NUMBER("traverse_collection returned error",error); + return error; + } + + DEBUG_STRING("syslog_sink_format","Exit"); + return EOK; +} + + +/* Cleanup per event internal data after a failure */ +static void syslog_sink_cleanup(struct data_descriptor *dblock) +{ + struct syslog_event *event_storage; + struct syslog_config *config; + + DEBUG_STRING("syslog_sink_cleanup","Entry"); + + event_storage = (struct event_storage *)(dblock->internal_data); + config = (struct event_storage *)(dblock->config); + + if(event_storage->sd.buffer != NULL) { + free(event_storage->sd.buffer); + event_storage->sd.buffer = NULL; + event_storage->sd.size = 0; + event_storage->sd.length = 0; + event_storage->sd.nest_level = 0; + event_storage->priority = config->level | config->facility; + } + + DEBUG_STRING("syslog_sink_cleanup","Exit"); +} + +/* Close facility */ +static void syslog_sink_close(struct data_descriptor *dblock) +{ + DEBUG_STRING("syslog_sink_close","Entry"); + + if(dblock->internal_data != NULL) { + syslog_sink_cleanup(dblock); + free(dblock->internal_data); + free(dblock->config); + dblock->internal_data=NULL; + dblock->config=NULL; + } + + closelog(); + DEBUG_STRING("syslog_sink_close","Exit"); +} + + +/* Logging calback */ +static int syslog_sink_submit(struct data_descriptor *dblock) +{ + struct syslog_event *event_storage; + struct syslog_config *config; + + DEBUG_STRING("syslog_sink_submit","Entry"); + DEBUG_NUMBER("DBLOCK in submit",dblock); + DEBUG_NUMBER("internal data in submit",dblock->internal_data); + + event_storage = (struct serial_data *)(dblock->internal_data); + config = (struct event_storage *)(dblock->config); + + DEBUG_STRING("OUTPUT:",event_storage->db.buffer); + + fprintf(stderr,"%s %d %s\n",config->ident, event_storage->priority, event_storage->db.buffer); + + syslog_sink_cleanup(dblock); + + DEBUG_STRING("syslog_sink_submit","Exit"); + return EOK; +} + +/* Return a filled in structure */ +void get_sink_info(struct sink_capability *sink_cpb_block) +{ + DEBUG_STRING("get_sink_info","Entry"); + + sink_cpb_block->retry_interval = SYSLOG_RETRY; + sink_cpb_block->init_cb = syslog_sink_init; + sink_cpb_block->cleanup_cb = syslog_sink_cleanup; + sink_cpb_block->format_cb = syslog_sink_format; + sink_cpb_block->submit_cb = syslog_sink_submit; + sink_cpb_block->close_cb = syslog_sink_close; + + DEBUG_STRING("get_sink_info","Exit"); +} + |