Check-in [f0887760c8]
Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Bundle logfmt1 into sub project. Support for /usr/share/logfmt/ database and update scripts (apache version is a trimmed down modseccfg.vhosts extractor). Support both pip and deb package (differ to some extend). |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
f0887760c86cf6ee08a7961533fbca4e |
User & Date: | mario 2020-12-16 10:35:59 |
Context
2020-12-16
| ||
10:39 | Use prefix/whitespace prepending for whole block (some macros just got the first line indented). check-in: a58faea2e0 user: mario tags: trunk | |
10:35 | Bundle logfmt1 into sub project. Support for /usr/share/logfmt/ database and update scripts (apache version is a trimmed down modseccfg.vhosts extractor). Support both pip and deb package (differ to some extend). check-in: f0887760c8 user: mario tags: trunk | |
2020-12-15
| ||
09:41 | Support TransferLog (which nobody uses). Add pretty ▰▰▰▰▰▰▰▰▱▱▱▱▱ progressbar for *.conf traversal on startup. check-in: d7f672369e user: mario tags: trunk | |
Changes
Added logfmt1/README.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | **logfmt1** handles `*.log.fmt` files to transform LogFormat / placeholder strings to regular expressions (named capture groups). Currently just comes with rules for Apache definitions. It bundles a `logex` and `update-logfmt` to create/rewrite `*.log.fmt` files globally. { "class": "apache combined", "record": "%h %l %u %t \"%r\" %>s %b", } It's basically meant for universal log parsing, whilst reducing manual configuration or the restrain on basic log variants. It originated in [modseccfg](https://fossil.include-once.org/modseccfg/). This Python package is mostly a stub. You should preferrably install the [system package](https://apt.include-once.org/): apt install python3-logfmt1 This will yield the proper `/usr/share/logfmt/` structure and the run-parts wrapper `update-logfmt`. The grok placeholders are supported, but remain untested. ### logfmt1 To craft a regex: import logfmt1, json fmt = json.load(open("/.../access.log.fmt", "r")) rx = logfmt1.regex(fmt) rx = logfmt1.rx2re(rx) # turn into Python regex Or with plain old guesswork / presuming a standard log format: rx = logfmt1.regex({"class": "apache combined"}) Though that's of course not the intended use case, and hinges on predefined formats in /usr/share/logfmt/. ### logex Very crudementary extractor for log files: logex .../access.log --tab @host @date +id Which of course handles the `.fmt` implicitly. ### update-logfmt The Python package does bundle a run-parts wrapper, but just the apache collector, and a local Python copy of the format database. It should discover all `*.log` files nonetheless and pair them with `.fmt` declarations. |
Added logfmt1/__init__.py.
> > > > > > > > | 1 2 3 4 5 6 7 8 | # encoding: utf-8 # api: python # title: logfmt1 # description: handle *.log.fmt specifiers and regex conversion # type: functions # depends: python (>= 3.6) from logfmt1.logfmt1 import regex, rx2re, update, rulesdb, logopen, parsy_parse |
Added logfmt1/grok2fmt1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | #!/usr/bin/env python3 # description: expand grok to .fmt # # output should go into /usr/share/logfmt/grok.fmt # and could then be inherited by various `grok.appname.fmt` # or in any ….log.fmt via {"class": "grok appname"} # or via "record": "%{GROK:%{IP:ip} %{DATE:data}...}" # or perhaps per "class":"grok" in fields/expand definitions # # import re, json # moved to https://github.com/logstash-plugins/logstash-patterns-core/blob/master/patterns/grok-patterns src = """ # https://github.com/elastic/logstash/blob/v1.4.2/patterns/grok-patterns USERNAME [a-zA-Z0-9._-]+ USER %{USERNAME} INT (?:[+-]?(?:[0-9]+)) BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))) NUMBER (?:%{BASE10NUM}) BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+)) BASE16FLOAT \b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+)))\b POSINT \b(?:[1-9][0-9]*)\b NONNEGINT \b(?:[0-9]+)\b WORD \b\w+\b NOTSPACE \S+ SPACE \s* DATA .*? GREEDYDATA .* QUOTEDSTRING (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``)) UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12} # Networking MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC}) CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4}) WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2}) COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}) IPV6 ((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)? IPV4 (?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9]) IP (?:%{IPV6}|%{IPV4}) HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b) HOST %{HOSTNAME} IPORHOST (?:%{HOSTNAME}|%{IP}) HOSTPORT %{IPORHOST}:%{POSINT} # paths PATH (?:%{UNIXPATH}|%{WINPATH}) UNIXPATH (?>/(?>[\w_%!$@:.,-]+|\\.)*)+ TTY (?:/dev/(pts|tty([pq])?)(\w+)?/?(?:[0-9]+)) WINPATH (?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+ URIPROTO [A-Za-z]+(\+[A-Za-z+]+)? URIHOST %{IPORHOST}(?::%{POSINT:port})? # uripath comes loosely from RFC1738, but mostly from what Firefox # doesn't turn into %XX URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*)+ #URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)? URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]* URIPATHPARAM %{URIPATH}(?:%{URIPARAM})? URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})? # Months: January, Feb, 3, 03, 12, December MONTH \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b MONTHNUM (?:0?[1-9]|1[0-2]) MONTHNUM2 (?:0[1-9]|1[0-2]) MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) # Days: Monday, Tue, Thu, etc... DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?) # Years? YEAR (?>\d\d){1,2} HOUR (?:2[0123]|[01]?[0-9]) MINUTE (?:[0-5][0-9]) # '60' is a leap second in most time standards and thus is valid. SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?) TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9]) # datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it) DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR} DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR} ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE})) ISO8601_SECOND (?:%{SECOND}|60) TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}? DATE %{DATE_US}|%{DATE_EU} DATESTAMP %{DATE}[- ]%{TIME} TZ (?:[PMCE][SD]T|UTC) DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ} DATESTAMP_RFC2822 %{DAY}, %{MONTHDAY} %{MONTH} %{YEAR} %{TIME} %{ISO8601_TIMEZONE} DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR} DATESTAMP_EVENTLOG %{YEAR}%{MONTHNUM2}%{MONTHDAY}%{HOUR}%{MINUTE}%{SECOND} # Syslog Dates: Month Day HH:MM:SS SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME} PROG (?:[\w._/%-]+) SYSLOGPROG %{PROG:program}(?:\[%{POSINT:pid}\])? SYSLOGHOST %{IPORHOST} SYSLOGFACILITY <%{NONNEGINT:facility}.%{NONNEGINT:priority}> HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT} # Shortcuts QS %{QUOTEDSTRING} # Log formats SYSLOGBASE %{SYSLOGTIMESTAMP:timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}: COMMONAPACHELOG %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-) COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent} # Log Levels LOGLEVEL ([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?) """ grok = dict(re.findall("^([A-Z]\w+) (.+)", src, re.M)) def grok2rx(rx): rx = re.sub("%\{(\w+)\}", lambda m: grok[m.group(1)], rx) rx = re.sub("%\{(\w+):([\w.\-]+)\}", lambda m: f"(?<{m.group(2)}>" + grok[m.group(1)] + ")", rx) return rx grok = {name:grok2rx(rx) for name,rx in grok.items()} grok = {name:grok2rx(rx) for name,rx in grok.items()} grok = {name:grok2rx(rx) for name,rx in grok.items()} grok = {name:grok2rx(rx) for name,rx in grok.items()} fmt = { "$license": "Apache-2.0", "$origin": "https://github.com/elastic/logstash/blob/v1.4.2/patterns/", "class": "grok", "separator": " ", "placeholder": "%\{\w+:([\w.-]+)\}", "rewrite": {}, "alias": {}, "fields": {}, "expand": { "%\{GROK:((?:[^{}]+|\{[^{}]+\})+)\}": { "id": "", "class": "grok" } }, "container": {}, "glob": ["*.grok"], } for name, rx in grok.items(): #if name in ("COMBINEDAPACHELOG", "COMMONAPACHELOG", "SYSLOGBASE",) or if len(re.findall("\(\?<\w+", rx))>=5: fmt["fields"]["%{"+name+"}"] = { "rx": rx, "id": name.lower(), "grok": name, } else: fmt["expand"]["%{"+name+":([\w.\-]+)}"] = { "rx": rx, "id": '$1', "grok": name, } print(json.dumps(fmt, indent=4)) |
Name change from modseccfg/scripts/logex.py to logfmt1/logex.py.
1 2 3 4 5 6 7 8 9 10 | #!/usr/bin/env python3 # encoding: utf-8 # title: logex # description: extract fields from log (with .fmt) # version: 0.2 # type: cli # category: extract # # # First parameter should be the log file. And a .log.fmt must exist | | | | | | | | | > > > > > > > > > > | > > > < | < < | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #!/usr/bin/env python3 # encoding: utf-8 # title: logex # description: extract fields from log (with .fmt) # version: 0.2 # type: cli # category: extract # # # First parameter should be the log file. And a .log.fmt must exist # alongside (generate with `update-logfmt`). # # Syntax: # logex.py /var/log/apache2/access.log request_path request_time @host # # Other args: # --json / --tab / --csv # --iso8601 / --debug # # Where any @'s are decoration, and fields can be supplied as individual # arguments (become space-separated without --tab/--csv). Field names are # application-type specific (internal) names. (E.g. @request_method, @host # or @tm_wday for Apache logs. With some predefined aliases, e.g. the w3c # extended log field names.) # # Field name prefixes are irrelevant for normal log entries. # But may join list-entries from container fields: # @name will just show the first entry # %name space-separated list # *name comma-separated list # +name plus-joined list # #name as json array # name whatever # # Fields can be given as individual arguments, or as part of a string # output groups: # logex fn.log --tab @individual "@combined,@with,@comma" @tabagain # logex fn.log --csv "@lone" "*multi" "#json" # Though you usually don't wanna overcomplicate the log format again. # import sys, re, json import traceback, dateutil.parser import logfmt1 #-- args argv = sys.argv space = " " if "--tab" in argv: space = "\t" if "--csv" in argv: space = "," iso8601 = any(a in argv for a in ("--iso", "--iso8601", "--date", "--fixdates", "--die-apachedateformat-die")) as_json = any(a in argv for a in ("--json", "--asjson", "--as-json")) dodebug = any(a in argv for a in ("--debug", "-D")) # remove --params argv = [a for a in argv if not re.match("^--\w+$|^-\w$", a)] # filename and field list log_fn = argv[1] output_fields = space.join(argv[2:]) #-- open log file try: reader = logfmt1.logopen(log_fn, debug=dodebug, duplicate=False) #if dodebug: # sys.stdout.write(json.dumps(reader.__dict__, indent=2, default=lambda x:str(x))+"\n") except Exception as e: sys.stderr.write(traceback.format_exc()+"\n") sys.stderr.write("Use `update-logfmt-apache` or modseccfg→File→Install→update_logfmt to generate a .fmt descriptor\n") sys.exit() # extra aliases (for apache/httpd) |
︙ | ︙ | |||
80 81 82 83 84 85 86 | } alias.update(reader.alias) # substitute occurences def get_field(m, row): pfx, name = m.groups() | | > > | > > | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | } alias.update(reader.alias) # substitute occurences def get_field(m, row): pfx, name = m.groups() val = row.get(name) or row.get(alias.get(name)) or "-" if isinstance(val, list): # how to handle lists (for unpacked [key "value"] fields) if pfx == "@": val = val[0] elif pfx == "+": val = "+".join(val) elif pfx == "%": val = " ".join(val) elif pfx == "*": val = ",".join(val) elif pfx == "#": val = json.dumps(val) else: val = str(val) return val |
︙ | ︙ |
Name change from modseccfg/logfmt1.py to logfmt1/logfmt1.py.
1 2 | # encoding: utf-8 # api: python | | | > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # encoding: utf-8 # api: python # title: python3-logfmt1 # description: handle *.log.fmt specifiers and regex conversion # type: transform # category: io # version: 0.4 # license: Apache-2.0 # pack: # logfmt1.py=/usr/lib/python3/dist-packages/ # update-logfmt=/usr/bin/ # ./logex.py=/usr/bin/logex # share=/usr/share/logfmt # architecture: all # depends: python (>= 3.6) # url: https://fossil.include-once.org/modseccfg/wiki/logfmt1 # # Logging format strings to regex conversion. # # This is supposed to recognize .fmt files adjacent to logs, # which document both the application type and log variant # with the most current %p%l%ace%holder definition used. # The purpose of this is to allow log extraction with exact |
︙ | ︙ | |||
136 137 138 139 140 141 142 | "alias": { "remote_address": "remote_addr", "ip": "remote_addr", "user": "remote_user", "file": "request_file", "size": "bytes_sent", "datetime": "request_time", | | | > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | "alias": { "remote_address": "remote_addr", "ip": "remote_addr", "user": "remote_user", "file": "request_file", "size": "bytes_sent", "datetime": "request_time", "ctime": "request_time", "date": "request_time", "loglevel": "remote_logname", "module_name": "request_method", "request_flushed": "file_line", "requests_on_connection": "keepalives", "error": "apr_status", "request_flushed": "file_line", }, # convert variant placeholders into fields beforehand, # possibly looking up other definitions (strftime) for marshalled placeholders "expand": { "%\{([^{}]+)\}t": { "id": "request_time", "class": "strftime", # different placeholders within \{...\} "record": "$1" }, "%[<>]?\{([\w\-]+)\}[Conexic]": { "id": "$1", "rx": "\S+" }, "%\{([\w\-]+)\}\^t[io]": { "id": "$1", |
︙ | ︙ | |||
232 233 234 235 236 237 238 | "%%": { "id": "percent", "rx": "%" }, }, "expand": { "%(\w)": "[\w\d.]+" } } | < < < < | > > > | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | "%%": { "id": "percent", "rx": "%" }, }, "expand": { "%(\w)": "[\w\d.]+" } } # return builtin definitions or from /usr/share/logfmt/*.*.fmt @staticmethod def get(cls): rules = {} cls = cls.split(" ") while cls: lookup = ".".join(cls) lookup_ = "_".join(cls) add = {} dir = "/usr/share/logfmt" if not os.path.exists(dir): # kludge for Python package dir = re.sub("[\w.]$", "share", __file__) # use bundled ./share/ directory fn = f"{dir}/{lookup}.fmt" if os.path.exists(fn): add = open(fn, "r", encoding="utf-8") add = re.sub("^\s*#.+", "", add, re.M) add = json.loads(add) #elif *.grok: read, find primary regex:, or declare %GROK per cls=["grok", "-"] #elif *.lnav: get readymade "regex:" else: |
︙ | ︙ | |||
268 269 270 271 272 273 274 275 276 277 278 279 280 281 | if isinstance(v, dict): if not k in rules: rules[k] = {} rulesdb.merge(rules[k], v) elif not k in rules: rules[k] = v return rules # should be the other way round: regex() is meant to be a subset of update() def update(fmt): fmt["regex"] = regex(fmt, update=True) # assemble regex for format string | > > > > > > > | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | if isinstance(v, dict): if not k in rules: rules[k] = {} rulesdb.merge(rules[k], v) elif not k in rules: rules[k] = v return rules #@staticmethod #def extract_all(): # for key,val in self.__dict__.items(): # if isinstance(val, dict): # open("share/{key}.fmt", "w").write(json.dumps(val, indent=4)) # should be the other way round: regex() is meant to be a subset of update() def update(fmt): fmt["regex"] = regex(fmt, update=True) # assemble regex for format string |
︙ | ︙ | |||
307 308 309 310 311 312 313 | if "rewrite" in rules: for rx, repl in rules["rewrite"].items(): record = re.sub(rx, repl.replace(r'$1', r'\1'), record) # create fields from variant placeholders if "expand" in rules: for rx, expand in rules["expand"].items(): | | | > | < | | > | > | < | | > > > | | | | | | | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | if "rewrite" in rules: for rx, repl in rules["rewrite"].items(): record = re.sub(rx, repl.replace(r'$1', r'\1'), record) # create fields from variant placeholders if "expand" in rules: for rx, expand in rules["expand"].items(): for is_quoted, match, *uu in re.findall(f"(\"?)({rx})", record): if match in fields: continue x = copy(expand) # id: is usually "$1", but might be "prefix_$2" or something if x["id"].find('$') >= 0: x["id"] = rx_sub(rx, x["id"], match) x["id"] = re.sub("\W+", "", x["id"]).lower() # recurse into other pattern types if not "rx" in x and "class" in x: x["rx"] = regex({ "class": x["class"], "record": rx_sub(rx, x.get("record") or "$1", match) }) # handle generic placeholders / quoted strings, somewhat apache-specific if "rx" in x: if not is_quoted and x["rx"] == '[^"]*': x["rx"] = "\S*" elif is_quoted and x["rx"] == "\S+": x["rx"] = "(?:[^\"]*|\\\\\")+" fields[match] = x # catch-all \S+ for completely unknown placeholders if "placeholder" in rules: for ph in re.findall(rules["placeholder"], record): if not ph in fields: id = re.sub("\W+", "", ph) fields[ph] = { "id": id, "rx": "\S+" } |
︙ | ︙ | |||
349 350 351 352 353 354 355 | else: rx = f"(?<{id}>{rx})" return rx rx = re.sub(rules["placeholder"], sub_placeholder, record) rx = rename_duplicates(rx) return rx | < < | > > > > > | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | else: rx = f"(?<{id}>{rx})" return rx rx = re.sub(rules["placeholder"], sub_placeholder, record) rx = rename_duplicates(rx) return rx # (?<duplicate2>) def rename_duplicates(rx): fields = [] def count_ph(m): s, i = m.group(1), 1 while s in fields: i += 1 s = f"{m.group(1)}{i}" fields.append(s) return s return re.sub("(?<=\(\?\<)(\w+)(?=\>)", count_ph, rx) # (?<name>) to (?P<name>) def rx2re(rx): return re.sub("\(\?<(?=\w+>)", "(?P<", rx) # allow for $1, $2, $3 in re.sub() def rx_sub(pattern, replacement, source, flags=0): if replacement.find('$') >= 0: replacement = re.sub(r'\(?=[0-9])', '$', replacement) return re.sub(pattern, replacement, source, flags) # file-style wrapper that yields parsed dictionaries instead of string lines class parsy_parse: def __init__(self, logfn="", fmt=None, debug=False, fail=False, duplicate=True): """ |
︙ | ︙ | |||
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | self.debug_rx(line) if self.fail: raise StopIteration() elif self.fail: raise StopIteration() else: pass # jusst try next line # add [key "value"] fields def container_expand(self, d): for k,opt in self.container.items(): if k in d: for id,val in re.findall(opt["rx"], d[k]): if not id in d: d[id] = val elif not isinstance(d[id], "list"): d[id] = [d[id], val] else: d[id].append(val) # ANSI output for debugging regex/fmt string def debug_rx(self, line): rx = self.rx.pattern line = line.rstrip() | > > > > | | < | | > > | < | > > > > | > > | > | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | self.debug_rx(line) if self.fail: raise StopIteration() elif self.fail: raise StopIteration() else: pass # jusst try next line # pass .close() and similar to file object def __getattr__(self, name): return getattr(self.f, name) # add [key "value"] fields def container_expand(self, d): for k,opt in self.container.items(): if k in d: for id,val in re.findall(opt["rx"], d[k]): if not id in d: d[id] = val elif not isinstance(d[id], "list"): d[id] = [d[id], val] else: d[id].append(val) # ANSI output for debugging regex/fmt string def debug_rx(self, line): rx = self.rx.pattern line = line.rstrip() #rx_cut = re.compile("[^)]* \(\?P<\w+> ( [^()]+ | \([^()]+\) )+ \) [^()]* \Z", re.X) # iteratively strip (?...) capture groups while len(rx) and rx.find("(?P<") >= 0: #fail = rx_cut.search(rx) #if fail: fail = fail.group(0) #else: fail = "<unknown-last-capture>"; break last = rx.rindex("(?P<") if last < 1: fail = "<unknown-last-capture>"; break fail = rx[last:] #print(f"testfail: `{fail}`") try: rx = rx[0:last] rx = re.sub("[^)]*$", "", rx) if re.match(rx, line): break # works now, so `fail` was the culprit except: # likely broke regex nesting, try removing next (?...) pass try: matched = re.match(rx, line) matched = matched.group(0) except: matched = "" print("\033[36m" + "failed regex section: \033[1;33;41m" + fail + "\033[40;0m") print("\033[42m" + matched + "\033[41m" + line[len(matched):] + "\033[40;0m") # alias logopen = parsy_parse #-- test def test(): |
︙ | ︙ |
Added logfmt1/setup.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #!/usr/bin/env python3 # encoding: utf-8 # api: pip # type: build # title: config for setuptools # # Notably the .deb will install as just dist-packages/logfmt1.py. # Whereas the .whl creates a logfmt1/__init__.py wrapper and # directory structure. # - share/ files shouldn't really reside within the pkg. # from pluginconf.setup import setup setup( fn="./logfmt1.py", long_description="@README.rst", package_dir={"logfmt1": "./"}, packages=["logfmt1"], package_data={ "logfmt1": [ "./share/*", "./share/update/*" ], }, #data_files=[], entry_points={ "console_scripts": [ "logex=logfmt1.logex", "update-logfmt=logfmt1.update_logfmt_all", ] } ) |
Added logfmt1/share/apache.combined.fmt.
> > > > > > > | 1 2 3 4 5 6 7 | { "class": "apache combined", "record": "%h %l %u %t \"%r\" %>s %b", "glob": [ "*.access.log" ] } |
Added logfmt1/share/apache.fmt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | { "class": "apache generic", "separator": " ", "rewrite": { "%[\\d!,]+": "%", "(?<!\\\\)([\\[\\]])": "\\\\$1", "%%": "%" }, "placeholder": "%[<>]?(?:\\w*\\{[^\\}]+\\})?\\^?\\w+", "fields": { "%a": { "id": "remote_addr", "rx": "[\\d.:a-f]+" }, "%{c}a": { "id": "remote_addr", "rx": "[\\d.:a-f]+" }, "%h": { "id": "remote_host", "rx": "[\\w\\-.:]+" }, "%{c}h": { "id": "remote_host", "rx": "[\\w\\-.:]+" }, "%A": { "id": "local_address", "rx": "[\\d.:a-f]+" }, "%u": { "id": "remote_user", "rx": "[\\-\\w@.]+" }, "%l": { "id": "remote_logname", "rx": "[\\w\\-.:]+" }, "%t": { "id": "request_time", "rx": "\\[(\\d[\\d:\\w\\s:./\\-+,;]+)\\]" }, "%{u}t": { "id": "request_time", "rx": "\\d+/\\w+/\\d+:\\d+:\\d+:\\d+\\.\\d+\\s\\+\\d+" }, "%{cu}t": { "id": "request_time", "rx": "\\d+-\\w+-\\d+\\s\\d+:\\d+:\\d+\\.\\d+" }, "%{msec_frac}t": { "id": "msec_frac", "rx": "[\\d.]+" }, "%{usec_frac}t": { "id": "usec_frac", "rx": "[\\d.]+" }, "%f": { "id": "request_file", "rx": "[^\\s\"]+" }, "%b": { "id": "bytes_sent", "rx": "\\d+|-" }, "%B": { "id": "bytes_sent", "rx": "\\d+|-" }, "%O": { "id": "bytes_out", "rx": "\\d+" }, "%I": { "id": "bytes_in", "rx": "\\d+" }, "%S": { "id": "bytes_combined", "rx": "\\d+" }, "%E": { "id": "apr_status", "rx": "\\w+" }, "%M": { "id": "message", "rx": ".+" }, "%L": { "id": "log_id", "rx": "[\\w\\-\\.]+" }, "%{c}L": { "id": "log_id", "rx": "[\\w\\-\\.]+" }, "%{C}L": { "id": "log_id", "rx": "[\\w\\-\\.]*" }, "%V": { "id": "server_name", "rx": "[\\w\\-\\.]+" }, "%v": { "id": "virtual_host", "rx": "[\\w\\-\\.]+" }, "%p": { "id": "server_port", "rx": "\\d+" }, "%{local}p": { "id": "server_port", "rx": "\\d+" }, "%{canonical}p": { "id": "canonical_port", "rx": "[\\w.]+" }, "%{remote}p": { "id": "remote_port", "rx": "\\d+" }, "%P": { "id": "pid", "rx": "\\d+" }, "%{g}T": { "id": "tid", "rx": "\\d+" }, "%{tid}P": { "id": "tid", "rx": "\\d+" }, "%{pid}P": { "id": "pid", "rx": "\\d+" }, "%{hextid}P": { "id": "tid", "rx": "\\w+" }, "%{hexpid}P": { "id": "pid", "rx": "\\w+" }, "%H": { "id": "request_protocol", "rx": "[\\w/\\d.]+" }, "%m": { "id": "request_method", "rx": "[\\w.]+" }, "%q": { "id": "request_query", "rx": "\\??\\S*" }, "%F": { "id": "file_line", "rx": "[/\\w\\-.:(\\d)]+" }, "%X": { "id": "connection_status", "rx": "[Xx+\\-.\\d]+" }, "%k": { "id": "keepalives", "rx": "\\d+" }, "%r": { "id": "request_line", "rx": "(?<request_method>\\w+) (?<request_path>\\S+) (?<request_protocol>[\\w/\\d.]+)" }, "%D": { "id": "request_duration_microseconds", "rx": "\\d+" }, "%T": { "id": "request_duration_scaled", "rx": "[\\d.]+" }, "%{s}T": { "id": "request_duration_seconds", "rx": "\\d+" }, "%{us}T": { "id": "request_duration_microseconds", "rx": "\\d+" }, "%{ms}T": { "id": "request_duration_milliseconds", "rx": "\\d+" }, "%U": { "id": "request_uri", "rx": "\\S+(?<!\")" }, "%s": { "id": "status", "rx": "\\d+" }, "%>s": { "id": "status", "rx": "-|\\d\\d\\d" }, "%R": { "id": "handler", "rx": "[\\w:.\\-]+" }, "%^FU": { "id": "ttfu", "rx": "-|\\d+" }, "%^FB": { "id": "ttfb", "rx": "-|\\d+" }, "%^\u0134S": { "id": "json", "rx": "\\{(?:[\\w:,\\s\\[\\]]+|\"(?:[^\\\\\"]+|\\\\.)*\")\\}" }, "%{Referer}i": { "id": "referer", "rx": "[^\"]*" }, "%{User-Agent}i": { "id": "user_agent", "rx": "(?:[^\"]+|\\\\\")*" } }, "alias": { "remote_address": "remote_addr", "ip": "remote_addr", "user": "remote_user", "file": "request_file", "size": "bytes_sent", "datetime": "request_time", "ctime": "request_time", "date": "request_time", "loglevel": "remote_logname", "module_name": "request_method", "request_flushed": "file_line", "requests_on_connection": "keepalives", "error": "apr_status" }, "expand": { "%\\{([^{}]+)\\}t": { "id": "request_time", "class": "strftime" }, "%[<>]?\\{([\\w\\-]+)\\}[Conexic]": { "id": "$1", "rx": "\\S+" }, "%\\{([\\w\\-]+)\\}\\^t[io]": { "id": "$1", "rx": "\\S+" } }, "container": { "message": { "id": "$1", "value": "$2", "rx": "\\[(\\w+) \"(.*?)\"\\]", "class": "apache mod_security" } }, "glob": [ "/var/log/apache*/*err*.log", "/var/log/apache*/*acc*.log" ] } |
Added logfmt1/share/grok.fmt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | { "$license": "Apache-2.0", "$origin": "https://github.com/elastic/logstash/blob/v1.4.2/patterns/", "class": "grok", "separator": " ", "placeholder": "%\\{\\w+:([\\w.-]+)\\}", "rewrite": {}, "alias": {}, "fields": { "%{SYSLOGBASE}": { "rx": "(?<timestamp>\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b +(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) (?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9])) (?:<(?<facility>\b(?:[0-9]+)\b).(?<priority>\b(?:[0-9]+)\b)> )?(?<logsource>(?:\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)|(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])))) (?<program>(?:[\\w._/%-]+))(?:\\[(?<pid>\b(?:[1-9][0-9]*)\b)\\])?:", "id": "syslogbase", "grok": "SYSLOGBASE" }, "%{COMMONAPACHELOG}": { "rx": "(?<clientip>(?:\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)|(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])))) (?<ident>[a-zA-Z0-9._-]+) (?<auth>[a-zA-Z0-9._-]+) \\[(?<timestamp>(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])/\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b/(?>\\d\\d){1,2}:(?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9]) (?:[+-]?(?:[0-9]+)))\\] \"(?:(?<verb>\b\\w+\b) (?<request>\\S+)(?: HTTP/(?<httpversion>(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+))))))?|(?<rawrequest>.*?))\" (?<response>(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+))))) (?:(?<bytes>(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+)))))|-)", "id": "commonapachelog", "grok": "COMMONAPACHELOG" }, "%{COMBINEDAPACHELOG}": { "rx": "(?<clientip>(?:\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)|(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])))) (?<ident>[a-zA-Z0-9._-]+) (?<auth>[a-zA-Z0-9._-]+) \\[(?<timestamp>(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])/\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b/(?>\\d\\d){1,2}:(?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9]) (?:[+-]?(?:[0-9]+)))\\] \"(?:(?<verb>\b\\w+\b) (?<request>\\S+)(?: HTTP/(?<httpversion>(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+))))))?|(?<rawrequest>.*?))\" (?<response>(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+))))) (?:(?<bytes>(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+)))))|-) (?<referrer>(?>(?<!\\)(?>\"(?>\\.|[^\\\"]+)+\"|\"\"|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))) (?<agent>(?>(?<!\\)(?>\"(?>\\.|[^\\\"]+)+\"|\"\"|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``)))", "id": "combinedapachelog", "grok": "COMBINEDAPACHELOG" } }, "expand": { "%\\{GROK:((?:[^{}]+|\\{[^{}]+\\})+)\\}": { "id": "", "class": "grok" }, "%{USERNAME:([\\w.\\-]+)}": { "rx": "[a-zA-Z0-9._-]+", "id": "$1", "grok": "USERNAME" }, "%{USER:([\\w.\\-]+)}": { "rx": "[a-zA-Z0-9._-]+", "id": "$1", "grok": "USER" }, "%{INT:([\\w.\\-]+)}": { "rx": "(?:[+-]?(?:[0-9]+))", "id": "$1", "grok": "INT" }, "%{BASE10NUM:([\\w.\\-]+)}": { "rx": "(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+)))", "id": "$1", "grok": "BASE10NUM" }, "%{NUMBER:([\\w.\\-]+)}": { "rx": "(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+))))", "id": "$1", "grok": "NUMBER" }, "%{BASE16NUM:([\\w.\\-]+)}": { "rx": "(?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))", "id": "$1", "grok": "BASE16NUM" }, "%{BASE16FLOAT:([\\w.\\-]+)}": { "rx": "\b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\\.[0-9A-Fa-f]*)?)|(?:\\.[0-9A-Fa-f]+)))\b", "id": "$1", "grok": "BASE16FLOAT" }, "%{POSINT:([\\w.\\-]+)}": { "rx": "\b(?:[1-9][0-9]*)\b", "id": "$1", "grok": "POSINT" }, "%{NONNEGINT:([\\w.\\-]+)}": { "rx": "\b(?:[0-9]+)\b", "id": "$1", "grok": "NONNEGINT" }, "%{WORD:([\\w.\\-]+)}": { "rx": "\b\\w+\b", "id": "$1", "grok": "WORD" }, "%{NOTSPACE:([\\w.\\-]+)}": { "rx": "\\S+", "id": "$1", "grok": "NOTSPACE" }, "%{SPACE:([\\w.\\-]+)}": { "rx": "\\s*", "id": "$1", "grok": "SPACE" }, "%{DATA:([\\w.\\-]+)}": { "rx": ".*?", "id": "$1", "grok": "DATA" }, "%{GREEDYDATA:([\\w.\\-]+)}": { "rx": ".*", "id": "$1", "grok": "GREEDYDATA" }, "%{QUOTEDSTRING:([\\w.\\-]+)}": { "rx": "(?>(?<!\\)(?>\"(?>\\.|[^\\\"]+)+\"|\"\"|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))", "id": "$1", "grok": "QUOTEDSTRING" }, "%{UUID:([\\w.\\-]+)}": { "rx": "[A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}", "id": "$1", "grok": "UUID" }, "%{MAC:([\\w.\\-]+)}": { "rx": "(?:(?:(?:[A-Fa-f0-9]{4}\\.){2}[A-Fa-f0-9]{4})|(?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})|(?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}))", "id": "$1", "grok": "MAC" }, "%{CISCOMAC:([\\w.\\-]+)}": { "rx": "(?:(?:[A-Fa-f0-9]{4}\\.){2}[A-Fa-f0-9]{4})", "id": "$1", "grok": "CISCOMAC" }, "%{WINDOWSMAC:([\\w.\\-]+)}": { "rx": "(?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})", "id": "$1", "grok": "WINDOWSMAC" }, "%{COMMONMAC:([\\w.\\-]+)}": { "rx": "(?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})", "id": "$1", "grok": "COMMONMAC" }, "%{IPV6:([\\w.\\-]+)}": { "rx": "((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?", "id": "$1", "grok": "IPV6" }, "%{IPV4:([\\w.\\-]+)}": { "rx": "(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])", "id": "$1", "grok": "IPV4" }, "%{IP:([\\w.\\-]+)}": { "rx": "(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9]))", "id": "$1", "grok": "IP" }, "%{HOSTNAME:([\\w.\\-]+)}": { "rx": "\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)", "id": "$1", "grok": "HOSTNAME" }, "%{HOST:([\\w.\\-]+)}": { "rx": "\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)", "id": "$1", "grok": "HOST" }, "%{IPORHOST:([\\w.\\-]+)}": { "rx": "(?:\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)|(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])))", "id": "$1", "grok": "IPORHOST" }, "%{HOSTPORT:([\\w.\\-]+)}": { "rx": "(?:\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)|(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9]))):\b(?:[1-9][0-9]*)\b", "id": "$1", "grok": "HOSTPORT" }, "%{PATH:([\\w.\\-]+)}": { "rx": "(?:(?>/(?>[\\w_%!$@:.,-]+|\\.)*)+|(?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+)", "id": "$1", "grok": "PATH" }, "%{UNIXPATH:([\\w.\\-]+)}": { "rx": "(?>/(?>[\\w_%!$@:.,-]+|\\.)*)+", "id": "$1", "grok": "UNIXPATH" }, "%{TTY:([\\w.\\-]+)}": { "rx": "(?:/dev/(pts|tty([pq])?)(\\w+)?/?(?:[0-9]+))", "id": "$1", "grok": "TTY" }, "%{WINPATH:([\\w.\\-]+)}": { "rx": "(?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+", "id": "$1", "grok": "WINPATH" }, "%{URIPROTO:([\\w.\\-]+)}": { "rx": "[A-Za-z]+(\\+[A-Za-z+]+)?", "id": "$1", "grok": "URIPROTO" }, "%{URIHOST:([\\w.\\-]+)}": { "rx": "(?:\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)|(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])))(?::(?<port>\b(?:[1-9][0-9]*)\b))?", "id": "$1", "grok": "URIHOST" }, "%{URIPATH:([\\w.\\-]+)}": { "rx": "(?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\\-]*)+", "id": "$1", "grok": "URIPATH" }, "%{URIPARAM:([\\w.\\-]+)}": { "rx": "\\?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\\-\\[\\]]*", "id": "$1", "grok": "URIPARAM" }, "%{URIPATHPARAM:([\\w.\\-]+)}": { "rx": "(?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\\-]*)+(?:\\?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\\-\\[\\]]*)?", "id": "$1", "grok": "URIPATHPARAM" }, "%{URI:([\\w.\\-]+)}": { "rx": "[A-Za-z]+(\\+[A-Za-z+]+)?://(?:[a-zA-Z0-9._-]+(?::[^@]*)?@)?(?:(?:\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)|(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])))(?::(?<port>\b(?:[1-9][0-9]*)\b))?)?(?:(?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\\-]*)+(?:\\?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\\-\\[\\]]*)?)?", "id": "$1", "grok": "URI" }, "%{MONTH:([\\w.\\-]+)}": { "rx": "\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b", "id": "$1", "grok": "MONTH" }, "%{MONTHNUM:([\\w.\\-]+)}": { "rx": "(?:0?[1-9]|1[0-2])", "id": "$1", "grok": "MONTHNUM" }, "%{MONTHNUM2:([\\w.\\-]+)}": { "rx": "(?:0[1-9]|1[0-2])", "id": "$1", "grok": "MONTHNUM2" }, "%{MONTHDAY:([\\w.\\-]+)}": { "rx": "(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])", "id": "$1", "grok": "MONTHDAY" }, "%{DAY:([\\w.\\-]+)}": { "rx": "(?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)", "id": "$1", "grok": "DAY" }, "%{YEAR:([\\w.\\-]+)}": { "rx": "(?>\\d\\d){1,2}", "id": "$1", "grok": "YEAR" }, "%{HOUR:([\\w.\\-]+)}": { "rx": "(?:2[0123]|[01]?[0-9])", "id": "$1", "grok": "HOUR" }, "%{MINUTE:([\\w.\\-]+)}": { "rx": "(?:[0-5][0-9])", "id": "$1", "grok": "MINUTE" }, "%{SECOND:([\\w.\\-]+)}": { "rx": "(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)", "id": "$1", "grok": "SECOND" }, "%{TIME:([\\w.\\-]+)}": { "rx": "(?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9])", "id": "$1", "grok": "TIME" }, "%{DATE_US:([\\w.\\-]+)}": { "rx": "(?:0?[1-9]|1[0-2])[/-](?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])[/-](?>\\d\\d){1,2}", "id": "$1", "grok": "DATE_US" }, "%{DATE_EU:([\\w.\\-]+)}": { "rx": "(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])[./-](?:0?[1-9]|1[0-2])[./-](?>\\d\\d){1,2}", "id": "$1", "grok": "DATE_EU" }, "%{ISO8601_TIMEZONE:([\\w.\\-]+)}": { "rx": "(?:Z|[+-](?:2[0123]|[01]?[0-9])(?::?(?:[0-5][0-9])))", "id": "$1", "grok": "ISO8601_TIMEZONE" }, "%{ISO8601_SECOND:([\\w.\\-]+)}": { "rx": "(?:(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)|60)", "id": "$1", "grok": "ISO8601_SECOND" }, "%{TIMESTAMP_ISO8601:([\\w.\\-]+)}": { "rx": "(?>\\d\\d){1,2}-(?:0?[1-9]|1[0-2])-(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])[T ](?:2[0123]|[01]?[0-9]):?(?:[0-5][0-9])(?::?(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))?(?:Z|[+-](?:2[0123]|[01]?[0-9])(?::?(?:[0-5][0-9])))?", "id": "$1", "grok": "TIMESTAMP_ISO8601" }, "%{DATE:([\\w.\\-]+)}": { "rx": "(?:0?[1-9]|1[0-2])[/-](?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])[/-](?>\\d\\d){1,2}|(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])[./-](?:0?[1-9]|1[0-2])[./-](?>\\d\\d){1,2}", "id": "$1", "grok": "DATE" }, "%{DATESTAMP:([\\w.\\-]+)}": { "rx": "(?:0?[1-9]|1[0-2])[/-](?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])[/-](?>\\d\\d){1,2}|(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])[./-](?:0?[1-9]|1[0-2])[./-](?>\\d\\d){1,2}[- ](?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9])", "id": "$1", "grok": "DATESTAMP" }, "%{TZ:([\\w.\\-]+)}": { "rx": "(?:[PMCE][SD]T|UTC)", "id": "$1", "grok": "TZ" }, "%{DATESTAMP_RFC822:([\\w.\\-]+)}": { "rx": "(?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?) \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) (?>\\d\\d){1,2} (?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9]) (?:[PMCE][SD]T|UTC)", "id": "$1", "grok": "DATESTAMP_RFC822" }, "%{DATESTAMP_RFC2822:([\\w.\\-]+)}": { "rx": "(?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?), (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b (?>\\d\\d){1,2} (?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9]) (?:Z|[+-](?:2[0123]|[01]?[0-9])(?::?(?:[0-5][0-9])))", "id": "$1", "grok": "DATESTAMP_RFC2822" }, "%{DATESTAMP_OTHER:([\\w.\\-]+)}": { "rx": "(?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?) \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) (?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9]) (?:[PMCE][SD]T|UTC) (?>\\d\\d){1,2}", "id": "$1", "grok": "DATESTAMP_OTHER" }, "%{DATESTAMP_EVENTLOG:([\\w.\\-]+)}": { "rx": "(?>\\d\\d){1,2}(?:0[1-9]|1[0-2])(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])(?:2[0123]|[01]?[0-9])(?:[0-5][0-9])(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)", "id": "$1", "grok": "DATESTAMP_EVENTLOG" }, "%{SYSLOGTIMESTAMP:([\\w.\\-]+)}": { "rx": "\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b +(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) (?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9])", "id": "$1", "grok": "SYSLOGTIMESTAMP" }, "%{PROG:([\\w.\\-]+)}": { "rx": "(?:[\\w._/%-]+)", "id": "$1", "grok": "PROG" }, "%{SYSLOGPROG:([\\w.\\-]+)}": { "rx": "(?<program>(?:[\\w._/%-]+))(?:\\[(?<pid>\b(?:[1-9][0-9]*)\b)\\])?", "id": "$1", "grok": "SYSLOGPROG" }, "%{SYSLOGHOST:([\\w.\\-]+)}": { "rx": "(?:\b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\\.?|\b)|(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?|(?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])))", "id": "$1", "grok": "SYSLOGHOST" }, "%{SYSLOGFACILITY:([\\w.\\-]+)}": { "rx": "<(?<facility>\b(?:[0-9]+)\b).(?<priority>\b(?:[0-9]+)\b)>", "id": "$1", "grok": "SYSLOGFACILITY" }, "%{HTTPDATE:([\\w.\\-]+)}": { "rx": "(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])/\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b/(?>\\d\\d){1,2}:(?!<[0-9])(?:2[0123]|[01]?[0-9]):(?:[0-5][0-9])(?::(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?))(?![0-9]) (?:[+-]?(?:[0-9]+))", "id": "$1", "grok": "HTTPDATE" }, "%{QS:([\\w.\\-]+)}": { "rx": "(?>(?<!\\)(?>\"(?>\\.|[^\\\"]+)+\"|\"\"|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))", "id": "$1", "grok": "QS" }, "%{LOGLEVEL:([\\w.\\-]+)}": { "rx": "([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)", "id": "$1", "grok": "LOGLEVEL" } }, "container": {}, "glob": [ "*.grok" ] } |
Added logfmt1/share/strftime.fmt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | { "class": "strftime", "placeholder": "%\\w", "rewrite": { "%[EO_^0#\\-]+(\\w)": "%$1" }, "fields": { "%a": { "id": "tm_wday", "rx": "\\w+" }, "%A": { "id": "tm_wday", "rx": "\\w+" }, "%b": { "id": "tm_mon", "rx": "\\w+" }, "%B": { "id": "tm_mon", "rx": "\\w+" }, "%c": { "id": "tm_dt", "rx": "[-:/.\\w\\d]+" }, "%C": { "id": "tm_cent", "rx": "\\d\\d" }, "%d": { "id": "tm_mday", "rx": "\\d\\d" }, "%D": { "id": "tm_mdy", "rx": "\\d+/\\d+/\\d+" }, "%e": { "id": "tm_mday", "rx": "[\\d\\s]\\d" }, "%F": { "id": "tm_date", "rx": "\\d\\d\\d\\d-\\d\\d-\\d\\d" }, "%G": { "id": "tm_wyear", "rx": "\\d\\d\\d\\d" }, "%g": { "id": "tm_wyearnc", "rx": "\\d\\d" }, "%h": { "id": "tm_mon", "rx": "\\w+" }, "%H": { "id": "tm_hour", "rx": "\\d\\d" }, "%I": { "id": "tm_hour", "rx": "\\d\\d" }, "%j": { "id": "tm_yday", "rx": "\\d\\d\\d" }, "%k": { "id": "tm_hour", "rx": "\\d\\d" }, "%l": { "id": "tm_hour", "rx": "[\\d\\s]\\d" }, "%m": { "id": "tm_mon", "rx": "\\d\\d" }, "%M": { "id": "tm_min", "rx": "\\d\\d" }, "%n": { "id": "newline", "rx": "\\n" }, "%p": { "id": "tm_ampm", "rx": "AM|PM" }, "%P": { "id": "tm_ampm", "rx": "am|pm" }, "%r": { "id": "tm_time", "rx": "\\d\\d:\\d\\d:\\d\\d [AMPM]{2}" }, "%R": { "id": "tm_time", "rx": "\\d\\d:\\d\\d" }, "%s": { "id": "tm_epoch", "rx": "\\d+" }, "%S": { "id": "tm_sec", "rx": "\\d\\d" }, "%t": { "id": "tab", "rx": "\\t" }, "%T": { "id": "tm_time", "rx": "\\d\\d:\\d\\d:\\d\\d" }, "%u": { "id": "tm_wday", "rx": "[1-7]" }, "%U": { "id": "tm_yday", "rx": "[0-5]\\d|5[0123]" }, "%V": { "id": "tm_yday", "rx": "\\d\\d" }, "%w": { "id": "tm_wday", "rx": "[0-6]" }, "%W": { "id": "tm_yday", "rx": "\\d\\d" }, "%x": { "id": "tm_ldate", "rx": "[-./\\d]+" }, "%X": { "id": "tm_ltime", "rx": "[:.\\d]+" }, "%y": { "id": "tm_year", "rx": "\\d\\d" }, "%Y": { "id": "tm_year", "rx": "\\d\\d\\d\\d" }, "%z": { "id": "tm_tz", "rx": "[-+]\\d\\d\\d\\d" }, "%Z": { "id": "tm_tz", "rx": "\\w+" }, "%+": { "id": "tm_date", "rx": "[-/:. \\w\\d]+" }, "%%": { "id": "percent", "rx": "%" } }, "expand": { "%(\\w)": "[\\w\\d.]+" } } |
Added logfmt1/share/update/apache.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | #!/usr/bin/env python3 import os, re, sys, random import subprocess import traceback import json from pprint import pprint try: import logfmt1 except: from modseccfg import logfmt1 # extraction patterns class rx: # a conf file '(*) /etc/apache2/main.conf' dump_includes = re.compile("^\s*\([\d*]+\)\s+(.+)$", re.M) # directives we care about (to detect relevant .conf files) interesting = re.compile(""" ^ \s* ( (Error|Custom|Global|Forensic|Transfer)Log | (Error)?LogFormat ) # log directivess """, re.M|re.I|re.X ) # extract directive line including line continuations (<\><NL>) configline = re.compile( """ ^ [\ \\t]* # whitespace \h* # (?:Use \s{1,4})? # optional: `Use␣` to find custom macros like `Use SecRuleRemoveByPath…` ( \w+ | # alphanumeric directive </?(?:File|Loc|Dir|If\\b)\w* # or <Wrap> section )\\b [\ \\t]* # whitespace \h+ ( (?: [^\\n\\\\]+ | [\\\\]. )* # literals, or backslash + anything ) (?: $ | >.*$ ) # account for line end or closing > """, re.M|re.S|re.X ) # to strip <\><NL> escnewline = re.compile( """[\\\\][\\n]\s*""" # escaped linkebreaks ) # handle quoted/unquoted directive arguments (not entirely sure if Apache does \" escaped quotes within) split_args = re.compile( """ (?:\s+) | # skip whitespace (\K not supported in python re, so removing empty matches in postprocessing) \#.*$ | # skip trailing comment (which isn't technically allowed, but) " ((?:[^\\\\"]+|\\\\ .)+) " | # quoted arguments (?!\#) ([^"\s]+) # plain arguments (no quotes, no spaces) """, re.X ) # envvars shell_vars = re.compile( """ ^\s* (?:export\s+)? ([A-Z_]+) = ["']? ([\w/\-.]+) ["']? """, re.M|re.X) #" # temporary state variables class tmp: env = { "APACHE_LOG_DIR": "/var/log/apache2" #/var/log/httpd/ } env_locations = [ "/etc/apache2/envvars", "/etc/default/httpd" ] log_formats = { "error": "[%t] [%l] [pid %P] %F: %E: [client %a] %M", #"default": "%h %l %u %t "%r" %>s %b", "common": '%h %l %u %t "%r" %>s %O', "forensic": '+%{forensic-id}n|%r|Host:%H|%{UA}|%{H*}\n-%{forensic-id}n', #%t == [%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d] } log_map = { #"../fn.log": "combined" } # encapsulate properties of config file (either vhosts, SecCfg*, or secrule collections) class vhost: """ Represents a config/vhost or mod_security rules file. Parameters ---------- fn : str *.conf filename src : str config file source """ # split *.conf directives, dispatch onto assignment/extract methods def __init__(self, fn, src, cfg_only=False): self.logs = [] self.extract(src, cfg_only=cfg_only) # extract directive lines def extract(self, src, cfg_only=False): for dir,args in rx.configline.findall(src): # or .finditer()? to record positions right away? dir = dir.lower() #log.debug(dir, args) if hasattr(self, dir): if cfg_only: #→ if run from SecOptions dialog, we don't actually want rules collected continue func = getattr(self, dir) func(self.split_args(args)) # strip \\ \n line continuations, split all "args" def split_args(self, args): args = re.sub(rx.escnewline, " ", args) args = rx.split_args.findall(args) args = [s[1] or s[0] for s in args] args = [s for s in args if len(s)] #args = [s.decode("unicode_escape") for s in args] # don't strip backslashes return args # apply ${ENV} vars def var_sub(self, s): return re.sub('\$\{(\w+)\}', lambda m: tmp.env.get(m.group(1), ""), s) # apache: log directives def customlog(self, args): fn, ty = self.var_sub(args[0]), args[1] self.logs.append(fn) if ty.find("%") >= 0: # turn literal placeholder format into temporary name ty, fmt = hex(hash(ty))[4:], ty self.logformat(ty, fmt) tmp.log_map[fn] = ty def errorlog(self, args): self.customlog([args[0], "error"]) def forensiclog(self, args): self.customlog([args[0], "forensic"]) def globallog(self, args): self.customlog([args[0], args[1] or "combined"]) def transferlog(self, args): self.customlog([args[0], "transfer"]) def logformat(self, args): if len(args) == 1: args[1] = "transfer" tmp.log_formats[args[1]] = args[0].replace('\\"', '"') def errorlogformat(self, args): self.logformat([args[0], "error"]) # scan for APACHE_ENV= vars def read_env_vars(): for fn in tmp.env_locations: if os.path.exists(fn): src = open(fn, "r", encoding="utf-8").read() tmp.env.update( dict(rx.shell_vars.findall(src)) ) # iterate over all Apache config files, visit relevant ones (vhosts/mod_security configs) def scan_all(): read_env_vars() ls = apache_dump_includes() for i, fn in enumerate(ls): src = open(fn, "r", encoding="utf-8").read() if rx.interesting.search(src): vhost(fn, src) # get *.conf list from apache2ctl def apache_dump_includes(): cmd = ["apache2ctl", "-t", "-D", "DUMP_INCLUDES"] stdout = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout return rx.dump_includes.findall(stdout.read().decode("utf-8")) # traverse log files, create .fmt descriptor with current format string def mk_fmt(): for fn,ty in tmp.log_map.items(): fn_fmt = f"{fn}.fmt" fmt_record = tmp.log_formats.get(ty) if not fmt_record: continue j = {} if os.path.exists(fn_fmt): try: j = json.loads(open(fn_fmt, "r", encoding="utf-8").read()) except Exception as e: j = {} print(f"WARN: {fn_fmt} contained invalid json: {str(e)}") if not "class" in j: j["class"] = f"apache {ty}" if not "record" in j or j["record"] != fmt_record: j["record"] = fmt_record # add descriptors for known placeholders if not "fields" in j or True: j["regex"] = logfmt1.regex(j) print(f"→ {fn_fmt}") try: f = open(fn_fmt, "w") f.write(json.dumps(j, indent=4)) f.close() except Exception as e: print("ERR: " + str(e)) scan_all() mk_fmt() |
Added logfmt1/update-logfmt.
> > | 1 2 | #!/bin/sh run-parts /usr/share/logfmt/update/ |
Added logfmt1/update_logfmt_all.py.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/usr/bin/env python3 # encoding: utf-8 # title: update-logfmt # description: invoke ./share/update/* scripts # type: virtual # # Stub that reimplements run-parts import os, re for dir in [re.sub("[.\w]+$", "share/update", __file__), "/usr/share/logfmt/update"]: if os.path.exists(dir): os.system(f"run-parts {dir}") break |