Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 162 additions & 72 deletions .docs/README.md
Original file line number Diff line number Diff line change
@@ -1,145 +1,235 @@
# Contributte Monolog

[Monolog](https://github.com/Seldaek/monolog/) integration into [Nette/DI](https://github.com/nette/di)

See also [Monolog documentation](https://github.com/Seldaek/monolog#documentation), this is only an integration.
Integration of [Monolog](https://github.com/Seldaek/monolog/) for Nette Framework.

## Content

- [Setup](#setup)
- [Installation](#installation)
- [Configuration](#configuration)
- [Tracy](#tracy)
- [Logging](#logging)
- [Logger manager](#loggermanager)
- [Logger holder](#loggerholder)
- [Channels](#channels)
- [Handlers](#handlers)
- [Processors](#processors)
- [Tracy](#tracy)
- [Usage](#usage)
- [Logging](#logging)
- [LoggerManager](#loggermanager)
- [LoggerHolder](#loggerholder)
- [Examples](#examples)

## Setup
## Installation

Install package
Install package using composer.

```bash
composer require contributte/monolog
```

Register extension
Register prepared [compiler extension](https://doc.nette.org/en/dependency-injection/nette-container) in your `config.neon` file.

```neon
extensions:
monolog: Contributte\Monolog\DI\MonologExtension
monolog: Contributte\Monolog\DI\MonologExtension
```

> [!NOTE]
> This is just a Nette integration, see also [Monolog documentation](https://github.com/Seldaek/monolog#documentation) for more information about handlers, processors and formatters.

## Configuration

### Channels

You can configure multiple logging channels. The `default` channel is required and is the only one that is autowired.

```neon
monolog:
channel:
default:
handlers:
- Monolog\Handler\StreamHandler(%appDir%/../log/app.log)
api:
handlers:
- Monolog\Handler\StreamHandler(%appDir%/../log/api.log)
```

### Handlers

Handlers are responsible for writing log records to various destinations. You can use any [Monolog handler](https://github.com/Seldaek/monolog/blob/main/doc/02-handlers-formatters-processors.md#handlers).

```neon
monolog:
channel:
default: # default channel is required
handlers:
- Monolog\Handler\RotatingFileHandler(%appDir%/../log/syslog.log, 30, Monolog\Logger::WARNING)
# you can use same configuration as in services section (with setup, type, arguments, etc.)
-
type: Monolog\Handler\RotatingFileHandler
arguments:
- %appDir%/../log/syslog.log
- 30
- Monolog\Logger::WARNING
- @serviceName # or reference an existing service
processors:
- Monolog\Processor\MemoryPeakUsageProcessor()
channel:
default:
handlers:
# Inline handler definition
- Monolog\Handler\StreamHandler(%appDir%/../log/app.log, Monolog\Logger::WARNING)
- Monolog\Handler\RotatingFileHandler(%appDir%/../log/app.log, 30, Monolog\Logger::DEBUG)
# Reference to existing service
- @myCustomHandler
```

### Processors

Processors allow you to add extra data to log records.

```neon
monolog:
channel:
default:
handlers:
- Monolog\Handler\StreamHandler(%appDir%/../log/app.log)
processors:
- Monolog\Processor\MemoryPeakUsageProcessor()
- Monolog\Processor\WebProcessor()
- Monolog\Processor\IntrospectionProcessor()
```

### Tracy

Monolog integrates with Tracy debugger. By default, logs are bridged in both directions.

```neon
monolog:
hook:
fromTracy: true # enabled by default, log through Tracy into Monolog
toTracy: true # enabled by default, log through Monolog into Tracy
hook:
fromTracy: true # enabled by default, log Tracy messages to Monolog
toTracy: true # enabled by default, log Monolog messages to Tracy
```

You may also want configure remote storage for Tracy bluescreens. In this case use [mangoweb-backend/monolog-tracy-handler](https://github.com/mangoweb-backend/monolog-tracy-handler)
> [!TIP]
> For remote storage of Tracy bluescreens, consider using [mangoweb-backend/monolog-tracy-handler](https://github.com/mangoweb-backend/monolog-tracy-handler).

## Usage

## Logging
### Logging

Log message with injected logger (only `default` is autowired)
Inject the logger using constructor injection or `inject*` method. Only the `default` channel is autowired.

```php
use Psr\Log\LoggerInterface;

class ExampleService
class OrderService
{

/** @var LoggerInterface **/
private $logger;
public function __construct(
private LoggerInterface $logger,
)
{
}

public function injectLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}

public function doSomething(): void
{
$this->logger->info('Log that application did something');
}
public function process(): void
{
$this->logger->info('Processing order');
$this->logger->error('Order failed', ['orderId' => 123]);
}

}
```

## LoggerManager
### LoggerManager

You could also use logger manager in case you need to use multiple logger at once.
Use LoggerManager when you need to access multiple channels.

```neon
monolog:
manager:
enabled: false # disabled by default
manager:
enabled: true # disabled by default
```

```php
use Contributte\Monolog\LoggerManager;

class ExampleService
class ReportService
{

/** @var LoggerManager **/
private $loggerManager;

public function injectLoggerManager(LoggerManager $loggerManager): void
{
$this->loggerManager = $loggerManager;
}
public function __construct(
private LoggerManager $loggerManager,
)
{
}

public function doSomething(): void
{
$this->loggerManager->get('default')->info('Log that application did something');
$this->loggerManager->get('specialLogger')->info('Log something very special');
}
public function generate(): void
{
$this->loggerManager->get('default')->info('Generating report');
$this->loggerManager->get('api')->info('Fetching data from API');
}

}
```

## LoggerHolder

Allow you get default logger statically in case that DIC is not available.
### LoggerHolder

It add into message info about which class (or file) called LoggerHolder for easier debugging.
LoggerHolder provides static access to the default logger when DI container is not available.

```neon
monolog:
holder:
enabled: false # disabled by default
holder:
enabled: true # disabled by default
```

```php
use Contributte\Monolog\LoggerHolder;

class VerySpecialClassWithoutDependencyInjectionContainerAvailable
class LegacyCode
{

public function doSomething(): void
{
LoggerHolder::getInstance()->getLogger()->info('Log that application did something');
}
public function process(): void
{
LoggerHolder::getInstance()->getLogger()->info('Processing');
}

}
```

> [!WARNING]
> LoggerHolder should only be used in legacy code or situations where dependency injection is not possible.

## Examples

### Full configuration

```neon
monolog:
channel:
default:
handlers:
- Monolog\Handler\RotatingFileHandler(%appDir%/../log/app.log, 14, Monolog\Logger::DEBUG)
- Monolog\Handler\StreamHandler(php://stderr, Monolog\Logger::ERROR)
processors:
- Monolog\Processor\MemoryPeakUsageProcessor()
- Monolog\Processor\WebProcessor()

email:
handlers:
- Monolog\Handler\StreamHandler(%appDir%/../log/email.log)

hook:
fromTracy: true
toTracy: true

manager:
enabled: true

holder:
enabled: false
```

### Custom handler service

```neon
services:
slackHandler:
factory: Monolog\Handler\SlackWebhookHandler(
%slack.webhookUrl%,
%slack.channel%,
%slack.username%
)

monolog:
channel:
default:
handlers:
- Monolog\Handler\StreamHandler(%appDir%/../log/app.log)
- @slackHandler
```

> [!TIP]
> Take a look at real **Contributte Monolog** configuration example at [contributte/webapp-skeleton](https://github.com/contributte/webapp-skeleton).
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
],
"require": {
"php": ">=8.2",
"contributte/di": "^0.5.3",
"monolog/monolog": "^2.0.0 || ^3.0.0",
"nette/di": "^3.2",
"nette/utils": "^3.0.0 || ^4.0.0"
},
"require-dev": {
"contributte/phpstan": "^0.1.0",
"contributte/qa": "^0.4.0",
"contributte/tester": "^0.2.0",
"contributte/tester": "^0.4.0",
"tracy/tracy": "^2.9.4"
},
"autoload": {
Expand Down
28 changes: 28 additions & 0 deletions src/DI/Helpers/SmartStatement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php declare(strict_types = 1);

namespace Contributte\Monolog\DI\Helpers;

use Contributte\Monolog\Exception\Logic\InvalidArgumentException;
use Nette\DI\Definitions\Statement;

final class SmartStatement
{

public static function from(mixed $service): Statement|string
{
if (is_string($service) && str_starts_with($service, '@')) {
return $service;
}

if (is_string($service)) {
return new Statement($service);
}

if ($service instanceof Statement) {
return $service;
}

throw new InvalidArgumentException('Unsupported type of service');
}

}
Loading