summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/elapi/Makefile.am6
-rw-r--r--common/elapi/elapi_async.c153
-rw-r--r--common/elapi/elapi_async.h37
-rw-r--r--common/elapi/elapi_event.c27
-rw-r--r--common/elapi/elapi_event.h5
-rw-r--r--common/elapi/elapi_fd.h42
-rw-r--r--common/elapi/elapi_internal.c6
-rw-r--r--common/elapi/elapi_log.c126
-rw-r--r--common/elapi/elapi_log.h19
-rw-r--r--common/elapi/elapi_priv.h107
-rw-r--r--common/elapi/elapi_resolve.c330
-rw-r--r--common/elapi/elapi_test/Makefile.am4
-rw-r--r--common/elapi/elapi_test/elapi_ut.c21
-rw-r--r--common/elapi/elapi_tm.h40
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