diff --git a/server/core/filter.c b/server/core/filter.c index beab5abac..4498a922e 100644 --- a/server/core/filter.c +++ b/server/core/filter.c @@ -135,6 +135,19 @@ FILTER_DEF *filter; return filter; } +/** + * Check a parameter to see if it is a standard filter parameter + * + * @param name Parameter name to check + */ +int +filter_standard_parameter(char *name) +{ + if (strcmp(name, "type") == 0 || strcmp(name, "module") == 0) + return 1; + return 0; +} + /** * Print all filters to a DCB * @@ -285,6 +298,17 @@ int i; spinlock_release(&filter->spin); } +/** + * Connect the downstream filter chain for a filter. + * + * This will create the filter instance, loading the filter module, and + * conenct the fitler into the downstream chain. + * + * @param filter The filter to add into the chain + * @param session The client session + * @param downstream The filter downstream of this filter + * @return The downstream component for the next filter + */ DOWNSTREAM * filterApply(FILTER_DEF *filter, SESSION *session, DOWNSTREAM *downstream) { @@ -315,6 +339,19 @@ DOWNSTREAM *me; return me; } +/** + * Connect a filter in the up stream filter chain for a session + * + * Note, the filter will have been created when the downstream chian was + * previously setup. + * Note all filters require to be in the upstream chain, so this routine + * may skip a filter if it does not provide an upstream interface. + * + * @param filter The fitler to add to the chain + * @param fsession The filter session + * @param upstream The filter that should be upstream of this filter + * @return The upstream component for the next filter + */ UPSTREAM * filterUpstream(FILTER_DEF *filter, void *fsession, UPSTREAM *upstream) { diff --git a/server/include/filter.h b/server/include/filter.h index 0da887d3a..568df291a 100644 --- a/server/include/filter.h +++ b/server/include/filter.h @@ -111,6 +111,8 @@ FILTER_DEF *filter_find(char *); void filterAddOption(FILTER_DEF *, char *); void filterAddParameter(FILTER_DEF *, char *, char *); DOWNSTREAM *filterApply(FILTER_DEF *, SESSION *, DOWNSTREAM *); +UPSTREAM *filterUpstream(FILTER_DEF *, void *, UPSTREAM *); +int filter_standard_parameter(char *); void dprintAllFilters(DCB *); void dprintFilter(DCB *, FILTER_DEF *); void dListFilters(DCB *); diff --git a/server/modules/filter/regexfilter.c b/server/modules/filter/regexfilter.c index f7680a84f..0eaf50825 100644 --- a/server/modules/filter/regexfilter.c +++ b/server/modules/filter/regexfilter.c @@ -19,9 +19,13 @@ #include #include #include +#include +#include #include #include +extern int lm_enabled_logfiles_bitmask; + /** * regexfilter.c - a very simple regular expression rewrite filter. * @@ -126,7 +130,7 @@ static FILTER * createInstance(char **options, FILTER_PARAMETER **params) { REGEX_INSTANCE *my_instance; -int i; +int i, cflags = REG_ICASE; if ((my_instance = calloc(1, sizeof(REGEX_INSTANCE))) != NULL) { @@ -137,9 +141,36 @@ int i; { if (!strcmp(params[i]->name, "match")) my_instance->match = strdup(params[i]->value); - if (!strcmp(params[i]->name, "replace")) + else if (!strcmp(params[i]->name, "replace")) my_instance->replace = strdup(params[i]->value); + else if (!filter_standard_parameter(params[i]->name)) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "regexfilter: Unexpected parameter '%s'.\n", + params[i]->name))); + } } + + for (i = 0; options[i]; i++) + { + if (!strcasecmp(options[i], "ignorecase")) + { + cflags |= REG_ICASE; + } + else if (!strcasecmp(options[i], "case")) + { + cflags &= ~REG_ICASE; + } + else + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "regexfilter: unsupported option '%s'.\n", + options[i]))); + } + } + if (my_instance->match == NULL || my_instance->replace == NULL) { return NULL; @@ -147,6 +178,9 @@ int i; if (regcomp(&my_instance->re, my_instance->match, REG_ICASE)) { + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, + "regexfilter: Invalid regular expression '%s'.\n", + my_instance->match))); free(my_instance->match); free(my_instance->replace); free(my_instance); diff --git a/server/modules/filter/topfilter.c b/server/modules/filter/topfilter.c index 0923122ec..b58c84888 100644 --- a/server/modules/filter/topfilter.c +++ b/server/modules/filter/topfilter.c @@ -33,10 +33,14 @@ #include #include #include +#include +#include #include #include #include +extern int lm_enabled_logfiles_bitmask; + MODULE_INFO info = { MODULE_API_FILTER, MODULE_ALPHA_RELEASE, @@ -105,6 +109,7 @@ typedef struct topnq { typedef struct { DOWNSTREAM down; UPSTREAM up; + char *clientHost; char *filename; int fd; struct timeval start; @@ -112,6 +117,8 @@ typedef struct { TOPNQ **top; int n_statements; struct timeval total; + struct timeval connect; + struct timeval disconnect; } TOPN_SESSION; /** @@ -168,8 +175,15 @@ TOPN_INSTANCE *my_instance; { if (!strcmp(params[i]->name, "count")) my_instance->topN = atoi(params[i]->value); - if (!strcmp(params[i]->name, "filebase")) + else if (!strcmp(params[i]->name, "filebase")) my_instance->filebase = strdup(params[i]->value); + else if (!filter_standard_parameter(params[i]->name)) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "topfilter: Unexpected parameter '%s'.\n", + params[i]->name))); + } } my_instance->sessions = 0; } @@ -214,6 +228,11 @@ int i; my_session->n_statements = 0; my_session->total.tv_sec = 0; my_session->total.tv_usec = 0; + if (session && session->client && session->client->remote) + my_session->clientHost = strdup(session->client->remote); + else + my_session->clientHost = NULL; + gettimeofday(&my_session->connect, NULL); } return my_session; @@ -232,9 +251,12 @@ closeSession(FILTER *instance, void *session) { TOPN_INSTANCE *my_instance = (TOPN_INSTANCE *)instance; TOPN_SESSION *my_session = (TOPN_SESSION *)session; +struct timeval diff; int i; FILE *fp; + gettimeofday(&my_session->disconnect, NULL); + timersub((&my_session->disconnect), &(my_session->connect), &diff); if ((fp = fopen(my_session->filename, "w")) != NULL) { fprintf(fp, "Top %d longest running queries in session.\n", @@ -243,21 +265,27 @@ FILE *fp; { if (my_session->top[i]->sql) { - fprintf(fp, "%4d.%-3d, %s\n", - my_session->top[i]->duration.tv_sec, - my_session->top[i]->duration.tv_usec / 1000, + fprintf(fp, "%.3f, %s\n", + (double)((my_session->top[i]->duration.tv_sec * 1000) + + (my_session->top[i]->duration.tv_usec / 1000) / 1000 +), my_session->top[i]->sql); } } fprintf(fp, "\n\nTotal of %d statements executed.\n", my_session->n_statements); fprintf(fp, "Total statement execution time %d.%d seconds\n", - my_session->total.tv_sec, - my_session->total.tv_usec / 1000); + (int)my_session->total.tv_sec, + (int)my_session->total.tv_usec / 1000); fprintf(fp, "Average statement execution time %.3f.\n", (double)((my_session->total.tv_sec * 1000) + (my_session->total.tv_usec / 1000)) / (1000 * my_session->n_statements)); + fprintf(fp, "Total connection time %d.%d seconds\n", + (int)diff.tv_sec, (int)diff.tv_usec / 1000); + if (my_session->clientHost) + fprintf(fp, "Connection from %s\n", + my_session->clientHost); fclose(fp); } } @@ -274,6 +302,8 @@ freeSession(FILTER *instance, void *session) TOPN_SESSION *my_session = (TOPN_SESSION *)session; free(my_session->filename); + if (my_session->clientHost) + free(my_session->clientHost); free(session); return; }