Skip to content

Commit

Permalink
added Logger & MonologExtension & TracyExceptionProcessor
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed May 24, 2016
1 parent ce1af46 commit c66ff8a
Show file tree
Hide file tree
Showing 7 changed files with 306 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/vendor
/composer.lock
30 changes: 30 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "nextras/tracy-monolog-adapter",
"type": "library",
"description": "Nextras Tracy-Monolog Adapter",
"keywords": ["monolog", "nette", "nextras", "logger"],
"homepage": "https://github.com/nextras/tracy-monolog-adapter",
"license": "BSD-3-Clause",
"authors": [
{ "name": "Nextras Project", "homepage": "https://github.com/nextras/tracy-monolog-adapter/graphs/contributors" }
],
"support": {
"issues": "https://github.com/nextras/tracy-monolog-adapter/issues"
},
"require": {
"php": ">=7.0",
"tracy/tracy": "~2.3",
"monolog/monolog": "~1.9"
},
"require-dev": {
"nette/di": "~2.2"
},
"autoload": {
"psr-4": { "Nextras\\TracyMonologAdapter\\": "src/" }
},
"extra": {
"branch-alias": {
"dev-master": "0.1-dev"
}
}
}
34 changes: 34 additions & 0 deletions license.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
New BSD License
---------------

Copyright (c) 2016 Nextras contributors (https://nextras.org)

Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)

All rights reserved.


Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of "Clevis", "Nextras" nor the names of this software contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.

This software is provided by the copyright holders and contributors "as is" and
any express or implied warranties, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose are
disclaimed. In no event shall the copyright owner or contributors be liable for
any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services;
loss of use, data, or profits; or business interruption) however caused and on
any theory of liability, whether in contract, strict liability, or tort
(including negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage.
17 changes: 17 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Nextras Tracy-Monolog Adapter
=============================

[![Downloads this Month](https://img.shields.io/packagist/dm/nextras/tracy-monolog-adapter.svg?style=flat)](https://packagist.org/packages/nextras/tracy-monolog-adapter)
[![Stable version](http://img.shields.io/packagist/v/nextras/tracy-monolog-adapter.svg?style=flat)](https://packagist.org/packages/nextras/tracy-monolog-adapter)

### Installation

Use composer:

```bash
$ composer require nextras/tracy-monolog-adapter
```

### License

New BSD License. See full [license](license.md).
67 changes: 67 additions & 0 deletions src/Bridges/NetteDI/MonologExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

/**
* @license New BSD License
* @link https://github.com/nextras/tracy-monolog-adapter
*/

namespace Nextras\TracyMonologAdapter\Bridges\NetteDI;

use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger as MonologLogger;
use Nette\DI\CompilerExtension;
use Nette\DI\Helpers;
use Nette\DI\Statement;
use Nette\PhpGenerator\ClassType;
use Nextras\TracyMonologAdapter\Logger;
use Nextras\TracyMonologAdapter\Processors\TracyExceptionProcessor;
use Tracy\Debugger;


class MonologExtension extends CompilerExtension
{
public function loadConfiguration()
{
$builder = $this->getContainerBuilder();
$logDir = isset($builder->parameters['logDir']) ? Helpers::expand('%logDir%', $builder->parameters) : Debugger::$logDirectory;

$config = $this->getConfig();

if (isset($config['monolog'])) {
$monologLogger = $config['monolog'];

} else {
$builder->addDefinition($this->prefix('handler'))
->setClass(RotatingFileHandler::class)
->setArguments([$logDir . '/nette.log'])
->setAutowired(false);

$builder->addDefinition($this->prefix('tracyExceptionProcessor'))
->setClass(TracyExceptionProcessor::class)
->setArguments([$logDir, '@Tracy\BlueScreen'])
->setAutowired(false);

$monologLogger = $builder->addDefinition($this->prefix('monologLogger'))
->setClass(MonologLogger::class)
->setArguments(['nette'])
->addSetup('pushHandler', ['@' . $this->prefix('handler')])
->addSetup('pushProcessor', ['@' . $this->prefix('tracyExceptionProcessor')])
->setAutowired(false);

This comment has been minimized.

Copy link
@JanTvrdik

JanTvrdik Aug 4, 2016

Member

sem zapomněl, proč je to autowired = false; má to nějaký důvod?

jsem si zatím případ to configu

# monolog
nextras.monolog.monologLogger:
    autowired: yes

This comment has been minimized.

Copy link
@hrach

hrach Aug 4, 2016

Author Member

je naprosto legitimni mit vice loggeru. toto je jedne pro specialni usecase, ktery cely zarizuje tato extension, tak by nemel zamorovat globalni autowire :-)

This comment has been minimized.

Copy link
@JanTvrdik

JanTvrdik Aug 5, 2016

Member

Legitimní sice ano, ale imho nepotřebné pro drtivou většinu aplikací. Navíc aplikace, co používají více loggerů stejně budou často $config[monolog], takže se tahle část kódu vůbec nespustí.

Teď pokud máš jednoduchou aplikaci a chceš používat tuhle integraci s Monologem a zároveň nechceš v aplikaci logovat přes Tracy\ILogger, ale přes PSR Logger, tak teď musíš vždycky ten autowiring ručně zapnout, ne?

This comment has been minimized.

Copy link
@hrach

hrach Aug 5, 2016

Author Member

Ten Logger ma nastaveny name na nette, tzn. je formalne spatne do nej logovat ne-nette veci, tj. aplikacni logiku.

This comment has been minimized.

Copy link
@hrach

hrach Aug 5, 2016

Author Member

To radej nechcem automaticky vytvorit nejaky dalsi logger.

}

$builder->addDefinition($this->prefix('tracyLogger'))
->setClass(Logger::class)
->setArguments([$monologLogger]);

if ($builder->hasDefinition('tracy.logger')) {
$builder->getDefinition('tracy.logger')->setAutowired(false);
}
}


public function afterCompile(ClassType $class)
{
$initialize = $class->getMethod('initialize');
$initialize->addBody('\Tracy\Debugger::setLogger($this->getByType(\Tracy\ILogger::class));');
}
}
55 changes: 55 additions & 0 deletions src/Logger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

/**
* @license New BSD License
* @link https://github.com/nextras/tracy-monolog-adapter
*/

namespace Nextras\TracyMonologAdapter;

use Monolog;
use Throwable;
use Tracy\Helpers;
use Tracy\ILogger;


class Logger implements ILogger
{
/** @const Tracy priority to Monolog priority mapping */
const PRIORITY_MAP = [
self::DEBUG => Monolog\Logger::DEBUG,
self::INFO => Monolog\Logger::INFO,
self::WARNING => Monolog\Logger::WARNING,
self::ERROR => Monolog\Logger::ERROR,
self::EXCEPTION => Monolog\Logger::CRITICAL,
self::CRITICAL => Monolog\Logger::CRITICAL,
];

/** @var Monolog\Logger */
protected $monolog;


public function __construct(Monolog\Logger $monolog)
{
$this->monolog = $monolog;
}


public function log($message, $priority = self::INFO)
{
$context = [
'at' => Helpers::getSource(),
];

if ($message instanceof Throwable) {
$context['exception'] = $message;
$message = '';
}

$this->monolog->addRecord(
self::PRIORITY_MAP[$priority] ?? Monolog\Logger::ERROR,
$message,
$context
);
}
}
101 changes: 101 additions & 0 deletions src/Processors/TracyExceptionProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

/**
* @license New BSD License
* @link https://github.com/nextras/tracy-monolog-adapter
*/

namespace Nextras\TracyMonologAdapter\Processors;

use Throwable;
use Tracy\BlueScreen;
use Tracy\Helpers;


class TracyExceptionProcessor
{
/** @var string */
private $directory;

/** @var BlueScreen */
private $blueScreen;


public function __construct(string $logDirectory, BlueScreen $blueScreen)
{
$this->directory = $logDirectory;
$this->blueScreen = $blueScreen;
}


public function __invoke(array $record)
{
if (isset($record['context']['exception'])) {
list($justCreated, $exceptionFileName) = $this->logException($record['context']['exception']);
$record['context']['tracy_filename'] = basename($exceptionFileName);
$record['context']['tracy_created'] = $justCreated;
if ($record['message'] === '') {
$record['message'] = self::formatMessage($record['context']['exception']);
}
unset($record['context']['exception']);
}
return $record;
}


/**
* @author David Grudl
* @see https://github.com/nette/tracy
*/
protected function logException(Throwable $exception): array
{
$file = $this->getExceptionFile($exception);
if ($handle = @fopen($file, 'x')) { // @ file may already exist
ob_start(); // double buffer prevents sending HTTP headers in some PHP
ob_start(function ($buffer) use ($handle) { fwrite($handle, $buffer); }, 4096);
$this->blueScreen->render($exception);
ob_end_flush();
ob_end_clean();
fclose($handle);
return [true, $file];
} else {
return [false, $file];
}
}


/**
* @author David Grudl
* @see https://github.com/nette/tracy
*/
private function getExceptionFile(Throwable $exception): string
{
$dir = strtr($this->directory . '/', '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
$hash = substr(md5(preg_replace('~(Resource id #)\d+~', '$1', $exception)), 0, 10);
foreach (new \DirectoryIterator($this->directory) as $file) {
if (strpos($file, $hash)) {
return $dir . $file;
}
}
return $dir . 'exception--' . @date('Y-m-d--H-i') . "--$hash.html"; // @ timezone may not be set
}


/**
* @author David Grudl
* @see https://github.com/nette/tracy
*/
protected static function formatMessage(Throwable $message): string
{
$tmp = [];
while ($message) {
$tmp[] = ($message instanceof \ErrorException
? Helpers::errorTypeToString($message->getSeverity()) . ': ' . $message->getMessage()
: Helpers::getClass($message) . ': ' . $message->getMessage()
) . ' in ' . $message->getFile() . ':' . $message->getLine();
$message = $message->getPrevious();
}
$message = implode($tmp, "\ncaused by ");

This comment has been minimized.

Copy link
@Mikulas

Mikulas Jul 13, 2016

Není tohle špatně? https://php.net/implode

This comment has been minimized.

Copy link
@Mikulas

Mikulas Jul 13, 2016

Aha, bere to oboje, ale teď to používá deprecated variantu… Nvm

This comment has been minimized.

Copy link
@JanTvrdik

JanTvrdik Jul 14, 2016

Member

jj, je to určitě blbě a náhodou to v PHP projde =)
mělo by se to fixnout i v Nette https://github.com/nette/tracy/blob/af97a2f1cf50aa461d1bdaafa13d2d4795cea0e2/src/Tracy/Logger.php#L94

return trim($message);
}
}

0 comments on commit c66ff8a

Please sign in to comment.