PHPackages                             mensbeam/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. mensbeam/logger

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

mensbeam/logger
===============

A simple yet configurable logger

v1.3.2(2w ago)095↓100%MITPHPPHP &gt;=8.1

Since Apr 8Pushed 2w ago2 watchersCompare

[ Source](https://github.com/mensbeam/Logger)[ Packagist](https://packagist.org/packages/mensbeam/logger)[ RSS](/packages/mensbeam-logger/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (4)Versions (8)Used By (0)

Logger
======

[](#logger)

*Logger* is a simple yet configurable logger for PHP. It is an opinionated implementation of [PSR-3 Logger Interface](https://www.php-fig.org/psr/psr-3/). It uses classes called *handlers* to handle messages to log. Currently there is only one handler: `StreamHandler` which allows for logging to files or to streams such as `php://stdout` or `php://stderr`. Handlers can be easily written and plugged into Logger.

Opinionated?
------------

[](#opinionated)

This library attempts what we're calling an "opinionated" implementation of PSR-3. This is because while it successfully implements `Psr\Log\LoggerInterface` *Logger* deviates from the true spirit of the specification in various ways:

1. In [section 1.1](https://www.php-fig.org/psr/psr-3/#11-basics) PSR-3 states that when calling the `log` method with one of the log level constants (later shown to be in `Psr\Log\LogLevel`) it must have the same result as calling the level-specific methods. The log level constants in `Psr\Log\LogLevel` are strings, but the `$level` parameter of the `log` method in `Psr\Log\LoggerInterface` is typeless. The words of the specification suggest that the `$level` parameter should be a string, but the actual code implementors are to use doesn't specify a type. The same section also references [RFC 5424](http://tools.ietf.org/html/rfc5424) when mentioning the log level methods, but why use strings when there are standardized integers used to identify severity? Since the interface allows for any type for `$level`, *Logger* will prefer the actual RFC standard's integers but will accept and convert PSR-3's strings internally to the integers just so it can remain PSR-3 compatible.
2. In [section 1.2](https://www.php-fig.org/psr/psr-3/#12-message) of the specification it describes an optional feature, placeholders, and requires the implementor to write code to parse out and replace placeholders using a syntax and a method that's not present anywhere else in the entirety of PHP. *Logger* won't support this feature because a logging library's place is to log messages and not to interpolate template strings. A separate library or a built-in function such as `sprintf` should be used instead. *Logger* provides a way to transform messages that can be used to hook in a preferred interpolation method if desired, though.
3. The specification in [section 1.3](https://www.php-fig.org/psr/psr-3/#13-context) also specifies that if an `Exception` object is passed in the `$context` parameter it must be within an `exception` key. This makes sense, but curiously there's nary a mention of what to do with an `Error` object. They've existed since PHP 7 and can be thrown just like exceptions. *Logger* will accept any `Throwable` in the `exception` key, but at present does nothing with it. Theoretically future handlers could be written to take advantage of it for structured data.
4. Also in the first item of [section 1.3](https://www.php-fig.org/psr/psr-3/#13-context) it states categorically that implementors must not trigger a warning when errant data is in the `$context` array and treat it with *"as much lenience as possible"*. It then states in the following item that if an exception is present in the context data it *must* be in the `exception` key and that implementors *must* verify the `exception` key. This is contradictory. You can't verify the `exception` key without triggering an error or exception when it's wrong. The user should be notified they've made a mistake; it's bad design otherwise. Our solution to this problem is to remove errant throwables from `$context` and also trigger warnings when they're encountered. However, `Logger->$warnOnInvalidContextThrowables` is provided to make it easy to suppress the warnings if necessary.

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

[](#requirements)

- PHP &gt;= 8.1
- [mensbeam/filesystem](https://code.mensbeam.com/MensBeam/Filesystem) &gt;= 1.0
    - ext-ctype or [symfony/polyfill-ctype](https://github.com/symfony/polyfill/tree/main/src/Ctype) &gt;= 1.8
    - ext-mbstring or [symfony/polyfill-mbstring](https://github.com/symfony/polyfill/tree/main/src/Mbstring) &gt;= 1.8
- [psr/log](https://github.com/php-fig/log) ^3.0

### Note

[](#note)

This library uses [mensbeam/filesystem](https://code.mensbeam.com/MensBeam/Filesystem) which provides polyfills for `ext-ctype` and `ext-mbstring`. If you have these extensions installed the polyfills won't be used. However, they are still installed. If you don't want the polyfills needlessly installed you can add this to your project's `composer.json`:

```
{
    "require": {
        "ext-ctype": "*",
        "ext-mbstring": "*"
    },
    "provide": {
        "symfony/polyfill-ctype": "*",
        "symfony/polyfill-mbstring": "*"
    }
}
```

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

[](#installation)

```
composer require mensbeam/logger
```

Usage
-----

[](#usage)

This library works without any configuration, but it might not be quite how you think it would work by default:

```
use MensBeam\Logger;

$logger = new Logger();
```

This will create a logger that outputs all debug, info, notice, and warning entries to `STDOUT` while any error, critical, alert, and emergency entries are output to `STDERR`. This seems like it would be a bizarre default since it causes duplicate output to the shell on errors. However, if you accompany it with an error handler like [`Catcher`](https://code.mensbeam.com/MensBeam/Catcher) it suddenly makes sense:

```
use MensBeam\{
    Catcher,
    Logger
};
use MensBeam\Catcher\PlainTextHandler;

$catcher = new Catcher(new PlainTextHandler([
    'logger' => new Logger('log'),
    'silent' => true
]));
```

Now, *Logger* will take care of the printing. But, *Logger* can do far more.

Documentation
-------------

[](#documentation)

### MensBeam\\Logger

[](#mensbeamlogger)

```
namespace MensBeam;
use MensBeam\Logger\{
    Handler,
    Level
};

class Logger implements Psr\Log\LoggerInterface {
    public bool $warnOnInvalidContextThrowables = true;

    public function __construct(?string $channel = null, Handler ...$handlers);

    public function getChannel(): ?string;
    public function getHandlers(): array;
    public function popHandler(): Handler;
    public function pushHandler(Handler ...$handlers): void;
    public function setChannel(?string $value): void;
    public function setHandlers(Handler ...$handlers): void;
    public function shiftHandler(): Handler;
    public function unshiftHandler(Handler ...$handlers): void;

    public function emergency(string|\Stringable $message, array $context = []): void;
    public function alert(string|\Stringable $message, array $context = []): void;
    public function critical(string|\Stringable $message, array $context = []): void;
    public function error(string|\Stringable $message, array $context = []): void;
    public function warning(string|\Stringable $message, array $context = []): void;
    public function notice(string|\Stringable $message, array $context = []): void;
    public function info(string|\Stringable $message, array $context = []): void;
    public function debug(string|\Stringable $message, array $context = []): void;
    public function log(int|string|Level $level, string|\Stringable $message, array $context = []): void;
}
```

#### Properties

[](#properties)

*warnOnInvalidContextThrowables*: When set to true Logger will trigger warnings when invalid `Throwable`s are in the `$context` array in the logging methods.

#### MensBeam\\Logger::getChannel

[](#mensbeamloggergetchannel)

Returns the channel name for the instance of *Logger*.

#### MensBeam\\Logger::getHandlers

[](#mensbeamloggergethandlers)

Returns an array of the handlers defined for use in the *Logger* instance.

#### MensBeam\\Logger::popHandler

[](#mensbeamloggerpophandler)

Pops the last handler off the stack and returns it

#### MensBeam\\Logger::pushHandler

[](#mensbeamloggerpushhandler)

Pushes the specified handler(s) onto the stack

#### MensBeam\\Logger::setChannel

[](#mensbeamloggersetchannel)

Sets the channel to the specified string

#### MensBeam\\Logger::setHandlers

[](#mensbeamloggersethandlers)

Replaces the stack of handlers with those specified as parameters

#### MensBeam\\Logger::shiftHandler

[](#mensbeamloggershifthandler)

Shifts the first handler off the stack of handlers and returns it

#### MensBeam\\Logger::unshiftHandler

[](#mensbeamloggerunshifthandler)

Unshifts the specified handler(s) onto the beginning of the stack

#### MensBeam\\Logger::emergency

[](#mensbeamloggeremergency)

Adds an emergency entry to the log

#### MensBeam\\Logger::alert

[](#mensbeamloggeralert)

Adds an alert entry to the log

#### MensBeam\\Logger::critical

[](#mensbeamloggercritical)

Adds a critical entry to the log

#### MensBeam\\Logger::error

[](#mensbeamloggererror)

Adds an error entry to the log

#### MensBeam\\Logger::warning

[](#mensbeamloggerwarning)

Adds a warning entry to the log

#### MensBeam\\Logger::notice

[](#mensbeamloggernotice)

Adds a notice entry to the log

#### MensBeam\\Logger::info

[](#mensbeamloggerinfo)

Adds an info entry to the log

#### MensBeam\\Logger::debug

[](#mensbeamloggerdebug)

Adds a debug entry to the log

#### MensBeam\\Logger::log

[](#mensbeamloggerlog)

Adds an entry to the log in the specified level

### MensBeam\\Logger\\Level

[](#mensbeamloggerlevel)

This is an enum of the RFC 5424 integer values for each of the log levels; also provides methods for converting to and from PSR-3 string values.

```
namespace MensBeam;

enum Level: int {
    case Emergency = 0;
    case Alert = 1;
    case Critical = 2;
    case Error = 3;
    case Warning = 4;
    case Notice = 5;
    case Info = 6;
    case Debug = 7;

    public static function fromPSR3(string $level): self;
    public function toPSR3(): string;
}
```

#### MensBeam\\Logger\\Level::fromPSR3

[](#mensbeamloggerlevelfrompsr3)

Takes a provided PSR-3 string level and returns a `Level` enum.

#### MensBeam\\Logger\\Level::toPSR3

[](#mensbeamloggerleveltopsr3)

Returns a PSR-3 string level representation of the enum.

### MensBeam\\Logger\\Handler

[](#mensbeamloggerhandler)

Handlers inherit from this abstract class. Since it is an abstract class meant for constructing handlers protected methods and properties will be documented here as well.

```
namespace MensBeam\Logger;

abstract class Handler {
    protected array $levels;

    protected bool $_bubbles = true;
    protected bool $_enabled = true;
    protected callable $_messageTransform = null;
    protected string $_timeFormat = 'M d H:i:s';

    public function __construct(array $levels = [ 0, 1, 2, 3, 4, 5, 6, 7 ], array $options = []);

    public function getLevels();
    public function getOption(string $name): mixed;
    public function setLevels(int ...$levels): void;
    public function setOption(string $name, mixed $value): void;
    public function __invoke(int $level, ?string $channel, string $message, array $context = []): void;

    abstract protected function invokeCallback(string $time, int $level, string $channel, string $message, array $context = []): void;
}
```

#### Properties (Protected)

[](#properties-protected)

*levels*: This is where the levels the handler is configured to support are stored

#### Options

[](#options)

Properties which begin with an underscore are all options. They can be set either through the constructor or via `setHandler` by name, removing the underscore (\_) at the beginning. All handlers inherit these options. Options in inherited classes should also begin with an underscore (\_).

*bubbles*: When set to true the stack loop will continue onto the next handler; if false it won't. Defaults to *true*
*enabled*: When set to true the handler will run; if false it won't. Defaults to *true*
*messageTransform*: A callable to use to transform messages before outputting. Defaults to *null*
*timeFormat*: The PHP-standard date format which to use for times in output. Defaults to *"M d H:i:s"*

##### Message Transform

[](#message-transform)

The *messageTransform* option allows for manipulation of log messages. It accepts any callable with the following structure:

```
function (string $message, array $context): string;
```

One common use of this feature would be to do string interpolation which isn't handled by the library. By providing a message transform it's possible to use any preferred method of interpolation:

```
$handler = new StreamHandler(options: [
    'messageTransform' => function (string $message, array $context): string {
        return vsprintf($message, $context);
    }
]);
```

Of course this is a simplistic example. One would want to convert the `$context` array to numerical keys (or just use numerical keys) before usage in `vsprintf`, but as can be seen it's very possible.

#### MensBeam\\Logger\\Handler::getLevels

[](#mensbeamloggerhandlergetlevels)

Returns the levels the handler is configured to support

#### MensBeam\\Logger\\Handler::getOption

[](#mensbeamloggerhandlergetoption)

Returns the value of the provided option name

#### MensBeam\\Logger\\Handler::setLevels

[](#mensbeamloggerhandlersetlevels)

Sets the levels the handler will then support

#### MensBeam\\Logger\\Handler::setOption

[](#mensbeamloggerhandlersetoption)

Sets the provided option with the provided value

#### MensBeam\\Logger\\Handler::\_\_invoke

[](#mensbeamloggerhandler__invoke)

Outputs/dispatches the log entry

#### MensBeam\\Logger\\Handler::invokeCallback (protected)

[](#mensbeamloggerhandlerinvokecallback-protected)

A callback method meant to be extended by inherited classes to output/dispatch the log entry

### MensBeam\\Logger\\StreamHandler

[](#mensbeamloggerstreamhandler)

```
namespace MensBeam\Logger;

class StreamHandler extends Handler {
    public function __construct(resource|string $stream = 'php://stdout', array $levels = [ 0, 1, 2, 3, 4, 5, 6, 7 ], array $options = []);

    public function getStream(): ?resource;
    public function getURI(): ?string;
    public function setStream(resource|string $value): void;
}
```

#### Options

[](#options-1)

*entryTransform*: A callable where the log entry can be manipulated. Defaults to *null*

##### Entry Transform

[](#entry-transform)

```
function (string $time, int $level, string $levelName, string $channel, string $message, array $context): string;
```

###### Parameters

[](#parameters)

 time The timestamp the log entry was dispatched at; can be altered with the *timeFormat* option level The RFC 5424 level integer for the entry levelName The RFC 5424 level name for the entry channel The channel defined when creating the logger message The message string; can be manipulated with the *messageTransform* option context The context array used when dispatching the entryHere is an example of how to use the *entryTransform* option to output entries to `php://stdout` as [JSONLines](https://jsonlines.org)/[NDJSON](https://ndjson.org)/whatever (ugh):

```
use MensBeam\Logger,
    MensBeam\Logger\StreamHandler;

$handler = new StreamHandler(options: [
    'entryTransform' => function (string $time, int $level, string $levelName, string $channel, string $message, array $context): string {
        $entry = [
            'time' => $time,
            'level' => $level,
            'levelName' => $levelName,
            'channel' => $channel,
            'message' => $message
        ];

        return json_encode($entry, \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE);
    }
]);

$logger = new Logger('ook', $handler);
$logger->info("ook\neek");
// {"time":"Feb 03 22:45:17","level":6,"levelName":"Info","channel":"ook","message":"ook\neek"}
```

#### MensBeam\\Logger\\StreamHandler::getStream

[](#mensbeamloggerstreamhandlergetstream)

Returns the resource where the handler will output to

#### MensBeam\\Logger\\StreamHandler::getURI

[](#mensbeamloggerstreamhandlergeturi)

Returns the URI where the handler will output to

#### MensBeam\\Logger\\StreamHandler::setStream

[](#mensbeamloggerstreamhandlersetstream)

Sets where the handler will output to

###  Health Score

46

—

FairBetter than 93% of packages

Maintenance97

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~177 days

Recently: every ~196 days

Total

7

Last Release

14d ago

### Community

Maintainers

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

---

Top Contributors

[![dustinwilson](https://avatars.githubusercontent.com/u/1885928?v=4)](https://github.com/dustinwilson "dustinwilson (25 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/mensbeam-logger/health.svg)

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

###  Alternatives

[bref/logger

All you need to log with Bref on AWS Lambda

341.4M5](/packages/bref-logger)[illuminated/console-logger

Logging and Notifications for Laravel Console Commands.

8674.5k](/packages/illuminated-console-logger)

PHPackages © 2026

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