PHPackages                             helsingborg-stad/psr-logger - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. helsingborg-stad/psr-logger

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

helsingborg-stad/psr-logger
===========================

Implementation of PSR-3: Logger Interface.

0.2.9(1mo ago)0113↓50%1MITPHPPHP ^8.2CI passing

Since Jun 15Pushed 1mo agoCompare

[ Source](https://github.com/helsingborg-stad/psr-logger)[ Packagist](https://packagist.org/packages/helsingborg-stad/psr-logger)[ RSS](/packages/helsingborg-stad-psr-logger/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (5)Dependencies (8)Versions (6)Used By (1)

PSR Logger
==========

[](#psr-logger)

[![Lint](https://github.com/helsingborg-stad/psr-logger/actions/workflows/php-lint.yml/badge.svg?branch=main)](https://github.com/helsingborg-stad/psr-logger/actions/workflows/php-lint.yml)[![Stan](https://github.com/helsingborg-stad/psr-logger/actions/workflows/php-stan.yml/badge.svg?branch=main)](https://github.com/helsingborg-stad/psr-logger/actions/workflows/php-stan.yml)[![Build](https://github.com/helsingborg-stad/psr-logger/actions/workflows/php-test.yml/badge.svg?branch=main)](https://github.com/helsingborg-stad/psr-logger/actions/workflows/php-test.yml)[![Tests](test-badge.svg)](test-badge.svg)[![Coverage](coverage-badge.svg)](coverage-badge.svg)

A PSR-3 compatible logger factory with namespace breadcrumbs, log-level filtering, and context placeholder interpolation. See the [full PSR-3 specification](https://www.php-fig.org/psr/psr-3/) for the interface contract this library implements.

Requirements
------------

[](#requirements)

- PHP **8.2** or higher
- [`psr/log`](https://packagist.org/packages/psr/log) **^2.0 || ^3.0**

Installation
------------

[](#installation)

With composer:

```
composer require helsingborg-stad/psr-logger
```

Basic usage
-----------

[](#basic-usage)

```
use PsrLogger\LoggerFactory;
use PsrLogger\Loggers\PhpErrorLogger;
use Psr\Log\LogLevel;

$factory = new LoggerFactory(
    namespace: 'MyPlugin',
    loggers: [['logger' => new PhpErrorLogger(), 'logLevel' => LogLevel::ERROR]]
);

$logger = $factory->createLogger();
$logger->error('Something went wrong');
// → [ERROR]:[MyPlugin]: Something went wrong
$logger->debug('Verbose detail');  // suppressed — below ERROR threshold
$logger->info('Just FYI');         // suppressed — below ERROR threshold
```

Child loggers (namespace tree)
------------------------------

[](#child-loggers-namespace-tree)

`createLogger()` returns a `LoggerInterface & LoggerFactoryInterface`, so you can branch the namespace tree by calling `createLogger(['namespace' => '...'])` on any logger.

```
$app       = $factory->createLogger();
$moduleA   = $app->createLogger(['namespace' => 'ModuleA']);
$component = $moduleA->createLogger(['namespace' => 'Component']);

$app->error('app');
// → [ERROR]:[MyPlugin]: app

$moduleA->error('moduleA');
// → [ERROR]:[MyPlugin/ModuleA]: moduleA

$component->error('component');
// → [ERROR]:[MyPlugin/ModuleA/Component]: component
```

Namespace display defaults to `breadcrumbMaxCount: -1` — all segments are shown. Set `breadcrumbMaxCount` to a positive integer to limit how many are displayed (e.g. `2` shows only the first and last segment).

Context placeholders
--------------------

[](#context-placeholders)

`{key}` tokens in the message are replaced with matching values from the `$context` array.

```
$logger->error('User {user.name} failed to log in', ['user' => ['name' => 'Alice']]);
// → [ERROR]:[MyPlugin]: User Alice failed to log in

$logger->debug('Payload: {data}', ['data' => ['id' => 1, 'status' => 'fail']]);
// → [DEBUG]:[MyPlugin]: Payload: {
//       "id": 1,
//       "status": "fail"
//   }

$logger->debug('Response: {res}', ['res' => $someObject]);
// → [DEBUG]:[MyPlugin]: Response: {
//       "prop": "value"
//   }
```

- Valid key characters are `A-Za-z0-9_.` — hyphens, whitespace, or other characters leave the token unreplaced
- No whitespace inside braces: `{ name }` is never interpolated
- Dot notation resolves nested arrays (`user.name` → `$context['user']['name']`)
- A flat key (`'user.name'`) takes precedence over dot-notation traversal when both exist in context
- Scalars (`int`, `float`) are cast to string; `Stringable` objects call `__toString()`; arrays and objects are JSON-encoded
- Unresolved keys (missing from context or no matching resolver) are left as the original `{key}` token
- When using custom `resolvers`, the first matching resolver wins — later ones are not evaluated
- Arrays and objects are JSON-encoded with JSON\_PRETTY\_PRINT by default. Pass a custom jsonResolverFlag per-logger to change the encoding flags

Custom logger implementation
----------------------------

[](#custom-logger-implementation)

Any class implementing `LoggerInterface` can be used as a destination. The simplest approach is to extend `Psr\Log\NullLogger` and override only `log()` — `NullLogger` provides no-op implementations of all the level-specific methods (`debug()`, `info()`, etc.) that forward to `log()`.

```
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Stringable;

class FileLogger extends NullLogger implements LoggerInterface
{
    public function __construct(private string $path) {}

    public function log($level, string|Stringable $message, array $context = []): void
    {
        file_put_contents($this->path, $message . PHP_EOL, FILE_APPEND);
    }
}

$factory = new LoggerFactory(
    namespace: 'MyPlugin',
    loggers: [['logger' => new FileLogger('/tmp/app.log'), 'logLevel' => LogLevel::DEBUG]]
);
```

The two built-in loggers follow the same pattern:

- **`PhpErrorLogger`** — passes the formatted message to `error_log()`.
- **`InMemoryLogger`** — appends each record to a public `$records` array; useful for testing.

LoggerFactory Constructor options
---------------------------------

[](#loggerfactory-constructor-options)

ParameterDefaultDescription`$namespace``'PluginNameSpace'`Root namespace label`$loggers``[['logger' => NullLogger, 'logLevel' => ERROR]]`One or more logger + level pairs`$logLevel``LogLevel::ERROR`Default threshold for all loggersPer-logger options (inside `$loggers` entries)
----------------------------------------------

[](#per-logger-options-inside-loggers-entries)

KeyDescription`logger`Any `LoggerInterface` instance`logLevel`Minimum level for this logger. Available levels (high → low): `emergency`, `alert`, `critical`, `error`, `warning`, `notice`, `info`, `debug``breadcrumbMaxCount`Max namespace segments shown (`-1` = all, default `-1`)`breadcrumbDirection`Which end to trim: `'left'` (default) or `'right'``formatStr``sprintf` format string — receives `LEVEL`, `namespace`, `message``jsonResolverFlag``json_encode` flags for array/object placeholders (default `JSON_PRETTY_PRINT`)`resolvers`Custom `[callable $test, callable $transform][]` pairs for placeholder resolution

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance91

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 90.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

5

Last Release

44d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/f46fe64973c3e89d15c745c0bf601c25983bafea81d30e64d4bf813a6f8c8c7c?d=identicon)[sebastianthulin](/maintainers/sebastianthulin)

---

Top Contributors

[![nRamstedt](https://avatars.githubusercontent.com/u/16800993?v=4)](https://github.com/nRamstedt "nRamstedt (10 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/helsingborg-stad-psr-logger/health.svg)

```
[![Health](https://phpackages.com/badges/helsingborg-stad-psr-logger/health.svg)](https://phpackages.com/packages/helsingborg-stad-psr-logger)
```

###  Alternatives

[sentry/sentry

PHP SDK for Sentry (http://sentry.io)

1.9k247.1M347](/packages/sentry-sentry)[matomo/matomo

Matomo is the leading Free/Libre open analytics platform

21.7k38.9k](/packages/matomo-matomo)[illuminate/log

The Illuminate Log package.

6225.3M657](/packages/illuminate-log)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k17](/packages/tempest-framework)[api-platform/metadata

API Resource-oriented metadata attributes and factories

295.0M223](/packages/api-platform-metadata)[pagemachine/typo3-formlog

Form log for TYPO3

23238.6k8](/packages/pagemachine-typo3-formlog)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
