diff options
| -rw-r--r-- | utility/config.c | 10 | ||||
| -rw-r--r-- | utility/config.h | 4 | ||||
| -rw-r--r-- | utility/logparse.c | 105 | ||||
| -rw-r--r-- | utility/logparse.h | 15 | ||||
| -rw-r--r-- | utility/mod_log_sql.conf | 3 | ||||
| -rw-r--r-- | utility/util.c | 96 | ||||
| -rw-r--r-- | utility/util.h | 2 |
7 files changed, 206 insertions, 29 deletions
diff --git a/utility/config.c b/utility/config.c index b1e7585..fca2f77 100644 --- a/utility/config.c +++ b/utility/config.c | |||
| @@ -320,15 +320,19 @@ apr_status_t config_check(config_t *cfg) | |||
| 320 | { | 320 | { |
| 321 | apr_status_t ret = APR_SUCCESS; | 321 | apr_status_t ret = APR_SUCCESS; |
| 322 | if (!cfg->dbdriver || !cfg->dbparams) { | 322 | if (!cfg->dbdriver || !cfg->dbparams) { |
| 323 | logging_log(cfg, LOGLEVEL_NOISE, "Database configuration is missing\n"); | 323 | logging_log(cfg, LOGLEVEL_NOISE, "CONFIG: Database configuration is missing"); |
| 324 | ret = APR_EINVAL; | 324 | ret = APR_EINVAL; |
| 325 | } | 325 | } |
| 326 | if (!cfg->table) { | 326 | if (!cfg->table) { |
| 327 | logging_log(cfg, LOGLEVEL_NOISE, "No Log Table defined\n"); | 327 | logging_log(cfg, LOGLEVEL_NOISE, "CONFIG: No Log Table defined"); |
| 328 | ret = APR_EINVAL; | 328 | ret = APR_EINVAL; |
| 329 | } | 329 | } |
| 330 | if (apr_is_empty_array(cfg->output_fields)) { | 330 | if (apr_is_empty_array(cfg->output_fields)) { |
| 331 | logging_log(cfg, LOGLEVEL_NOISE, "No Output Fields Defined\n"); | 331 | logging_log(cfg, LOGLEVEL_NOISE, "CONFIG: No Output Fields Defined"); |
| 332 | ret = APR_EINVAL; | ||
| 333 | } | ||
| 334 | if (apr_hash_count(cfg->log_formats)==0) { | ||
| 335 | logging_log(cfg, LOGLEVEL_NOISE, "CONFIG: No Input Log Formats Defined"); | ||
| 332 | ret = APR_EINVAL; | 336 | ret = APR_EINVAL; |
| 333 | } | 337 | } |
| 334 | return ret; | 338 | return ret; |
diff --git a/utility/config.h b/utility/config.h index 763ef5d..26a4e99 100644 --- a/utility/config.h +++ b/utility/config.h | |||
| @@ -115,6 +115,8 @@ typedef enum { | |||
| 115 | 115 | ||
| 116 | typedef struct config_output_field_t config_output_field_t; | 116 | typedef struct config_output_field_t config_output_field_t; |
| 117 | 117 | ||
| 118 | typedef struct parser_func_t parser_func_t; | ||
| 119 | |||
| 118 | struct config_output_field_t { | 120 | struct config_output_field_t { |
| 119 | const char *field; | 121 | const char *field; |
| 120 | logsql_field_datatype datatype; | 122 | logsql_field_datatype datatype; |
| @@ -122,7 +124,7 @@ struct config_output_field_t { | |||
| 122 | const char *def; | 124 | const char *def; |
| 123 | const char *source; | 125 | const char *source; |
| 124 | const char *fname; | 126 | const char *fname; |
| 125 | void *func; | 127 | parser_func_t *func; |
| 126 | const char **args; | 128 | const char **args; |
| 127 | void *data; | 129 | void *data; |
| 128 | }; | 130 | }; |
diff --git a/utility/logparse.c b/utility/logparse.c index f4afb52..7ea6bc1 100644 --- a/utility/logparse.c +++ b/utility/logparse.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "database.h" | 12 | #include "database.h" |
| 13 | 13 | ||
| 14 | apr_hash_t *g_parser_funcs; | 14 | apr_hash_t *g_parser_funcs; |
| 15 | void **g_parser_linedata; | ||
| 15 | 16 | ||
| 16 | static apr_status_t parser_func_regexmatch(apr_pool_t *p, config_t *cfg, | 17 | static apr_status_t parser_func_regexmatch(apr_pool_t *p, config_t *cfg, |
| 17 | config_output_field_t *field, const char *value, const char **ret) | 18 | config_output_field_t *field, const char *value, const char **ret) |
| @@ -19,33 +20,34 @@ static apr_status_t parser_func_regexmatch(apr_pool_t *p, config_t *cfg, | |||
| 19 | struct { | 20 | struct { |
| 20 | ap_regex_t *rx; | 21 | ap_regex_t *rx; |
| 21 | const char *substr; | 22 | const char *substr; |
| 22 | }*data; | 23 | }*_data; |
| 23 | ap_regmatch_t regm[AP_MAX_REG_MATCH]; | 24 | ap_regmatch_t regm[AP_MAX_REG_MATCH]; |
| 24 | // Check if a regular expression configured | 25 | // Check if a regular expression configured |
| 25 | if (!field->args[0]) | 26 | if (!field->args[0]) |
| 26 | return APR_EINVAL; | 27 | return APR_EINVAL; |
| 27 | if (!field->data) { | 28 | if (!field->data) { |
| 28 | // pre compile the regex | 29 | // pre compile the regex |
| 29 | data = apr_palloc(cfg->pool, sizeof(ap_regex_t)+sizeof(const char *)); | 30 | _data = apr_palloc(cfg->pool, sizeof(ap_regex_t)+sizeof(const char *)); |
| 30 | data->rx = ap_pregcomp(cfg->pool, field->args[0], | 31 | _data->rx = ap_pregcomp(cfg->pool, field->args[0], |
| 31 | AP_REG_EXTENDED|AP_REG_ICASE); | 32 | AP_REG_EXTENDED|AP_REG_ICASE); |
| 32 | if (field->args[1]) { | 33 | if (field->args[1]) { |
| 33 | data->substr = field->args[1]; | 34 | _data->substr = field->args[1]; |
| 34 | } else { | 35 | } else { |
| 35 | data->substr = "$1"; | 36 | _data->substr = "$1"; |
| 36 | } | 37 | } |
| 37 | if (!data->rx) | 38 | if (!_data->rx) |
| 38 | return APR_EINVAL; | 39 | return APR_EINVAL; |
| 39 | field->data = data; | 40 | field->data = _data; |
| 40 | } else | 41 | } else |
| 41 | data = field->data; | 42 | _data = field->data; |
| 42 | 43 | ||
| 43 | if (!ap_regexec(data->rx, value, AP_MAX_REG_MATCH, regm, 0)) { | 44 | if (!ap_regexec(_data->rx, value, AP_MAX_REG_MATCH, regm, 0)) { |
| 44 | *ret = ap_pregsub(p, data->substr, value, AP_MAX_REG_MATCH, regm); | 45 | *ret = ap_pregsub(p, _data->substr, value, AP_MAX_REG_MATCH, regm); |
| 45 | } else { | 46 | } else { |
| 46 | *ret = field->def; | 47 | *ret = field->def; |
| 47 | } | 48 | } |
| 48 | //printf("We matched %s against %s to %s\n",value, field->args[0], *ret); | 49 | logging_log(cfg, LOGLEVEL_DEBUG, "REGEX: matched %s against %s to %s", value, |
| 50 | field->args[0], *ret); | ||
| 49 | return APR_SUCCESS; | 51 | return APR_SUCCESS; |
| 50 | } | 52 | } |
| 51 | 53 | ||
| @@ -76,26 +78,87 @@ static apr_status_t parser_func_machineid(apr_pool_t *p, config_t *cfg, | |||
| 76 | } | 78 | } |
| 77 | 79 | ||
| 78 | /** @todo Implement Query arg ripping function */ | 80 | /** @todo Implement Query arg ripping function */ |
| 81 | static apr_status_t parser_func_queryarg(apr_pool_t *p, config_t *cfg, | ||
| 82 | config_output_field_t *field, const char *value, const char **ret) | ||
| 83 | { | ||
| 84 | apr_table_t *query = parser_get_linedata(field->func); | ||
| 85 | |||
| 86 | if (!field->args[0]) | ||
| 87 | return APR_EINVAL; | ||
| 88 | |||
| 89 | if (!query) { | ||
| 90 | char *query_beg; | ||
| 91 | |||
| 92 | query = apr_table_make(p,3); | ||
| 93 | |||
| 94 | query_beg = strchr(value, '?'); | ||
| 95 | // if we have a query string, rip it apart | ||
| 96 | if (query_beg) { | ||
| 97 | char *key; | ||
| 98 | char *value; | ||
| 99 | char *query_string; | ||
| 100 | char *strtok_state; | ||
| 101 | char *query_end = strrchr(++query_beg,' '); | ||
| 102 | |||
| 103 | query_string = apr_pstrndup(p, query_beg, query_end-query_beg); | ||
| 104 | logging_log(cfg, LOGLEVEL_DEBUG, "QUERY: Found String %pp, %pp, %s", | ||
| 105 | query_beg, query_end, query_string); | ||
| 106 | |||
| 107 | key = apr_strtok(query_string, "&", &strtok_state); | ||
| 108 | while (key) { | ||
| 109 | value = strchr(key, '='); | ||
| 110 | if (value) { | ||
| 111 | *value = '\0'; /* Split the string in two */ | ||
| 112 | value++; /* Skip past the = */ | ||
| 113 | } | ||
| 114 | else { | ||
| 115 | value = "1"; | ||
| 116 | } | ||
| 117 | ap_unescape_url(key); | ||
| 118 | ap_unescape_url(value); | ||
| 119 | apr_table_set(query, key, value); | ||
| 120 | |||
| 121 | logging_log(cfg, LOGLEVEL_DEBUG, | ||
| 122 | "QUERY: Found arg: %s = %s", key, value); | ||
| 79 | 123 | ||
| 80 | parser_func_t parser_get_func(const char *name) | 124 | key = apr_strtok(NULL, "&", &strtok_state); |
| 125 | } | ||
| 126 | } | ||
| 127 | parser_set_linedata(field->func,query); | ||
| 128 | } | ||
| 129 | *ret = apr_table_get(query, field->args[0]); | ||
| 130 | if (*ret == NULL) *ret = field->def; | ||
| 131 | return APR_SUCCESS; | ||
| 132 | } | ||
| 133 | |||
| 134 | parser_func_t *parser_get_func(const char *name) | ||
| 81 | { | 135 | { |
| 82 | return apr_hash_get(g_parser_funcs, name, APR_HASH_KEY_STRING); | 136 | return apr_hash_get(g_parser_funcs, name, APR_HASH_KEY_STRING); |
| 83 | } | 137 | } |
| 84 | 138 | ||
| 85 | static void parser_add_func(apr_pool_t *p, const char *const name, | 139 | static void parser_add_func(apr_pool_t *p, const char *const name, |
| 86 | parser_func_t func) | 140 | parser_func_f func, int id) |
| 87 | { | 141 | { |
| 142 | parser_func_t *s; | ||
| 88 | if (!g_parser_funcs) { | 143 | if (!g_parser_funcs) { |
| 89 | g_parser_funcs = apr_hash_make(p); | 144 | g_parser_funcs = apr_hash_make(p); |
| 90 | } | 145 | } |
| 91 | apr_hash_set(g_parser_funcs, lowerstr(p, name), APR_HASH_KEY_STRING, func); | 146 | s = apr_palloc(p, sizeof(parser_func_t)); |
| 147 | s->func = func; | ||
| 148 | s->pos = id; | ||
| 149 | s->linedata = &g_parser_linedata; | ||
| 150 | apr_hash_set(g_parser_funcs, lowerstr(p, name), APR_HASH_KEY_STRING, s); | ||
| 92 | } | 151 | } |
| 93 | 152 | ||
| 94 | void parser_init(apr_pool_t *p) | 153 | void parser_init(apr_pool_t *p) |
| 95 | { | 154 | { |
| 96 | parser_add_func(p, "regexmatch", parser_func_regexmatch); | 155 | int i = 0; |
| 97 | parser_add_func(p, "totimestamp", parser_func_totimestamp); | 156 | parser_add_func(p, "regexmatch", parser_func_regexmatch, ++i); |
| 98 | parser_add_func(p, "machineid", parser_func_machineid); | 157 | parser_add_func(p, "totimestamp", parser_func_totimestamp, ++i); |
| 158 | parser_add_func(p, "machineid", parser_func_machineid, ++i); | ||
| 159 | parser_add_func(p, "queryarg", parser_func_queryarg, ++i); | ||
| 160 | g_parser_linedata = apr_pcalloc(p, sizeof(void *) * (i+1)); | ||
| 161 | g_parser_linedata[0] = (void *)i; | ||
| 99 | } | 162 | } |
| 100 | 163 | ||
| 101 | void parser_find_logs(config_t *cfg) | 164 | void parser_find_logs(config_t *cfg) |
| @@ -333,8 +396,10 @@ apr_status_t parse_processline(apr_pool_t *ptemp, config_t *cfg, char **argv, | |||
| 333 | } | 396 | } |
| 334 | /** @todo Run Pre Filters here */ | 397 | /** @todo Run Pre Filters here */ |
| 335 | 398 | ||
| 336 | // Convert input fields to output fields | ||
| 337 | ofields = (config_output_field_t *)cfg->output_fields->elts; | 399 | ofields = (config_output_field_t *)cfg->output_fields->elts; |
| 400 | // clear out ofield function per-line data | ||
| 401 | memset(&g_parser_linedata[1],0,sizeof(void *)*(int)g_parser_linedata[0]); | ||
| 402 | // Convert input fields to output fields | ||
| 338 | for (i=0; i<cfg->output_fields->nelts; i++) { | 403 | for (i=0; i<cfg->output_fields->nelts; i++) { |
| 339 | const char *val; | 404 | const char *val; |
| 340 | val = apr_table_get(datain, ofields[i].source); | 405 | val = apr_table_get(datain, ofields[i].source); |
| @@ -347,8 +412,8 @@ apr_status_t parse_processline(apr_pool_t *ptemp, config_t *cfg, char **argv, | |||
| 347 | apr_table_setn(dataout, ofields[i].field, val); | 412 | apr_table_setn(dataout, ofields[i].field, val); |
| 348 | } else { | 413 | } else { |
| 349 | const char *ret= NULL; | 414 | const char *ret= NULL; |
| 350 | rv = ((parser_func_t)ofields[i].func)(ptemp, cfg, &ofields[i], val, | 415 | rv = ((parser_func_t *)ofields[i].func)->func(ptemp, cfg, |
| 351 | &ret); | 416 | &ofields[i], val, &ret); |
| 352 | if (rv) | 417 | if (rv) |
| 353 | return rv; | 418 | return rv; |
| 354 | apr_table_setn(dataout, ofields[i].field, ret); | 419 | apr_table_setn(dataout, ofields[i].field, ret); |
diff --git a/utility/logparse.h b/utility/logparse.h index 816624a..bc39cb1 100644 --- a/utility/logparse.h +++ b/utility/logparse.h | |||
| @@ -3,10 +3,21 @@ | |||
| 3 | 3 | ||
| 4 | #include "config.h" | 4 | #include "config.h" |
| 5 | 5 | ||
| 6 | typedef apr_status_t (*parser_func_t)(apr_pool_t *p, config_t *cfg, | 6 | typedef apr_status_t (*parser_func_f)(apr_pool_t *p, config_t *cfg, |
| 7 | config_output_field_t *field, const char *value, const char **ret); | 7 | config_output_field_t *field, const char *value, const char **ret); |
| 8 | 8 | ||
| 9 | parser_func_t parser_get_func(const char *name); | 9 | struct parser_func_t { |
| 10 | parser_func_f func; | ||
| 11 | int pos; | ||
| 12 | void *data; | ||
| 13 | void ***linedata; | ||
| 14 | }; | ||
| 15 | |||
| 16 | #define parser_get_linedata(f) (*f->linedata)[f->pos] | ||
| 17 | |||
| 18 | #define parser_set_linedata(f, v) (*f->linedata)[f->pos] = v | ||
| 19 | |||
| 20 | parser_func_t *parser_get_func(const char *name); | ||
| 10 | 21 | ||
| 11 | void parser_init(apr_pool_t *p); | 22 | void parser_init(apr_pool_t *p); |
| 12 | 23 | ||
diff --git a/utility/mod_log_sql.conf b/utility/mod_log_sql.conf index 771f7c7..8822bb5 100644 --- a/utility/mod_log_sql.conf +++ b/utility/mod_log_sql.conf | |||
| @@ -49,3 +49,6 @@ OutputField request_time char(28) "" date regexmatch ".+" | |||
| 49 | OutputField agent varchar(255) "" agent | 49 | OutputField agent varchar(255) "" agent |
| 50 | OutputField referer varchar(255) "" referer | 50 | OutputField referer varchar(255) "" referer |
| 51 | OutputField machine_id varchar(25) "" "" machineid | 51 | OutputField machine_id varchar(25) "" "" machineid |
| 52 | #VIZU Fields | ||
| 53 | OutputField poll_id int 0 request queryarg n | ||
| 54 | |||
diff --git a/utility/util.c b/utility/util.c index 99bb046..7ecb902 100644 --- a/utility/util.c +++ b/utility/util.c | |||
| @@ -31,6 +31,99 @@ void line_chomp(char *str) | |||
| 31 | } | 31 | } |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | /* | ||
| 35 | * *** Ripped from HTTPD util.c (why are so many PORTABLE things not in APR UTIL?) | ||
| 36 | */ | ||
| 37 | static char x2c(const char *what) | ||
| 38 | { | ||
| 39 | register char digit; | ||
| 40 | |||
| 41 | digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 | ||
| 42 | : (what[0] - '0')); | ||
| 43 | digit *= 16; | ||
| 44 | digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 | ||
| 45 | : (what[1] - '0')); | ||
| 46 | return (digit); | ||
| 47 | } | ||
| 48 | |||
| 49 | /* | ||
| 50 | * *** Ripped from HTTPD util.c (why are so many PORTABLE things not in APR UTIL?) | ||
| 51 | * | ||
| 52 | * Unescapes a URL, leaving reserved characters intact. | ||
| 53 | * Returns 0 on success, non-zero on error | ||
| 54 | * Failure is due to | ||
| 55 | * bad % escape returns HTTP_BAD_REQUEST | ||
| 56 | * | ||
| 57 | * decoding %00 or a forbidden character returns HTTP_NOT_FOUND | ||
| 58 | */ | ||
| 59 | static int unescape_url(char *url, const char *forbid, const char *reserved) | ||
| 60 | { | ||
| 61 | register int badesc, badpath; | ||
| 62 | char *x, *y; | ||
| 63 | |||
| 64 | badesc = 0; | ||
| 65 | badpath = 0; | ||
| 66 | /* Initial scan for first '%'. Don't bother writing values before | ||
| 67 | * seeing a '%' */ | ||
| 68 | y = strchr(url, '%'); | ||
| 69 | if (y == NULL) { | ||
| 70 | return APR_SUCCESS; | ||
| 71 | } | ||
| 72 | for (x = y; *y; ++x, ++y) { | ||
| 73 | if (*y != '%') { | ||
| 74 | *x = *y; | ||
| 75 | } | ||
| 76 | else { | ||
| 77 | if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) { | ||
| 78 | badesc = 1; | ||
| 79 | *x = '%'; | ||
| 80 | } | ||
| 81 | else { | ||
| 82 | char decoded; | ||
| 83 | decoded = x2c(y + 1); | ||
| 84 | if ((decoded == '\0') | ||
| 85 | || (forbid && strchr(forbid, decoded))) { | ||
| 86 | badpath = 1; | ||
| 87 | *x = decoded; | ||
| 88 | y += 2; | ||
| 89 | } | ||
| 90 | else if (reserved && strchr(reserved, decoded)) { | ||
| 91 | *x++ = *y++; | ||
| 92 | *x++ = *y++; | ||
| 93 | *x = *y; | ||
| 94 | } | ||
| 95 | else { | ||
| 96 | *x = decoded; | ||
| 97 | y += 2; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | *x = '\0'; | ||
| 103 | if (badesc) { | ||
| 104 | return APR_EINVAL; | ||
| 105 | } | ||
| 106 | else if (badpath) { | ||
| 107 | return APR_EINVAL; | ||
| 108 | } | ||
| 109 | else { | ||
| 110 | return APR_SUCCESS; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | /* | ||
| 115 | * *** Ripped from HTTPD util.c (why are so many PORTABLE things not in APR UTIL?) | ||
| 116 | */ | ||
| 117 | int ap_unescape_url(char *url) | ||
| 118 | { | ||
| 119 | /* Traditional */ | ||
| 120 | #ifdef CASE_BLIND_FILESYSTEM | ||
| 121 | return unescape_url(url, "/\\", NULL); | ||
| 122 | #else | ||
| 123 | return unescape_url(url, "/", NULL); | ||
| 124 | #endif | ||
| 125 | } | ||
| 126 | |||
| 34 | void logging_init(config_t *cfg) | 127 | void logging_init(config_t *cfg) |
| 35 | { | 128 | { |
| 36 | apr_status_t rv; | 129 | apr_status_t rv; |
| @@ -58,9 +151,6 @@ const char *logging_strerror(apr_status_t rv) | |||
| 58 | return apr_strerror(rv, buff, 256); | 151 | return apr_strerror(rv, buff, 256); |
| 59 | } | 152 | } |
| 60 | 153 | ||
| 61 | /** | ||
| 62 | * @todo implement logging | ||
| 63 | */ | ||
| 64 | void logging_log(config_t *cfg, loglevel_e level, const char *fmt, ...) | 154 | void logging_log(config_t *cfg, loglevel_e level, const char *fmt, ...) |
| 65 | { | 155 | { |
| 66 | va_list ap; | 156 | va_list ap; |
diff --git a/utility/util.h b/utility/util.h index c67cf9c..99f93aa 100644 --- a/utility/util.h +++ b/utility/util.h | |||
| @@ -12,6 +12,8 @@ char *lowerstr(apr_pool_t *pool, const char *input); | |||
| 12 | */ | 12 | */ |
| 13 | void line_chomp(char *str); | 13 | void line_chomp(char *str); |
| 14 | 14 | ||
| 15 | int ap_unescape_url(char *url); | ||
| 16 | |||
| 15 | void logging_init(config_t *cfg); | 17 | void logging_init(config_t *cfg); |
| 16 | 18 | ||
| 17 | void logging_log(config_t *cfg, loglevel_e level, const char *fmt, ...) | 19 | void logging_log(config_t *cfg, loglevel_e level, const char *fmt, ...) |
