Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
razonyang committed Aug 21, 2019
0 parents commit 9642d61
Show file tree
Hide file tree
Showing 25 changed files with 498 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# composer
composer.lock
composer.phar
vendor/

# phpunit
.phpunit.result.cache

tests/runtime
14 changes: 14 additions & 0 deletions .scrutinizer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
build:
nodes:
analysis:
tests:
override:
- php-scrutinizer-run

checks:
php: true
tools:
php_code_coverage:
enabled: true
external_code_coverage:
timeout: 600
6 changes: 6 additions & 0 deletions .styleci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
preset: psr2

finder:
exclude:
- docs
- vendor
26 changes: 26 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
language: php

php:
- 7.1
- 7.2
- 7.3

# faster builds on new travis setup not using sudo
sudo: false

# cache vendor dirs
cache:
directories:
- $HOME/.composer/cache

install:
- travis_retry composer self-update && composer --version
- export PATH="$HOME/.composer/vendor/bin:$PATH"
- travis_retry composer install --prefer-dist --no-interaction

script:
- vendor/bin/codecept run --coverage --coverage-xml

after_script:
- wget -c https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover tests/_output/coverage.xml
Empty file added CHANGELOG.md
Empty file.
29 changes: 29 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2019, Razon Yang
All rights reserved.

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

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

2. 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.

3. Neither the name of the copyright holder nor the names of its
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 HOLDER 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.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Yii2 PSR Logger Adapter
=======================

[![Build Status](https://travis-ci.org/razonyang/yii2-psr-log.svg?branch=master)](https://travis-ci.org/razonyang/yii2-psr-log)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/razonyang/yii2-psr-log/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/razonyang/yii2-psr-log/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/razonyang/yii2-psr-log/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/razonyang/yii2-psr-log/?branch=master)
[![Latest Stable Version](https://img.shields.io/packagist/v/razonyang/yii2-psr-log.svg)](https://packagist.org/packages/razonyang/yii2-psr-log)
[![Total Downloads](https://img.shields.io/packagist/dt/razonyang/yii2-psr-log.svg)](https://packagist.org/packages/razonyang/yii2-psr-log)
[![LICENSE](https://img.shields.io/github/license/razonyang/yii2-psr-log)](LICENSE)

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

```
composer require razonyang/yii2-psr-log
```

Usage
-----

```php
$categoryParam = '__CATEGORY__';

$logger = new \RazonYang\Yii2\Psr\Log\Logger($categoryParam);
$logger->error('hello {name}', [$categoryParam => __METHOD__, 'name' => 'foo']);
// equals to
Yii::error('hello foo', __METHOD__);
```
15 changes: 15 additions & 0 deletions codeception.dist.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
actor_suffix: Tester
bootstrap: _bootstrap.php
extensions:
enabled:
- Codeception\Extension\RunFailed
coverage:
enabled: true
include:
- src/*
41 changes: 41 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "razonyang/yii2-psr-log",
"description": "Yii2 PSR Logger Adapter",
"type": "yii2-extension",
"keywords": ["yii2", "psr", "logger"],
"license": "BSD-3-Clause",
"authors": [
{
"name": "Razon Yang",
"email": "razonyang@gmail.com"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": "^7.1",
"psr/log": "^1.1",
"yiisoft/yii2": "~2.0.13"
},
"require-dev": {
"codeception/codeception": "^3.0",
"codeception/verify": "^1.1",
"phpunit/phpunit": "^7"
},
"autoload": {
"psr-4": {
"RazonYang\\Yii2\\Psr\\Log\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"RazonYang\\Yii2\\Psr\\Log\\Tests\\": "tests/"
}
},
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
]
}
84 changes: 84 additions & 0 deletions src/Logger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
namespace RazonYang\Yii2\Psr\Log;

use yii\base\Configurable;
use yii\log\Logger as YiiLogger;
use Psr\Log\AbstractLogger;
use Psr\Log\LogLevel;
use Yii;

class Logger extends AbstractLogger implements Configurable
{
/**
* @var string $categoryParam category param name.
*
* @see log()
*/
private $categoryParam;

/**
* @var array $levelMap an array that mapping from PSR log level to Yii log level.
*/
private $levelMap;

/**
* @var int $defaultLevel default Yii logger level
*
* @see log()
*/
private $defaultLevel;

/**
* @var array $defaultLevelMap default log level map.
*/
protected $defaultLevelMap = [
LogLevel::EMERGENCY => YiiLogger::LEVEL_ERROR,
LogLevel::ALERT => YiiLogger::LEVEL_ERROR,
LogLevel::CRITICAL => YiiLogger::LEVEL_ERROR,
LogLevel::ERROR => YiiLogger::LEVEL_ERROR,
LogLevel::WARNING => YiiLogger::LEVEL_WARNING,
LogLevel::NOTICE => YiiLogger::LEVEL_INFO,
LogLevel::INFO => YiiLogger::LEVEL_INFO,
LogLevel::DEBUG => YiiLogger::LEVEL_TRACE
];

public function __construct(string $categoryParam = '__CATEGORY__', ?array $levelMap = null, $defaultLevel = YiiLogger::LEVEL_INFO)
{
$this->categoryParam = $categoryParam;
$this->levelMap = $levelMap ?? $this->defaultLevelMap;
$this->defaultLevel = $defaultLevel;
}

/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*/
public function log($level, $message, array $context = [])
{
$level = $this->levelMap[$level] ?? $this->defaultLevel;
Yii::getLogger()->log($this->interpolate($message, $context), $level, $context[$this->categoryParam] ?? 'application');
}

/**
* Interpolates context values into the message placeholders.
*
* @param string $message
* @param array $context
*
* @return string
*/
protected function interpolate(string $message, array $context = []): string
{
$replace = [];
foreach ($context as $key => $val) {
if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
$replace['{' . $key . '}'] = $val;
}
}

return strtr($message, $replace);
}
}
87 changes: 87 additions & 0 deletions tests/Unit/LoggerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php
namespace RazonYang\Yii2\Psr\Log\Tests\Unit;

use yii\log\Logger as YiiLogger;
use Codeception\Test\Unit;
use Psr\Log\LogLevel;
use RazonYang\Yii2\Psr\Log\Logger;
use Yii;

class LoggerTest extends Unit
{
/**
* @dataProvider dataLog
*/
public function testLog(
string $level,
string $message,
array $context,
int $expectedLevel,
string $expectedMessage,
string $expectedCategory
): void {
$yiiLogger = Yii::createObject('yii\log\Logger');
Yii::setLogger($yiiLogger);

$logger = new Logger();
$logger->log($level, $message, $context);
$message = Yii::getLogger()->messages[0];
$this->assertSame($expectedMessage, $message[0]);
$this->assertSame($expectedLevel, $message[1]);
$this->assertSame($expectedCategory, $message[2]);
}

public function dataLog(): array
{
return [
[LogLevel::EMERGENCY, 'foo', [], YiiLogger::LEVEL_ERROR, 'foo', 'application'],
[LogLevel::ALERT, 'bar', ['__CATEGORY__' => __METHOD__], YiiLogger::LEVEL_ERROR, 'bar', __METHOD__],
[LogLevel::CRITICAL, 'foo', [], YiiLogger::LEVEL_ERROR, 'foo', 'application'],
[LogLevel::ERROR, 'foo', [], YiiLogger::LEVEL_ERROR, 'foo', 'application'],
[LogLevel::WARNING, 'foo', [], YiiLogger::LEVEL_WARNING, 'foo', 'application'],
[LogLevel::NOTICE, 'foo', [], YiiLogger::LEVEL_INFO, 'foo', 'application'],
[LogLevel::INFO, 'foo', [], YiiLogger::LEVEL_INFO, 'foo', 'application'],
[LogLevel::DEBUG, 'hi {name}', ['name' => 'foo'], YiiLogger::LEVEL_TRACE, 'hi foo', 'application'],
];
}

/**
* @dataProvider dataConstruct
*/
public function testConstruct(int $defaultLevel, string $categoryParam, array $levelMap): void
{
$logger = new Logger($categoryParam, $levelMap, $defaultLevel);
foreach (['categoryParam', 'defaultLevel', 'levelMap'] as $name) {
$property = new \ReflectionProperty(Logger::class, $name);
$property->setAccessible(true);
$this->assertSame($$name, $property->getValue($logger));
}
}

public function dataConstruct(): array
{
return [
[YiiLogger::LEVEL_ERROR, 'foo', []],
[YiiLogger::LEVEL_WARNING, 'bar', [LogLevel::CRITICAL => YiiLogger::LEVEL_ERROR]],
];
}

/**
* @dataProvider dataInterpolate
*/
public function testInterpolate(string $message, array $context, string $expected): void
{
$logger = new Logger();
$method = new \ReflectionMethod(Logger::class, 'interpolate');
$method->setAccessible(true);
$this->assertSame($expected, $method->invoke($logger, $message, $context));
}

public function dataInterpolate(): array
{
return [
['hello world', [], 'hello world'],
['hello {name}', ['name' => 'foo'], 'hello foo'],
];
}
}
1 change: 1 addition & 0 deletions tests/Unit/_bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php
13 changes: 13 additions & 0 deletions tests/_bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

// ensure we get report on all possible php errors
error_reporting(-1);

define('YII_ENABLE_ERROR_HANDLER', false);
define('YII_DEBUG', true);
define('YII_ENV', 'test');

require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');

Yii::setAlias('@RazonYang/Yii2/____', dirname(__DIR__) . '/src');
Empty file added tests/_data/.gitkeep
Empty file.
2 changes: 2 additions & 0 deletions tests/_output/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
26 changes: 26 additions & 0 deletions tests/_support/AcceptanceTester.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php


/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method void pause()
*
* @SuppressWarnings(PHPMD)
*/
class AcceptanceTester extends \Codeception\Actor
{
use _generated\AcceptanceTesterActions;

/**
* Define custom actions here
*/
}
Loading

0 comments on commit 9642d61

Please sign in to comment.