diff options
-rw-r--r-- | common/elapi/Makefile.am | 6 | ||||
-rw-r--r-- | common/elapi/elapi_async.c | 153 | ||||
-rw-r--r-- | common/elapi/elapi_async.h | 37 | ||||
-rw-r--r-- | common/elapi/elapi_event.c | 27 | ||||
-rw-r--r-- | common/elapi/elapi_event.h | 5 | ||||
-rw-r--r-- | common/elapi/elapi_fd.h | 42 | ||||
-rw-r--r-- | common/elapi/elapi_internal.c | 6 | ||||
-rw-r--r-- | common/elapi/elapi_log.c | 126 | ||||
-rw-r--r-- | common/elapi/elapi_log.h | 19 | ||||
-rw-r--r-- | common/elapi/elapi_priv.h | 107 | ||||
-rw-r--r-- | common/elapi/elapi_resolve.c | 330 | ||||
-rw-r--r-- | common/elapi/elapi_test/Makefile.am | 4 | ||||
-rw-r--r-- | common/elapi/elapi_test/elapi_ut.c | 21 | ||||
-rw-r--r-- | common/elapi/elapi_tm.h | 40 |
14 files changed, 828 insertions, 95 deletions
diff --git a/common/elapi/Makefile.am b/common/elapi/Makefile.am index d548a629..08fd2d77 100644 --- a/common/elapi/Makefile.am +++ b/common/elapi/Makefile.am @@ -51,12 +51,16 @@ libelapi_la_SOURCES = \ elapi_event.c \ elapi_log.c \ elapi_internal.c \ - elapi_event.h \ elapi_sink.c \ + elapi_resolve.c \ + elapi_async.c \ + elapi_event.h \ elapi_priv.h \ elapi_sink.h \ elapi_log.h \ elapi_async.h \ + elapi_fd.h \ + elapi_tm.h \ elapi.h libelapi_la_LIBADD = libprovider.la libelapibasic.la diff --git a/common/elapi/elapi_async.c b/common/elapi/elapi_async.c new file mode 100644 index 00000000..0c404c04 --- /dev/null +++ b/common/elapi/elapi_async.c @@ -0,0 +1,153 @@ +/* + ELAPI + + Implementation for the ELAPI async processing interface. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#define _GNU_SOURCE +#include <errno.h> /* for errors */ + +#include "elapi_async.h" +/* Private headers that deal with fd and tm structure definitions */ +#include "elapi_fd.h" +#include "elapi_tm.h" +#include "trace.h" +#include "config.h" + +/* Functions to set and get data from file descriptor data. */ +/* Functions return EINVAL if passed in argument is invalid. */ +int elapi_set_fd_priv(struct elapi_fd_data *fd_data, + void *priv_data_to_set) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_set_fd_priv", "Entry"); + + /* Check arguments */ + if (fd_data == NULL) { + TRACE_ERROR_NUMBER("Invalid argument. Error", EINVAL); + return EINVAL; + } + + fd_data->ext_data = priv_data_to_set; + + TRACE_FLOW_STRING("elapi_set_fd_priv", "Exit"); + return error; +} + +int elapi_get_fd_priv(struct elapi_fd_data *fd_data, + void **priv_data_to_get) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_get_fd_priv", "Entry"); + + /* Check arguments */ + if ((fd_data == NULL) || (priv_data_to_get == NULL)) { + TRACE_ERROR_NUMBER("Invalid argument. Error", EINVAL); + return EINVAL; + } + + *priv_data_to_get = fd_data->ext_data; + + TRACE_FLOW_STRING("elapi_get_fd_priv", "Exit"); + return error; +} + +/* Cleanup function */ +void elapi_destroy_fd_data(struct elapi_fd_data *fd_data) +{ + TRACE_FLOW_STRING("elapi_destroy_fd_data", "Entry"); + + + TRACE_FLOW_STRING("elapi_destroy_fd_data", "Exit"); +} + + +/* Functions to set and get custom data from timer data. */ +/* Functions return EINVAL if passed in argument is invalid. */ +int elapi_set_tm_priv(struct elapi_tm_data *tm_data, + void *priv_data_to_set) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_set_tm_priv", "Entry"); + + /* Check arguments */ + if (tm_data == NULL) { + TRACE_ERROR_NUMBER("Invalid argument. Error", EINVAL); + return EINVAL; + } + + tm_data->ext_data = priv_data_to_set; + + TRACE_FLOW_STRING("elapi_set_tm_priv", "Exit"); + return error; +} + +int elapi_get_tm_priv(struct elapi_tm_data *tm_data, + void **priv_data_to_get) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_get_tm_priv", "Entry"); + + /* Check arguments */ + if ((tm_data == NULL) || (priv_data_to_get == NULL)) { + TRACE_ERROR_NUMBER("Invalid argument. Error", EINVAL); + return EINVAL; + } + + *priv_data_to_get = tm_data->ext_data; + + TRACE_FLOW_STRING("elapi_get_tm_priv", "Exit"); + return error; +} + +/* Cleanup function */ +void elapi_destroy_tm_data(struct elapi_tm_data *tm_data) +{ + TRACE_FLOW_STRING("elapi_destroy_tm_data", "Entry"); + + + TRACE_FLOW_STRING("elapi_destroy_tm_data", "Exit"); +} + + +/* Public interfaces ELAPI exposes to handle fd or timer + * events (do not confuse with log events). + */ +int elapi_process_fd(struct elapi_fd_data *fd_data) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_process_fd", "Entry"); + + + TRACE_FLOW_STRING("elapi_process_fd", "Exit"); + return error; +} + +int elapi_process_tm(struct elapi_tm_data *tm_data) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_process_tm", "Entry"); + + + TRACE_FLOW_STRING("elapi_process_tm", "Exit"); + return error; +} diff --git a/common/elapi/elapi_async.h b/common/elapi/elapi_async.h index f9fbd9e3..21331766 100644 --- a/common/elapi/elapi_async.h +++ b/common/elapi/elapi_async.h @@ -38,7 +38,7 @@ int elapi_set_fd_priv(struct elapi_fd_data *fd_data, int elapi_get_fd_priv(struct elapi_fd_data *fd_data, void **priv_data_to_get); /* Cleanup function */ -int elapi_destroy_fd_data(struct elapi_fd_data *fd_data); +void elapi_destroy_fd_data(struct elapi_fd_data *fd_data); /* Functions to set and get custom data from timer data. */ /* Functions return EINVAL if passed in argument is invalid. */ @@ -47,7 +47,7 @@ int elapi_set_tm_priv(struct elapi_tm_data *tm_data, int elapi_get_tm_priv(struct elapi_tm_data *tm_data, void **priv_data_to_get); /* Cleanup function */ -int elapi_destroy_tm_data(struct elapi_tm_data *tm_data); +void elapi_destroy_tm_data(struct elapi_tm_data *tm_data); /* Public interfaces ELAPI exposes to handle fd or timer * events (do not confuse with log events). @@ -84,10 +84,8 @@ typedef int (*elapi_set_fd)(int fd, /* Signature of the function to add timer. * Provided by caller of the ELAPI interface. - * Caller must be aware that the timeval strcuture - * is allocated on stack. */ -typedef int (*elapi_add_tm)(struct timeval *tv, +typedef int (*elapi_add_tm)(struct timeval tv, struct elapi_tm_data *tm_data, void *ext_tm_data); @@ -101,34 +99,5 @@ typedef int (*elapi_rem_tm)(struct elapi_tm_data *tm_data, -/* Structure that contains the pointer to functions - * that needed to be provided to enable async processing. - */ -struct elapi_async_ctx { - elapi_add_fd add_fd_cb; - elapi_rem_fd rem_fd_cb; - elapi_set_fd set_fd_cb; - void *ext_fd_data; - elapi_add_tm add_tm_cb; - elapi_rem_tm rem_tm_cb; - void *ext_tm_data; -}; - -/* Interface to create the async context */ -int elapi_create_asctx(struct elapi_async_ctx **ctx, - elapi_add_fd add_fd_cb, - elapi_rem_fd rem_fd_cb, - elapi_set_fd set_fd_cb, - void *ext_fd_data, - elapi_add_tm add_tm_cb, - elapi_rem_tm rem_tm_cb, - void *ext_tm_data); - -/* Function to free the async context */ -void elapi_destroy_asctx(struct elapi_async_ctx *ctx); - -/* Function to validate the consistency of the - * async context */ -int elapi_check_asctx(struct elapi_async_ctx *ctx); #endif diff --git a/common/elapi/elapi_event.c b/common/elapi/elapi_event.c index 735de599..e1baf424 100644 --- a/common/elapi/elapi_event.c +++ b/common/elapi/elapi_event.c @@ -449,7 +449,7 @@ static int interpret_key(char *key, adjust_by = 2; } else if ((*cursor == 'u') && (*(cursor+1) == '(')) { - *type = COL_TYPE_INTEGER; + *type = COL_TYPE_UNSIGNED; adjust_by = 2; } else if ((*cursor == 'l') && ((*(cursor+1) == 'i')||(*(cursor+1) == 'd')) && (*(cursor+2) == '(')) { @@ -457,7 +457,7 @@ static int interpret_key(char *key, adjust_by = 3; } else if ((*cursor == 'l') && (*(cursor+1) == 'u') && (*(cursor+2) == '(')) { - *type = COL_TYPE_LONG; + *type = COL_TYPE_ULONG; adjust_by = 3; } else if (((*cursor == 'f')||(*cursor == 'e')) && (*(cursor+1) == '(')) { @@ -866,6 +866,7 @@ int elapi_create_event_with_vargs(struct collection_item **event, { int error = EOK; struct collection_item *evt = NULL; + const char *alias; TRACE_FLOW_STRING("elapi_create_event_with_vargs", "Entry"); @@ -897,9 +898,17 @@ int elapi_create_event_with_vargs(struct collection_item **event, } } - /* Add elements from the template */ + /* Add elements from the collection */ if (collection != NULL) { - error = col_add_collection_to_collection(evt, NULL, NULL, collection, mode); + /* If we are told to use FLAT DOT mode + * add collection with prefixing here. + */ + if (mode == COL_ADD_MODE_FLATDOT) { + alias = col_get_item_property(collection, NULL); + } + else alias = NULL; + + error = col_add_collection_to_collection(evt, NULL, alias, collection, mode); if (error) { TRACE_ERROR_NUMBER("Failed to add elements from external collection. Error", error); col_destroy_collection(evt); @@ -955,6 +964,7 @@ int elapi_modify_event(struct collection_item *event, { int error = EOK; va_list args; + const char *alias; TRACE_FLOW_STRING("elapi_modify_event", "Entry"); @@ -966,7 +976,14 @@ int elapi_modify_event(struct collection_item *event, /* Add elements from the template */ if (collection != NULL) { - error = col_add_collection_to_collection(event, NULL, NULL, collection, mode); + /* If we are told to use FLAT DOT mode + * add collection with prefixing here. + */ + if (mode == COL_ADD_MODE_FLATDOT) { + alias = col_get_item_property(collection, NULL); + } + else alias = NULL; + error = col_add_collection_to_collection(event, NULL, alias, collection, mode); if (error) { TRACE_ERROR_NUMBER("Failed to add elements from external collection. Error", error); col_destroy_collection(event); diff --git a/common/elapi/elapi_event.h b/common/elapi/elapi_event.h index dfaba771..6a5fe044 100644 --- a/common/elapi/elapi_event.h +++ b/common/elapi/elapi_event.h @@ -46,6 +46,11 @@ */ #define E_MESSAGE "__message__" + +/* Standard prefix for internal attributes */ +#define E_PREFIX "__" +#define E_PREFIX_LEN 2 + /* Base argument in the template creation function is a bit mask. * Each supported predefined element corresponds to its bit in * the mask. diff --git a/common/elapi/elapi_fd.h b/common/elapi/elapi_fd.h new file mode 100644 index 00000000..48f2722c --- /dev/null +++ b/common/elapi/elapi_fd.h @@ -0,0 +1,42 @@ +/* + ELAPI + + Private header to define internal structure of the ELAPI fd data. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef ELAPI_FD_H +#define ELAPI_FD_H + +#include "elapi_priv.h" + +/* Structure that holds ELAPI file descriptor's watch data */ +struct elapi_fd_data { + int fd; + void *ext_data; + struct elapi_dispatcher *handle; + struct elapi_sink_ctx *sink_ctx; + struct collection_item *event; +}; + +/* Create the fd data structure for the event */ +int elapi_create_fd_data(struct elapi_fd_data **fd_data, + int fd, + void *ext_data, + struct elapi_sink_ctx *sink_ctx, + struct collection_item *event); + + +#endif diff --git a/common/elapi/elapi_internal.c b/common/elapi/elapi_internal.c index d0fd48dc..d80725b2 100644 --- a/common/elapi/elapi_internal.c +++ b/common/elapi/elapi_internal.c @@ -74,11 +74,6 @@ int elapi_tgt_cb(const char *target, TRACE_INFO_STRING("Current event will be logged into the target:", target); - /* FIXME THIS IS A PLACEHOLDER FUNCTION FOR NOW */ - - printf("\n\n\nPROCESSING EVENT:\n"); - col_debug_collection(target_data->event, COL_TRAVERSE_DEFAULT); - /* Log event */ error = elapi_tgt_submit(target_data->handle, context, target_data->event); if (error) { @@ -86,7 +81,6 @@ int elapi_tgt_cb(const char *target, return error; } - TRACE_FLOW_STRING("elapi_tgt_cb", "Exit."); return EOK; } diff --git a/common/elapi/elapi_log.c b/common/elapi/elapi_log.c index 322f5f8a..ee4c1a0c 100644 --- a/common/elapi/elapi_log.c +++ b/common/elapi/elapi_log.c @@ -97,6 +97,101 @@ static int elapi_dsp_msg_with_vargs(uint32_t target, /********** Main functions of the interface **********/ +/* Function to free the async context */ +void elapi_destroy_asctx(struct elapi_async_ctx *ctx) +{ + TRACE_FLOW_STRING("elapi_destroy_asctx", "Entry"); + + free(ctx); + + TRACE_FLOW_STRING("elapi_destroy_asctx", "Exit"); +} + +/* Function to validate the consistency of the + * async context */ +static int elapi_check_asctx(struct elapi_async_ctx *ctx) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_check_asctx", "Entry"); + + /* Check callbacks */ + if ((ctx->add_fd_cb == NULL) || + (ctx->rem_fd_cb == NULL) || + (ctx->set_fd_cb == NULL) || + (ctx->add_tm_cb == NULL) || + (ctx->rem_tm_cb == NULL)) { + TRACE_ERROR_NUMBER("One of the callbacks is missing. Error", EINVAL); + return EINVAL; + } + + /* We do not check the data pointers. + * Why? Becuase thought it is a bad approach + * the data the callbacks will use + * can be a global (bad but can be!). + * So forcing caller to provide non-NULL + * data pointers is a bit too much. + */ + + TRACE_FLOW_STRING("elapi_check_asctx", "Exit"); + return error; +} + +/* Interface to create the async context */ +int elapi_create_asctx(struct elapi_async_ctx **ctx, + elapi_add_fd add_fd_cb, + elapi_rem_fd rem_fd_cb, + elapi_set_fd set_fd_cb, + void *ext_fd_data, + elapi_add_tm add_tm_cb, + elapi_rem_tm rem_tm_cb, + void *ext_tm_data) +{ + int error = EOK; + struct elapi_async_ctx *ctx_new; + + TRACE_FLOW_STRING("elapi_create_asctx", "Entry"); + + /* Allocate data, copy it and then check. + * Why this order? Why not check first + * without allocating memory and wasting + * cycles for it? + * Becuase the check function can be used + * in other place to validate that the context + * is correct. Allocating and freeing + * data is not an overhead since + * it is going to catch development + * error that would not exist in the final + * product. Otherwise the progam just + * would not run. + */ + + ctx_new = (struct elapi_async_ctx *)malloc(sizeof(struct elapi_async_ctx)); + if (ctx_new == NULL) { + TRACE_ERROR_NUMBER("Failed to allocate memory for the context", ENOMEM); + return ENOMEM; + } + + ctx_new->add_fd_cb = add_fd_cb; + ctx_new->rem_fd_cb = rem_fd_cb; + ctx_new->set_fd_cb = set_fd_cb; + ctx_new->add_tm_cb = add_tm_cb; + ctx_new->rem_tm_cb = rem_tm_cb; + ctx_new->ext_fd_data = ext_fd_data; + ctx_new->ext_tm_data = ext_tm_data; + + error = elapi_check_asctx(ctx_new); + if (error) { + TRACE_ERROR_NUMBER("Check context failed", error); + elapi_destroy_asctx(ctx_new); + return error; + } + + *ctx = ctx_new; + + TRACE_FLOW_STRING("elapi_create_asctx", "Exit"); + return error; +} /* Function to create a dispatcher */ int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, @@ -128,7 +223,14 @@ int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, return EINVAL; } - /* FIXME: Check if context is valid */ + /* Check if context is valid */ + if (async_ctx) { + error = elapi_check_asctx(async_ctx); + if (error) { + TRACE_ERROR_NUMBER("Check context failed", error); + return error; + } + } /* Check what is passed in the config_path */ if (config_path) { @@ -251,6 +353,14 @@ int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, handle->async_ctx = NULL; } + /* Build the list of the items we know how to resolve */ + error = elapi_init_resolve_list(&(handle->resolve_list)); + if (error != EOK) { + TRACE_ERROR_NUMBER("Failed to create list of resolvers. Error", error); + elapi_destroy_dispatcher(handle); + return error; + } + *dispatcher = handle; TRACE_FLOW_STRING("elapi_create_dispatcher_adv", "Returning Success."); @@ -316,6 +426,8 @@ void elapi_destroy_dispatcher(struct elapi_dispatcher *dispatcher) free_ini_config(dispatcher->ini_config); TRACE_INFO_STRING("Deleting targets name array.", ""); free_string_config_array(dispatcher->targets); + TRACE_INFO_STRING("Unbind resolver iterator.", ""); + col_unbind_iterator(dispatcher->resolve_list); TRACE_INFO_STRING("Freeing dispatcher.", ""); free(dispatcher); } @@ -330,6 +442,7 @@ int elapi_dsp_log(uint32_t target, { int error = EOK; struct elapi_tgt_data target_data; + struct collection_item *resolved_event; TRACE_FLOW_STRING("elapi_dsp_log", "Entry"); @@ -339,9 +452,16 @@ int elapi_dsp_log(uint32_t target, return EINVAL; } + /* Create a resolved event */ + error = elapi_resolve_event(&resolved_event, event, dispatcher); + if (error) { + TRACE_ERROR_NUMBER("Failed to create event context. Error", error); + return error; + } + /* Wrap parameters into one argument and pass on */ target_data.handle = dispatcher; - target_data.event = event; + target_data.event = resolved_event; target_data.target_mask = target; TRACE_INFO_NUMBER("Target mask is:", target_data.target_mask); @@ -352,6 +472,8 @@ int elapi_dsp_log(uint32_t target, elapi_tgt_cb, (void *)(&target_data)); + elapi_destroy_event(resolved_event); + TRACE_FLOW_NUMBER("elapi_dsp_log Exit. Returning", error); return error; } diff --git a/common/elapi/elapi_log.h b/common/elapi/elapi_log.h index 7d783553..5417caa7 100644 --- a/common/elapi/elapi_log.h +++ b/common/elapi/elapi_log.h @@ -42,6 +42,23 @@ struct elapi_dispatcher; */ /********** Main functions of the interface **********/ +/* Structure that contains the pointer to functions + * that needed to be provided to enable async processing. + */ +struct elapi_async_ctx; + +/* Interface to create the async context */ +int elapi_create_asctx(struct elapi_async_ctx **ctx, + elapi_add_fd add_fd_cb, + elapi_rem_fd rem_fd_cb, + elapi_set_fd set_fd_cb, + void *ext_fd_data, + elapi_add_tm add_tm_cb, + elapi_rem_tm rem_tm_cb, + void *ext_tm_data); + +/* Function to free the async context */ +void elapi_destroy_asctx(struct elapi_async_ctx *ctx); /* Function to create a dispatcher */ int elapi_create_dispatcher(struct elapi_dispatcher **dispatcher, /* Handle of the dispatcher will be stored in this variable */ @@ -52,7 +69,7 @@ int elapi_create_dispatcher(struct elapi_dispatcher **dispatcher, /* Handle of int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, /* Handle of the dispatcher will be stored in this variable */ const char *appname, /* Application name. Passed to the sinks to do initialization */ const char *config_path, /* See notes below in the elapi_init() function. */ - struct elapi_async_ctx *async_ctx); /* Async context. */ + struct elapi_async_ctx *ctx); /* Async context. */ /* Function to clean memory associated with the dispatcher */ void elapi_destroy_dispatcher(struct elapi_dispatcher *dispatcher); diff --git a/common/elapi/elapi_priv.h b/common/elapi/elapi_priv.h index fb8cd3e8..27b0079f 100644 --- a/common/elapi/elapi_priv.h +++ b/common/elapi/elapi_priv.h @@ -21,6 +21,7 @@ #define ELAPI_PRIV_H #include <stdint.h> +#include <stdarg.h> #include "collection.h" #include "elapi_async.h" @@ -33,6 +34,7 @@ #define COL_CLASS_ELAPI_SINK COL_CLASS_ELAPI_BASE + 2 #define COL_CLASS_ELAPI_TARGET COL_CLASS_ELAPI_BASE + 3 #define COL_CLASS_ELAPI_SINK_REF COL_CLASS_ELAPI_BASE + 4 +#define COL_CLASS_ELAPI_RES_ITEM COL_CLASS_ELAPI_BASE + 5 /* Names for the collections */ #define E_TEMPLATE_NAME "template" @@ -51,6 +53,7 @@ #define ELAPI_SINK_ONERROR "onerror" #define ELAPI_SINK_TIMEOUT "timeout" #define ELAPI_SINK_SYNCH "synch" +#define ELAPI_RESOLVE_ITEM "res_item" /* Default timout before dispatcher tries to revive sink. * The actual value is configurable on per sink basis @@ -73,6 +76,22 @@ #define ELAPI_ONERROR_REVIVE 0 #define ELAPI_ONERROR_DISABLE 1 +/* Structure that contains the pointer to functions + * that needed to be provided to enable async processing. + */ +struct elapi_async_ctx { + /* Callbacks related to file descriptor. */ + elapi_add_fd add_fd_cb; + elapi_rem_fd rem_fd_cb; + elapi_set_fd set_fd_cb; + /* File descriptor callback external data. */ + void *ext_fd_data; + /* Callbacks for timer */ + elapi_add_tm add_tm_cb; + elapi_rem_tm rem_tm_cb; + /* Timer's external data */ + void *ext_tm_data; +}; struct elapi_dispatcher { /* Application name */ @@ -87,24 +106,14 @@ struct elapi_dispatcher { struct collection_item *sink_list; /* Configuration */ struct collection_item *ini_config; + /* Items to resolve */ + struct collection_iterator *resolve_list; /* Default event template */ struct collection_item *default_template; /* Async processing related data */ struct elapi_async_ctx *async_ctx; - /* Indicator of our synch mode - * FIXME: Do we need it? - */ - uint32_t async_mode; - /* Time offset */ - int32_t offset; }; -/* Structure to pass data from logging function to targets */ -struct elapi_tgt_data { - struct collection_item *event; - struct elapi_dispatcher *handle; - uint32_t target_mask; -}; /* This is a structure that holds the information * about the target. @@ -165,41 +174,32 @@ struct elapi_sink_ctx { }; -/* The structure to hold the event and its context */ -/* FIXME The event should be turned into this object - * on the high level before going - * into any target. - * and then this should be passed around - * instead of the actual event. +/* A helper structure that holds data + * needed to resolve the event. */ -struct elapi_event_ctx { - /* This is a copy of the event */ - /* We have to copy it for two reasons: - * a) It needs to be flattened so - * that we do not get unnecesary naming - * collisions if same key appears on different - * levels - * b) In case of async logging we need - * the original event until we are sure - * it is actually logged. If we do not - * keep it around the application can modify - * it or delete it before we figured out - * that sink is broken and we need to fail over. - * If in this case we go to another sink - * and if we do not have the original event - * we are screwed. - */ +struct elapi_resolve_data { + /* Reference to the event */ struct collection_item *event; - /* Reference count */ - int refcount; - /* Event time */ + /* Reference back to dispatcher */ + struct elapi_dispatcher *handle; + /* Time related data */ time_t tm; - /* Resolved message */ - char *message; + /* Structured UTC time */ + struct tm utc_time; + /* Structured local time */ + struct tm local_time; /* Time offset */ - int32_t offset; + int offset; }; +/* Structure to pass data from logging function to targets */ +struct elapi_tgt_data { + struct collection_item *event; + struct elapi_dispatcher *handle; + uint32_t target_mask; +}; + + /* Lookup structure for searching for providers */ struct elapi_prvdr_lookup { const char *name; @@ -213,6 +213,26 @@ struct elapi_get_sink { int found; }; +/* Signature of the item resolution function */ +typedef int (*elapi_rslv_cb)(struct elapi_resolve_data *resolver, + struct collection_item *item, + int *skip); + +/* Structure to hold type-callback tuples */ +struct elapi_rslv_item_data { + int type; + elapi_rslv_cb resolve_cb; +}; + +/* Structure to hold name-data tuples */ +struct elapi_resolve_list { + const char *name; + struct elapi_rslv_item_data resolve_item; +}; + +/* Function to initialize resolution list */ +int elapi_init_resolve_list(struct collection_iterator **list); + /* Function to create event using arg list */ int elapi_create_event_with_vargs(struct collection_item **event, struct collection_item *template, @@ -296,6 +316,11 @@ int elapi_tgt_submit(struct elapi_dispatcher *handle, /* Create list of targets for a dispatcher */ int elapi_tgt_mklist(struct elapi_dispatcher *handle); +/* Create event context */ +int elapi_resolve_event(struct collection_item **final_event, + struct collection_item *event, + struct elapi_dispatcher *handle); + /* Send ELAPI config errors into a file */ void elapi_dump_ini_err(struct collection_item *error_list); diff --git a/common/elapi/elapi_resolve.c b/common/elapi/elapi_resolve.c new file mode 100644 index 00000000..5570eee0 --- /dev/null +++ b/common/elapi/elapi_resolve.c @@ -0,0 +1,330 @@ +/* + ELAPI + + Module contains functions to resolve the event. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#define _GNU_SOURCE +#include <errno.h> /* for errors */ +#include <string.h> /* for strcmp() */ + +#include "elapi_priv.h" +#include "elapi_event.h" +/* #include "elapi_subst.h" */ +#include "trace.h" +#include "config.h" + +/*****************************************/ +/* Individual callbacks are defined here */ +/*****************************************/ +/* Timestamp resoltion callback */ +int elapi_timestamp_cb(struct elapi_resolve_data *resolver, + struct collection_item *item, + int *skip) +{ + int error = EOK; + char timestamp[TIME_ARRAY_SIZE + 1]; + int length; + + TRACE_FLOW_STRING("elapi_timestamp_cb", "Entry"); + + /* Construct the time stamp */ + length = strftime(timestamp, + TIME_ARRAY_SIZE, + (const char *)(col_get_item_data(item)), + &(resolver->local_time)); + + /* Update the time stamp item */ + error = col_modify_str_item(item, + NULL, + timestamp, + length + 1); + + TRACE_FLOW_NUMBER("elapi_timestamp_cb. Exit. Returning", error); + return error; +} + +/* UTC time resolution callback */ +int elapi_utctime_cb(struct elapi_resolve_data *resolver, + struct collection_item *item, + int *skip) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_utctime_cb", "Entry"); + + /* Update the UTC item */ + error = col_modify_int_item(item, + NULL, + (int)(resolver->tm)); + + TRACE_FLOW_NUMBER("elapi_utctime_cb. Exit. Returning", error); + return error; +} + +/* Offset resolution callback */ +int elapi_offset_cb(struct elapi_resolve_data *resolver, + struct collection_item *item, + int *skip) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_offset_cb", "Entry"); + + /* Update the offset item */ + error = col_modify_int_item(item, + NULL, + (int)(resolver->offset)); + + TRACE_FLOW_NUMBER("elapi_offset_cb. Exit. Returning", error); + return error; +} + + +/* Message resolution callback */ +int elapi_message_cb(struct elapi_resolve_data *resolver, + struct collection_item *item, + int *skip) +{ + int error = EOK; + /* int length; */ + /* char *result; */ + + TRACE_FLOW_STRING("elapi_message_cb", "Entry"); + + /* FIXME: Resolve message here */ + /* Function is not yet implemented ... + error = elapi_sprintf(&result, + &length, + (const char *)col_get_item_data(item), + resolver->event); + if (error) { + TRACE_ERROR_NUMBER("Failed to build message", error); + return error; + } + + error = col_modify_str_item(item, + NULL, + result; + length + 1); + free(result); + if (error) { + TRACE_ERROR_NUMBER("Failed to modify message item", error); + return error; + } + */ + + TRACE_FLOW_NUMBER("elapi_message_cb. Exit. Returning", error); + return error; +} + + +/*****************************************/ +/* Array of structures for resolution of + * the different event properties. + */ +struct elapi_resolve_list elapi_known_fields[] = { + { E_TIMESTAMP, { COL_TYPE_STRING, elapi_timestamp_cb }}, + { E_UTCTIME, { COL_TYPE_INTEGER, elapi_utctime_cb }}, + { E_OFFSET, { COL_TYPE_INTEGER, elapi_offset_cb }}, + { E_MESSAGE, { COL_TYPE_STRING, elapi_message_cb }}, + /* ADD NEW CALLBACKS HERE */ + { NULL, { COL_TYPE_ANY, NULL }} +}; + + + + +/*****************************************/ +/* A callback function to do substitutions + * of different properties as we copy the event. + */ +static int elapi_resolve_item(struct collection_item *item, + void *ext_data, + int *skip) +{ + int error = EOK; + struct elapi_resolve_data *resolver; + struct collection_item *res_item; + struct elapi_rslv_item_data *rslv_pair; + int res; + + TRACE_FLOW_STRING("elapi_resolve_item", "Entry"); + + /* Do we care about this field ? */ + if (strncmp(col_get_item_property(item, NULL), + E_PREFIX, + E_PREFIX_LEN) != 0) { + TRACE_FLOW_STRING("elapi_resolve_item. Skipping resoltion.", "Exit"); + return EOK; + } + + /* This is an internal field that might need resolution */ + resolver = (struct elapi_resolve_data *)ext_data; + + /* NOTE: This iteration loop uses advanced iterator + * capabilities. Read more about it before you decide + * to use this code as an example. + */ + while (1) { + + /* Advance to next item in the list */ + error = col_iterate_collection(resolver->handle->resolve_list, + &res_item); + if (error) { + TRACE_ERROR_NUMBER("Failed to iterate collection", error); + return error; + } + + /* Are we done ? This means we looped and did not find + * the item. */ + if (res_item == NULL) break; + + /* Compare items */ + res = col_compare_items(item, + res_item, + COL_CMPIN_PROP_EQU, + NULL); + if (res == 0) { + /* Item names are the same, so drill down and get expected type. */ + rslv_pair = *((struct elapi_rslv_item_data **)col_get_item_data(res_item)); + /* Make sure that types matched too */ + if (rslv_pair->type == col_get_item_type(item)) { + /* This is the item we need to resolve so resolve */ + error = rslv_pair->resolve_cb(resolver, + item, + skip); + if (error) { + TRACE_ERROR_NUMBER("Failed to resolve item", error); + return error; + } + + /* Pin down the iterator here */ + col_pin_iterator(resolver->handle->resolve_list); + + /* Break out of loop */ + break; + } + } + } + TRACE_FLOW_STRING("elapi_resolve_item", "Exit"); + return error; +} + + +/* Resolve event */ +int elapi_resolve_event(struct collection_item **final_event, + struct collection_item *event, + struct elapi_dispatcher *handle) +{ + int error = EOK; + struct elapi_resolve_data resolver; + struct collection_item *new_event; + time_t local; + time_t utc; + + TRACE_FLOW_STRING("elapi_create_event_ctx", "Entry"); + + /* Prepeare the resolver */ + resolver.event = event; + resolver.handle = handle; + /* Get seconds */ + resolver.tm = time(NULL); + /* Convert to local and UTC structured time */ + localtime_r(&resolver.tm, &(resolver.local_time)); + gmtime_r(&resolver.tm, &(resolver.utc_time)); + /* Convert back */ + utc = mktime(&(resolver.utc_time)); + local = mktime(&(resolver.local_time)); + /* Get offset - it is safe to typecast to int here */ + resolver.offset = (int)(difftime(local, utc)); + + /* NOTE: We will use FLATDOT mode. + * We will see what people have to say + * about this approach... + */ + error = col_copy_collection_with_cb(&new_event, + event, + NULL, + COL_COPY_FLATDOT, + elapi_resolve_item, + (void *)&resolver); + if (error) { + TRACE_ERROR_NUMBER("Failed to resolve the event", error); + return error; + } + + *final_event = new_event; + + TRACE_FLOW_STRING("elapi_create_event_ctx", "Exit"); + return error; +} + +/* Function to initialize resolution list */ +int elapi_init_resolve_list(struct collection_iterator **list) +{ + int error = EOK; + struct elapi_resolve_list *current; + struct collection_item *col = NULL; + struct collection_iterator *iterator; + struct elapi_rslv_item_data *bin_data; + + TRACE_FLOW_STRING("elapi_init_resolve_list", "Entry"); + + /* Create collection of fields that we know how to process */ + error = col_create_collection(&col, + ELAPI_RESOLVE_ITEM, + COL_CLASS_ELAPI_RES_ITEM); + + if (error) { + TRACE_ERROR_NUMBER("Failed to create collection", error); + return error; + } + + /* Loop through the static array and turn it into a collection */ + current = elapi_known_fields; + while (current->name) { + bin_data = &(current->resolve_item); + error = col_add_binary_property(col, + NULL, + current->name, + (void *)&bin_data, + sizeof(struct elapi_rslv_item_data *)); + if (error) { + TRACE_ERROR_NUMBER("Failed to add item resolver", error); + col_destroy_collection(col); + return error; + } + + current++; + } + + /* Now bind iterator */ + error = col_bind_iterator(&iterator, col, COL_TRAVERSE_FLAT); + if (error) { + TRACE_ERROR_NUMBER("Failed to bind collection", error); + col_destroy_collection(col); + return error; + } + + /* We do not need the collection itself - we have iterator */ + col_destroy_collection(col); + + *list = iterator; + + TRACE_FLOW_STRING("elapi_init_resolve_list", "Exit"); + return error; +} diff --git a/common/elapi/elapi_test/Makefile.am b/common/elapi/elapi_test/Makefile.am index 76f06e0c..dcf1707c 100644 --- a/common/elapi/elapi_test/Makefile.am +++ b/common/elapi/elapi_test/Makefile.am @@ -30,11 +30,15 @@ libelapi_test_la_SOURCES = \ ../elapi_sink.c \ ../elapi_basic.c \ ../elapi_basic.h \ + ../elapi_resolve.c \ + ../elapi_async.c \ ../elapi_event.h \ ../elapi_priv.h \ ../elapi_sink.h \ ../elapi_log.h \ ../elapi_async.h \ + ../elapi_fd.h \ + ../elapi_tm.h \ ../elapi.h \ ../providers/file/file_provider.c \ ../providers/file/file_provider.h \ diff --git a/common/elapi/elapi_test/elapi_ut.c b/common/elapi/elapi_test/elapi_ut.c index 0a823432..1046ed0e 100644 --- a/common/elapi/elapi_test/elapi_ut.c +++ b/common/elapi/elapi_test/elapi_ut.c @@ -208,8 +208,8 @@ int complex_event_test(void) return error; } - col_debug_collection(template, COL_TRAVERSE_FLAT); - col_debug_collection(event, COL_TRAVERSE_FLAT); + col_debug_collection(template, COL_TRAVERSE_DEFAULT); + col_debug_collection(event, COL_TRAVERSE_DEFAULT); error = elapi_log(E_TARGET_DEBUG, event); @@ -233,8 +233,9 @@ int complex_event_test(void) "%d(int_number),", -200, "%u(unsigned_number)", 300, "%ld(long_number)", -1234567, + "%lu(long_unsigned)", -1234567, E_MESSAGE, - "%(stamp), %s(sub_string), %(int_number), %(unsigned_number), %(long_unsigned_number), %(bin), %e(double_number)", + "%(stamp), %(sub_string), %(int_number), %(unsigned_number), %(long_unsigned_number), %(bin), %(double_number)", E_EOARG); if (error) { @@ -270,8 +271,11 @@ int complex_event_test(void) col_destroy_collection(col); - col_debug_collection(template, COL_TRAVERSE_FLAT); - col_debug_collection(event, COL_TRAVERSE_FLAT); + col_debug_collection(template, COL_TRAVERSE_DEFAULT); + + printf("\nPRINTING EVENT\n\n"); + printf("\nPRINTING EVENT, removed message added bin\n\n"); + col_debug_collection(event, COL_TRAVERSE_DEFAULT); if ((error = col_create_collection(&col, "test", 0)) || @@ -300,6 +304,10 @@ int complex_event_test(void) return error; } + printf("\nPRINTING EVENT, removed message, added bin,\n" + "added test collection with zzz & zzz2\n\n"); + + col_debug_collection(event, COL_TRAVERSE_DEFAULT); col_destroy_collection(col); if ((error = col_create_collection(&col, "flat", 0)) || @@ -326,6 +334,9 @@ int complex_event_test(void) return error; } + printf("\nPRINTING EVENT, added flat collection with zzz & zzz2\n\n"); + + col_debug_collection(event, COL_TRAVERSE_DEFAULT); col_destroy_collection(col); error = elapi_copy_event(&event_copy, event); diff --git a/common/elapi/elapi_tm.h b/common/elapi/elapi_tm.h new file mode 100644 index 00000000..e9d50e4b --- /dev/null +++ b/common/elapi/elapi_tm.h @@ -0,0 +1,40 @@ +/* + ELAPI + + Private header to define internal structure of the ELAPI timer data. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef ELAPI_TM_H +#define ELAPI_TM_H + +#include "elapi_priv.h" + +/* Structure that holds ELAPI timer watch data */ +struct elapi_tm_data { + void *ext_data; + struct elapi_dispatcher *handle; + struct elapi_sink_ctx *sink_ctx; + struct collection_item *event; +}; + +/* Create the tm data structure for the event */ +int elapi_create_tm_data(struct elapi_tm_data **tm_data, + void *ext_data, + struct elapi_sink_ctx *sink_ctx, + struct collection_item *event); + + +#endif |