Download the PHP package thingston/psr3 without Composer
On this page you can find all versions of the php package thingston/psr3. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download thingston/psr3
More information about thingston/psr3
Files in thingston/psr3
Package psr3
Short Description A lightweight, dependency-free PSR-3 logger with pluggable local and cloud adapters.
License MIT
Informations about the package psr3
Thingston PSR3
A lightweight, dependency-free PSR-3 logger for PHP 8.4+, with pluggable adapters for local backends (file, syslog, database) and cloud services (CloudWatch, Google Cloud Logging, Azure Monitor, Papertrail, Slack).
- One hard dependency:
psr/log. Everything else (cloud SDKs, curl) is optional and lazily checked. - Composable by design: fan a record out to multiple backends with
CompositeAdapter, filter by severity withMinLevelAdapter, and swapLineFormatter/JsonFormatterper adapter. - 100% test coverage, PHPStan level 8, PSR-12 coding style.
Table of contents
- Installation
- Quick start
- Core concepts
- Formatters
- Composing adapters
- CompositeAdapter
- MinLevelAdapter
- Local adapters
- NullAdapter
- StreamAdapter
- RotatingFileAdapter
- SyslogAdapter
- PdoAdapter
- Cloud adapters
- CloudWatchLogsAdapter
- GoogleCloudLoggingAdapter
- AzureMonitorAdapter
- PapertrailAdapter
- SlackWebhookAdapter
- Writing your own adapter
- PSR-3 message interpolation
- Development
Installation
Cloud adapters that wrap a vendor SDK (CloudWatch, Google Cloud Logging) require you to separately install that
SDK — see their sections below. Adapters that only need HTTP (Azure, Slack) or raw sockets (Papertrail) work out of
the box with ext-curl, which ships with most PHP installs.
Quick start
Logger implements Psr\Log\LoggerInterface, so it's a drop-in wherever a PSR-3 logger is expected (frameworks,
libraries, DI containers).
Core concepts
| Class/interface | Role |
|---|---|
Thingston\Log\Logger |
PSR-3 logger. Interpolates {placeholders} and hands a LogRecord to one AdapterInterface. |
Thingston\Log\LogRecord |
Immutable value object: level, message (already interpolated), context, channel, timestamp. |
Thingston\Log\Level |
Backed enum of the eight PSR-3 levels, with syslog-style severity ordering (emergency = 0 … debug = 7). |
Thingston\Log\Adapter\AdapterInterface |
The thing you swap: handle(LogRecord $record): void. |
Thingston\Log\Formatter\FormatterInterface |
Turns a LogRecord into a string for adapters that write text (files, syslog, sockets). |
Logger only ever talks to a single adapter. To send a record to several backends at once, wrap them in a
CompositeAdapter — see Composing adapters. This keeps Logger itself free of routing
concerns.
Formatters
Two formatters ship with the package; adapters that produce text default to LineFormatter unless noted.
LineFormatter — plain text, one line per record:
JsonFormatter — single-line structured JSON, for backends that want structured payloads:
Both throw RuntimeException if the record can't be encoded (e.g. non-UTF-8 bytes in the message for
JsonFormatter).
Composing adapters
CompositeAdapter
Fans a record out to multiple adapters — e.g. write to a file and alert Slack. A failure in one adapter doesn't stop the others, and doesn't propagate to your application:
MinLevelAdapter
Decorator that filters by PSR-3 severity before delegating, so a noisy channel (e.g. Slack) only receives
error-and-worse while everything still reaches a file:
Local adapters
All local adapters only need core PHP extensions (ext-pdo, syslog functions), no vendor SDKs.
NullAdapter
Discards everything. Useful as a default/no-op in tests or config-driven setups:
StreamAdapter
Writes formatted records to a file path (opened in append mode) or an already-open resource:
RotatingFileAdapter
Writes to a date-stamped file, rotating automatically when the date changes, and optionally pruning old files:
SyslogAdapter
Sends records to the system logger via openlog()/syslog(), mapping each PSR-3 level to its syslog priority:
PdoAdapter
Inserts each record as a row via PDO. Ships a createTable() convenience helper for quick starts/tests (SQLite
syntax); production schemas should be managed by your own migrations:
Cloud adapters
Cloud adapters live under Thingston\Log\Adapter\Cloud. None of them are hard dependencies of the package — install
what you use.
CloudWatchLogsAdapter
Requires aws/aws-sdk-php:
The AWS client is invoked duck-typed (only putLogEvents() is called), so the core package never references the
SDK's class directly; if aws/aws-sdk-php isn't installed, the constructor throws a clear RuntimeException
instead of a confusing autoload failure.
GoogleCloudLoggingAdapter
Requires google/cloud-logging:
AzureMonitorAdapter
Talks directly to the Azure Monitor HTTP Data Collector API
— no vendor SDK required, just ext-curl (bundled CurlHttpTransport):
PapertrailAdapter
Sends RFC 3164 syslog messages over TCP/TLS. Works with Papertrail as well as any
other generic syslog-over-TLS endpoint (Loggly, etc.) — just point host/port at theirs:
SlackWebhookAdapter
Posts to a Slack Incoming Webhook URL. Intended for alerting — wrap it
in MinLevelAdapter so only significant events reach the channel:
Both AzureMonitorAdapter and SlackWebhookAdapter accept an optional HttpTransportInterface (defaulting to
CurlHttpTransport), so you can swap in your own HTTP client (e.g. a PSR-18 bridge) or a test double:
Writing your own adapter
Implement the single-method AdapterInterface:
Throw on failure — wrap with CompositeAdapter if you need one broken backend to not affect others.
PSR-3 message interpolation
Logger replaces {key} placeholders in the message with the corresponding context[key] value, following the
PSR-3 reference implementation:
- Scalars (
string,int,float,bool),null, and objects implementingStringableare replaced. - Arrays and non-
Stringableobjects are left as literal{key}text (they can't be safely cast to string). - Placeholders with no matching context key are left untouched.
The raw $context array (not just the interpolated message) is always passed through to LogRecord::$context, so
structured adapters (JsonFormatter, PdoAdapter, cloud adapters) can still log it as structured data.
Development
Tests are split into two suites (tests/Unit, tests/Integration) so mocked behavior and real-resource behavior
are never conflated:
Unit suite (tests/Unit)
Runs unconditionally, with no real extensions, network, filesystem daemons, or vendor SDKs required — extension and SDK dependent adapters are exercised against mocks/fakes instead:
Logger, formatters,CompositeAdapter,MinLevelAdapter,NullAdapter,StreamAdapter, andRotatingFileAdapterare plain PHPUnit tests (no faking needed).PdoAdapteris tested againstcreateMock(\PDO::class)/createMock(\PDOStatement::class)— no real database driver is touched.SyslogAdapteris tested againstopenlog()/syslog()/closelog()overrides declared intests/Fixtures/FunctionOverrides/syslog-functions.php, recorded bytests/Fixtures/FakeSyslog.php.CurlHttpTransportis tested againstcurl_init()/curl_exec()/etc. overrides intests/Fixtures/FunctionOverrides/curl-functions.php, recorded bytests/Fixtures/FakeCurl.php.PapertrailAdapteris tested againstfsockopen()/stream_socket_client()overrides intests/Fixtures/FunctionOverrides/socket-functions.php, recorded bytests/Fixtures/FakeSockets.php.AzureMonitorAdapterandSlackWebhookAdapterare tested against an injectedHttpTransportInterfacedouble (no curl involved at all).CloudWatchLogsAdapterandGoogleCloudLoggingAdapterare tested via duck-typed client doubles, so the unit suite never needsaws/aws-sdk-phporgoogle/cloud-logginginstalled.
These PHP-level function overrides work because PHP resolves an unqualified function call (e.g. curl_exec()
from a file in Thingston\Log\Adapter\Cloud) against that same namespace first, falling back to the global
function — so the fake is only active while a test arms it, and the real extension is used everywhere else,
including by the integration suite below.
The unit suite enforces 100% line/method/class coverage (checked in CI). The only lines excluded via
@codeCoverageIgnore are assert() type-narrowing calls that PHP itself compiles out when
zend.assertions is -1 (the recommended production setting), and are therefore unreachable by design.
Integration suite (tests/Integration)
Exercises real extensions/resources and is grouped per dependency so each can run in isolation:
curl, pdo, syslog, and sockets need no external configuration (they spin up a local built-in server,
SQLite file, or TCP listener) and run in CI on every PR.
CI runs the unit suite (with the 100% coverage gate, PHPStan, and coding-standards checks) and the full
integration suite across PHP 8.4 and 8.5 (see .github/workflows/ci.yml).