Update of "log"
Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Artifact ID: | ec3705b625b53c8a34b05eb39f732d0c98c6a98b |
---|---|
Page Name: | log |
Date: | 2015-01-10 06:07:14 |
Original User: | mario |
Mimetype: | text/x-markdown |
Parent: | 4e40d9cb5d4bc872f83adaee07b8457b3c3a0e32 (diff) |
Next | a7af1b190344ecef34a97be76b05bf1c4d804be6 |
Structured and hierarchical logging with :token-parametric API
- State: experimental
- Category: logging
- Features: journaling, structured, hierarchical
- Backend: SQLite, JSON,
fluentd,logstash - Signature: hybrid, parametric
logStruck Ε
implements a logging API and SQLite/JSON storage backend.
- It's purpose is storing structured log data and retaining log event hierarchies.
- Implements a hybrid and terse function interface.
- Accepts plain string messages, Ruby-style
:token
categorizers and placeholders, and understands array params. - Implicitly captures and maps PHP errors, unhandled exceptions, and most importantly
assert()
ions.
Unlike other PHP logging frameworks it's not primarily a text/line-oriented message dump.
Quick example
Invocations can be along the lines of:
Ε(':warn', ':wikiauth', "User doesn't have permission", $pageObj, ':vars', $_SESSION);
All the fun is in the :token
literals, and passing arrays or objects.
Database scheme, primary fields
All columns in the database scheme are primary fields. Any extra data/values end up in the context
array.
<style> table.dbstruct { width: 75%; margin-left: 3%; } table.dbstruct td { vertical-align: top; } table.dbstruct tr:nth-child(2n) { background: #efefef; } </style>
i | PRIM | Where i is the primary index, g the event group, and p the parent reference. Which allows displaying event group hierarchies. |
g | INT | |
p | INT | |
timestamp | REAL | Timestamp with microseconds. |
timestr | TEXT | ISO DateTime string. In GMT/UTC of course. |
host | TEXT | Hostname. |
pri | INT | Priority number (0β¦7). |
prio | TEXT | Priority string (emergβ¦info) |
source | TEXT | log | sys | lang | excpt | assert |
errno | INT | 0β¦32767 |
app | TEXT | AppName.php |
section | TEXT | Application structure / module / part / section. |
file | TEXT | path/file.php |
line | INT | 125 |
version | TEXT | Meta data from source code. |
message | TEXT | Primary log event message string. |
doc | TEXT | Extra documentation / long message / href. |
backtrace | JSON | Array of :backtrace |
code | TEXT | Extracted code context (3 lines). |
vars | JSON | Main $vars[] array. |
context | JSON | Additional / user-defined fields. |
Priority levels | ||
---|---|---|
:debug | 7 | Low-level debug events. |
:info | 6 | Process flow infos etc. |
:notice, :note | 5 | Lowest priority language notices. |
:warning, :warn | 4 | Warnings. |
:error, :err | 3 | PHP or system error. |
:critical, :crit | 2 | This can't be good. |
:alert, :alrt | 1 | Turn on the bat light. |
:emergency, :emerg | 0 | Someone call the president. |
Source / generator | ||
:log | Application origin, normal/manual log calls. | |
:sys | System-level events and errno codes. | |
:lang | Language errors, warnings, notices, etc. | |
:exception | Langauge/runtime exceptions. | |
:assert | Assert() warnings. | |
Field names | ||
Any database column / primary field name can be represented as :token . It's pretty much only useful to use :vars however to map the following array parameter. | ||
Injector calls | ||
:backtrace | Populates backtrace. | |
:server | Inserts $_SERVER array into context . | |
:file | Uncovers file and line from backtrace. | |
:version | Reads out meta data (file/scm version, and section) from script comments. | |
:code | Inserts 3 lines of code context. | |
:p | Tries to deduce log event hierarchy from prior calls, sections, and backtraces. (Not yet implemented.) |
Any other :token
name can be used freely to classify and group your application flow. They'll be used as section names.
Setup
You obviously need a readily available log.db
SQLite store. Best keep it DOCUMENT_ROOT
-relative, so it's easy to declare on instantiation:
Ε::$db = "$_SERVER[DOCUMENT_ROOT]/config/log.db";
Ε::$app = "YourAppID";
You can of course manually load the library. Most autoloaders would already load it implicitly because of the class reference. (Even PSR-x ones, and they'd even be accidentially correct for once with case-sensitive Unicode lookups here).
While you ought to use :section
names for logging calls, you can also override/update the default throughout your application flow with:
Ε::$section = "forum";
Or likewise adapt properties of the global logger group Ε()->section=..
.
Notes / Rationale
So, this is all either genius, or completely bonkers.
logStruck is decidedly different to most other logging libraries in PHP. It doesn't follow PSR-3 (lowest common denominator) and historic line/text-oriented logging. In particular it tries to avoid parsing+reformatting backends or making structured/JSON logging an afterthought.
Entirely intended as userland runtime. Mostly suitable for wee projects. It's primary use case is application-level debugging and auditability.
The function name Ε isn't completely settled on. (Maybe a bit too much novelty strive.)
Extensibility of the database scheme is easily done, but not planned for.
Alternative logging backends are best implemented in branches.
- (In the time and age of GitHub forkeritis anyway.)
- It doesn't seem senseful to impose a configuration-centric instantiation.
- However making
$Ε->db
just a Callable would be trivial. - The API and JSON-logging design is specifically meant to avoid MonoLog-style message formatting / parsing / filter chains. Events are structured from the start, shouldn't be downconverted to suit textdump interfaces.
Inspired by structlog, cabin, journald, graylog, PEAR log even, and with logstash/fluentd in mind.
The fancy ':token' signature is used in place of named params and constant literals in PHP.
Currently just inserts one-dimensional events. The API mapping is too crude still for spatial message/section/prio collections.
ToDo
Log events are only associated to a primary group event as of now. The
:p
filter will allow to regroup events automatically from context information.- Alternatively
$p = Ε("first"); Ε("second", "p:$p");
can control it manually.
- Alternatively
The alternative JSON file-append store just keeps event-local ids/groups=1/parent ids. This needs an insertion transaction or trigger for reconverting into a SQLite store. (Rather simple.)
To mix application and server-level logging an injector for Apaches
UNIQUE_ID
might make sense. Still would require log post-processing to turn it into a sequential event id. Or alternatively stash all entries with a UUID.Investigate whether logstash (supposedly works with multiline/mutate), fluentd or graylog2 make suitable targets. Neither seems to provide incremental log ids on submission. Each requires post processing on pushed events, or incremental json/sqlite imports.