Architecture
Monorepo layout
log-lens/
├── packages/
│ ├── core/ cliqthemes/log-lens-core - standalone engine (PHP, PDO SQLite, no framework)
│ │ ├── src/ LogLens\ (Config, Database, Kernel, Http, Services, Repositories, Parsing, Connectors, Domain)
│ │ ├── public/ front controller + built UI (public/ui)
│ │ ├── bin/ import.php, sync.php
│ │ ├── tests/ run.php (assertion suite)
│ │ └── config.php
│ └── laravel/ cliqthemes/log-lens - Laravel adapter (thin)
│ ├── src/ LogLens\Laravel\ (ServiceProvider, LogLens gate, Http, Console)
│ ├── config/ log-lens.php
│ └── resources/dist built UI (base /vendor/log-lens/)
├── frontend/ shared React app to builds to both targets
├── skills/ claude / codex agent skills
├── docs/ this documentation (plain Markdown, incl. reference/)
├── docs-site/ Docusaurus renderer for docs/
└── site/ marketing / landing page (Astro)
Layers (core)
Framework-agnostic, PSR-4 LogLens\:
- Parsing - streaming parsers (
LaravelLogParser,NginxAccessLogParser,GenericConsoleLogParser) selected byParserRegistry; yieldLogEvents without loading whole files. - Domain -
LogEvent,EventAnalysis,RemoteLogFile. - Services - ingestion, connectors/sync, tags, modules, workflow, retention, maintenance, application registry, path repair.
- Repositories -
IssueRepository(persist/fingerprint),IssueQueryRepository(search/detail/summary). - Http - the transport-agnostic dispatcher (below).
Request/response kernel (the key to being embeddable)
The HTTP layer never touches PHP superglobals or emits output directly:
LogLensRequest- DTO (method, query, body, headers) with afromGlobals()factory for the standalone transport.LogLensResponse- DTO (data + status).ApiController::handle(LogLensRequest): LogLensResponseandApplicationApiController- return responses; neverexit.RequestGuard::check()- pure; returns a 401/403 response ornull.Kernel::handle(LogLensRequest): LogLensResponse- resolves the application, opens itsDatabase, repairs moved paths, and dispatches.
This is why two front-ends can share one engine:
standalone public/index.php to LogLensRequest::fromGlobals() to Kernel to JsonResponse::emit()
laravel LogLensController to Illuminate Request to LogLensRequest to Kernel to response()->json()
Everything below Kernel is untouched by which framework calls it.
Storage
SQLite per application (WAL, busy_timeout, migration gated by
PRAGMA user_version). Occurrences store byte ranges into archived files rather
than duplicating bodies; an indexed generated column occurred_day powers date
filters/trends. Full schema and indexes:
reference/database-schema.md.
Frontend
One React/Vite app builds to two bases via env (LOG_LENS_BASE,
LOG_LENS_OUTDIR): /ui/ into packages/core/public/ui for standalone, and
/vendor/log-lens/ into packages/laravel/resources/dist for the adapter. API
calls are prefix-relative, so the SPA works at / or under /log-lens.