summaryrefslogtreecommitdiffstats
path: root/sinks
diff options
context:
space:
mode:
authorDmitri Pal <dpal@dpal.csb>2009-02-23 10:38:06 -0500
committerDmitri Pal <dpal@dpal.csb>2009-02-23 10:38:06 -0500
commitd986aeb99fa33967374290bf7ce75eab76c6d446 (patch)
treee85af838cd95b43c4f1be5bc2203a1a3474ba589 /sinks
downloadelapi_draft-d986aeb99fa33967374290bf7ce75eab76c6d446.tar.gz
elapi_draft-d986aeb99fa33967374290bf7ce75eab76c6d446.tar.xz
elapi_draft-d986aeb99fa33967374290bf7ce75eab76c6d446.zip
Initial commit.
Diffstat (limited to 'sinks')
-rw-r--r--sinks/Makefile.am1
-rw-r--r--sinks/elapi_sink.h56
-rw-r--r--sinks/file/elapi_sink_file.c268
-rw-r--r--sinks/stderr/elapi_sink_stderr.c135
-rw-r--r--sinks/syslog/elapi_sink_syslog.c287
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");
+}
+