Files
regexx/examples/ascii_logparse.c
T

72 lines
3.2 KiB
C
Raw Normal View History

/* ascii_logparse - demonstrates ASCII mode doing what it is actually for:
* parsing structured, line-oriented text with named groups, then reading
* fields back out by name rather than by remembering a numeric position.
* This is the ordinary, common case the other examples in this directory
* deliberately are not (they each isolate one less-common feature
* instead); it is included so the directory has one example that looks
* like typical real-world usage: log filtering and field extraction.
*/
#include "regexx.h"
#include <stdio.h>
#include <string.h>
static const char *LOG =
"2024-01-15 10:23:45 INFO [auth] user 'alice' logged in from 10.0.0.5\n"
"2024-01-15 10:24:02 ERROR [db] connection refused to 10.0.0.9:5432\n"
"2024-01-15 10:24:03 WARN [auth] repeated login failure for user 'bob'\n"
"2024-01-15 10:25:11 ERROR [auth] user 'bob' locked out after 5 failures\n"
"2024-01-15 10:26:00 INFO [db] connection pool resized to 32\n";
int main(void) {
const char *pattern =
"(?P<date>\\d{4}-\\d{2}-\\d{2}) (?P<time>\\d{2}:\\d{2}:\\d{2}) "
"(?P<level>\\w+)\\s+\\[(?P<component>\\w+)\\] (?P<message>.+)";
PatternError err; memset(&err, 0, sizeof err);
Pattern *pat = re_compile(pattern, strlen(pattern), ASCII, &err);
if (!pat) {
fprintf(stderr, "compile error: %s\n", err.msg);
PatternError_free(&err);
return 1;
}
printf("-- every ERROR line, fields read back by name --\n");
size_t linelen = strlen(LOG);
size_t start = 0;
int error_count = 0;
for (size_t pos = 0; pos <= linelen; pos++) {
if (pos == linelen || LOG[pos] == '\n') {
size_t len = pos - start;
if (len > 0) {
Input *line = Input_from_buffer((const uint8_t *)(LOG + start), len);
Match m; memset(&m, 0, sizeof m);
if (Pattern_fullmatch(pat, line, 0, -1, &m) == 1) {
const char *level; size_t levellen;
Match_group(&m, "level", 0, &level, &levellen);
if (levellen == 5 && strncmp(level, "ERROR", 5) == 0) {
const char *time, *component, *message;
size_t timelen, componentlen, messagelen;
Match_group(&m, "time", 0, &time, &timelen);
Match_group(&m, "component", 0, &component, &componentlen);
Match_group(&m, "message", 0, &message, &messagelen);
printf("[%.*s] %.*s: %.*s\n",
(int)timelen, time,
(int)componentlen, component,
(int)messagelen, message);
error_count++;
}
Match_free(&m);
}
Input_free(line);
}
start = pos + 1;
}
}
printf("\n%d error line(s) found (Pattern_groupindex_lookup(\"message\") = %d,\n"
"used internally by name lookup so this program never hardcodes a\n"
"capturing group's numeric position)\n",
error_count, Pattern_groupindex_lookup(pat, "message"));
Pattern_free(pat);
return 0;
}