PHPackages                             timdev/timdev-log - 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. timdev/timdev-log

ActiveLibrary

timdev/timdev-log
=================

(Very) opinionated structured logging for PHP. Probably not for you.

0.1.2(4y ago)051MITPHPPHP ^8.0

Since Sep 26Pushed 4y ago1 watchersCompare

[ Source](https://github.com/timdev/timdev-log)[ Packagist](https://packagist.org/packages/timdev/timdev-log)[ RSS](/packages/timdev-timdev-log/feed)WikiDiscussions main Synced 1w ago

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

timdev/log
==========

[](#timdevlog)

> (Very) Opinionated, structured, logging for PHP. Probably not for you.

- Build on top of [monolog](https://github.com/Seldaek/monolog) and [timdev/stack-logger](https://git.timdev.com/tim/php-stack-logger).
- Logs are structured as [ndjson](http://ndjson.org/)

Goals
-----

[](#goals)

This package represents my (admittedly evolving) approach to logging for PHP applications. It composes [timdev/stack-logger](https://github.com/timdev/php-stack-logger/) with [monolog](https://github.com/Seldaek/monolog) to produce a distinct flavor of [ndjson](http://ndjson.org/) logs.

The main goal is to reduce the number of things I need to decide or remember when setting up logging in PHP application. Therefore, configuration knobs are intentionally minimized.

The Logger
----------

[](#the-logger)

The logger extends timdev/stack-logger's MonologStackLogger, providing a static factory with only three scalar arguments (only one of which is required). It also provides a couple of convenience methods to help log application events and exceptions. And that's it.

Included Middleware
-------------------

[](#included-middleware)

StackLogger opens up some nice possibilities. Particularly in middleware-based web applications, it can be nice to add some persistent context to the logger instance early in the request, so it's included in all subsequent logging calls.

This library includes several StackLogger-aware PSR-15-compatible middleware that I've used in web app projects.

### TimDev\\Log\\Middleware\\LogRequestAttributes

[](#timdevlogmiddlewarelogrequestattributes)

Extracts request attributes from the PSR7 ServerRequest and adds them as context to the logger.

Example:

```
use Psr\Http\Message\ServerRequestInterface as SRI;
use TimDev\Log\Middleware\LogRequestAttributes;

$middleware = new LogRequestAttributes(
    // A StackLogger instance
    $logger,
    // map of context-key => request-attribute name | callable
    [
        // Extract 'user_id' attribute from request, and set the 'uid'
        // context value on the logger.
        'uid' => 'user_id',

        // The above is a shortcut for:
        'uid2' => fn(SRI $req) => $req->getAttribute('user_id'),

        // If you want other data from the request, you can use the same pattern
        // to get it. For example:
        'ref' => fn(SRI $req) => $req->getHeader('Referer')[0] ?? null
    ];
);
```

The middleware will not set context keys for `null` values.

For more example usage, see the [tests](tests/Middleware/LogRequestAttributesTest.php)

### TimDev\\Log\\Middleware\\DevelopmentRedirect

[](#timdevlogmiddlewaredevelopmentredirect)

This middleware strips the `Location` header from redirect-responses and replaces the body with basic HTML document that includes a meta-refresh tag.

This is handy if you're using something like Monolog's BrowserConsoleHandler that relies on emitting javascript for the browser to execute in order to push log messages to the browser's console.

Example:

```
use Psr\Http\Message\ServerRequestInterface as SRI;
use TimDev\Log\Middleware\DevelopmentRedirect;

// Seconds to delay before refreshing. Default is zero.
$delaySeconds = 2;
$middleware = new DevelopmentRedirect($delaySeconds);
```

This middleware should usually be added *early* in your pipeline, since it only touches the response, and you want the response-mutation to happen last or nearly-last. In my projects, I typically do something like this:

```
// ErrorHandler is the outermost middleware.
$app->pipe(ErrorHandler::class);
// If we're adding it, the DR middlware is the second outer-most.
if (getenv('APP_ENV') === 'development'){
    $app->pipe(new DevelopmentRedirect(1));
}
// ... all the rest of my middlewares.
```

Framework Integration
---------------------

[](#framework-integration)

### Mezzio

[](#mezzio)

To date, I've been using this setup with [Mezzio](https://github.com/mezzio/mezzio)-based applications.

This package provides a [ConfigProvider](src/ConfigProvider.php) and a [LoggerFactory](src/DI/LoggerFactory.php).

To set this logger up in your mezzio project, just add the ConfigProvider in your config, and you'll have a logger in your container:

```
$logger = $container->get(\TimDev\Log\Logger::class);

// It's a PSR3 logger!
$logger->info('I can do PSR3 things ...');

// It's a StackLogger!
$childLogger = $logger->withContext(['some' => 'context']);
$childLogger->debug('foo');

// You can throw exceptions at it!
$ex = new \LogicException('Ya dun goofed!');
$logger->exception($ex);

// etc
```

You can configure the logger in any of your `config/autoload/*.php` files as appropriate. A full configuration might look like:

**config/autoload/timdev\_log.local.php**

```
return [
    'timdev' => [
        'log' => [
            'name'    => 'my-app',              // default: 'app'
            'logfile' => 'data/logs/app.log'    // default: 'php://stdout'
            'enable_browser_console' => true,   // default: false
            'dev_redir_delay_seconds' => 2      // default: 0
        ]
    ]
];
```

###  Health Score

23

—

LowBetter than 27% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity8

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity47

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 ~0 days

Total

3

Last Release

1695d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4eb475c7f4d3d1df5053f83417bf4e756a35b59d1686cd7d379055da2828017f?d=identicon)[timdev](/maintainers/timdev)

---

Top Contributors

[![timdev](https://avatars.githubusercontent.com/u/513999?v=4)](https://github.com/timdev "timdev (18 commits)")

### Embed Badge

![Health badge](/badges/timdev-timdev-log/health.svg)

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

###  Alternatives

[laravel/framework

The Laravel Framework.

34.7k509.9M17.0k](/packages/laravel-framework)[cakephp/cakephp

The CakePHP framework

8.8k18.5M1.6k](/packages/cakephp-cakephp)[contao/core-bundle

Contao Open Source CMS

1231.6M2.4k](/packages/contao-core-bundle)[rareloop/lumberjack-core

A powerful MVC framework for the modern WordPress developer. Write better, more expressive and easier to maintain code

42155.0k19](/packages/rareloop-lumberjack-core)[neos/flow

Flow Application Framework

862.0M451](/packages/neos-flow)[neos/flow-development-collection

Flow packages in a joined repository for pull requests.

144179.3k3](/packages/neos-flow-development-collection)

PHPackages © 2026

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