Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dcarbone committed Feb 9, 2017
1 parent 03ed679 commit 81b46da
Show file tree
Hide file tree
Showing 9 changed files with 517 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/.idea
/*.iml
/vendor
/composer.lock
57 changes: 57 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,59 @@
# default-psr-logger
A simple PSR-3 compliant logger

## Installation

This library is designed to be used with [Composer](https://getcomposer.org)

Require entry:

```json
{
"myena/default-psr-logger": "@stable"
}
```

## Basic Usage

```php
$logger = new \MyENA\DefaultLogger();

$logger->debug('hello!');
```

## Defaults

The default level of this logger is `debug`

The default stream for this logger is `php://output`

## Custom Levels

You may specify custom levels one of two ways:

**Construction**:
```php
$logger = new \MyENA\DefaultLogger(\Psr\Log\LogLevel::INFO);
```

**Post-Construction**:
```php
$logger->setLogLevel(\Psr\Log\LogLevel::INFO);
```

If you attempt to specify a level not denoted by
[\Psr\Log\LogLevel](https://github.com/php-fig/log/blob/1.0.2/Psr/Log/LogLevel.php), an exception will be thrown.

## Custom Stream

If you wish for the log output to go to a file or some other resource writeable by the
[fwrite](http://php.net/manual/en/function.fwrite.php) function, you may pass it in as the 2nd argument.

```php
$logger = new \MyENA\DefaultLogger(\Psr\Log\LogLevel::DEBUG, fopen('tmp/test.log', 'ab'));
```

If this file becomes un-writeable for some reason, it will attempt to reconstruct the internal resource. If it is
unable, it will revert to using the stream returned by the [defaultStream()](./src/DefaultLogger.php#L133).

**NOTE**: No write-ability determination is done, if you pass in a read-only stream it will ultimately not work.
26 changes: 26 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "myena/default-logger",
"type": "library",
"description": "A simple PSR-3 compliant logger",
"license": "MPLv2.0",
"authors": [
{
"name": "Daniel Carbone",
"email": "dcarbone@ena.com"
}
],

"autoload": {
"psr-4": {
"MyENA\\": "src/"
}
},

"require": {
"psr/log": "1.*"
},

"require-dev": {
"phpunit/phpunit": "5.7.*"
}
}
47 changes: 47 additions & 0 deletions phpunit.local.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd"
bootstrap="./vendor/autoload.php"
backupGlobals="true"
backupStaticAttributes="false"
cacheTokens="false"
colors="false"
convertErrorsToExceptions="false"
convertNoticesToExceptions="false"
convertWarningsToExceptions="false"
forceCoversAnnotation="false"
mapTestClassNameToCoveredClassName="false"
printerClass="PHPUnit_TextUI_ResultPrinter"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
testSuiteLoaderClass="PHPUnit_Runner_StandardTestSuiteLoader"
timeoutForSmallTests="1"
timeoutForMediumTests="10"
timeoutForLargeTests="60"
verbose="false">

<testsuites>
<testsuite name="default">
<file>./tests/DefaultStateTest.php</file>
</testsuite>
<testsuite name="custom">
<file>./tests/CustomStateTest.php</file>
</testsuite>
</testsuites>

<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>

<logging>
<log type="coverage-html" target="tmp/report" lowUpperBound="35" highLowerBound="70" />
</logging>

</phpunit>
39 changes: 39 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd"
bootstrap="./vendor/autoload.php"
backupGlobals="true"
backupStaticAttributes="false"
cacheTokens="false"
colors="false"
convertErrorsToExceptions="false"
convertNoticesToExceptions="false"
convertWarningsToExceptions="false"
forceCoversAnnotation="false"
mapTestClassNameToCoveredClassName="false"
printerClass="PHPUnit_TextUI_ResultPrinter"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
testSuiteLoaderClass="PHPUnit_Runner_StandardTestSuiteLoader"
timeoutForSmallTests="1"
timeoutForMediumTests="10"
timeoutForLargeTests="60"
verbose="false">

<testsuites>
<testsuite name="default">
<file>./tests/DefaultStateTest.php</file>
</testsuite>
<testsuite name="custom">
<file>./tests/CustomStateTest.php</file>
</testsuite>
</testsuites>



</phpunit>
185 changes: 185 additions & 0 deletions src/DefaultLogger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php namespace MyENA;

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

use Psr\Log\AbstractLogger;
use Psr\Log\LogLevel;

/**
* Class DefaultLogger
*
* @package MyENA
*/
class DefaultLogger extends AbstractLogger
{
/** @var string */
public static $dateTimeFormat = \DateTime::RFC3339;

/** @var resource */
protected $stream;

/** @var string */
protected $streamURI;
/** @var string */
protected $streamMode;

/** @var string */
protected $level;

/** @var array */
protected $levelMap = [
LogLevel::DEBUG => 0,
LogLevel::INFO => 1,
LogLevel::NOTICE => 2,
LogLevel::WARNING => 3,
LogLevel::ERROR => 4,
LogLevel::CRITICAL => 5,
LogLevel::ALERT => 6,
LogLevel::EMERGENCY => 7,
];

/**
* DefaultLogger constructor.
*
* @param string $level
* @param resource|null $writeableStream
*/
public function __construct($level = LogLevel::DEBUG, $writeableStream = null)
{
$this->setLogLevel($level);

if (null === $writeableStream)
$this->stream = $this->defaultStream();
else
$this->stream = $writeableStream;

$m = stream_get_meta_data($this->stream);
$this->streamMode = $m['mode'];
$this->streamURI = $m['uri'];
}

/**
* @return array
*/
public function getPossibleLogLevels()
{
return $this->levelMap;
}

/**
* @return string
*/
public function getLogLevel()
{
return $this->level;
}

/**
* setLogLevel will limit what is written to a level greater than or equal to value passed in.
*
* @param string $logLevel
*/
public function setLogLevel($logLevel)
{
if (!is_string($logLevel) || '' === ($level = strtolower($logLevel)) || !isset($this->levelMap[$level]))
{
throw new \InvalidArgumentException(sprintf(
'%s - Log level must be one of the following values: ["%s"]. %s seen.',
get_called_class(),
implode('", "', array_keys($this->levelMap)),
is_string($logLevel) ? $logLevel : gettype($logLevel)
));
}

$this->level = $level;
}

/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*/
public function log($level, $message, array $context = array())
{
if (!is_string($level) || !isset($this->levelMap[$level]))
throw new \InvalidArgumentException(sprintf('"%s" is an unknown log level', $level));

if ($this->levelMap[$this->level] <= $this->levelMap[$level])
{
$slug = sprintf('[%s]%s', strtolower($level), str_repeat(' ', 15 - strlen($level)));
if ("\n" !== substr($message, -1))
$message .= "\n";

$msg = sprintf('%s%s %s', $slug, date(static::$dateTimeFormat), $message);

$this->tryLog($msg);
}
}

/**
* defaultStream will be used if no alternative is passed in during construction or if specified stream closes
* unexpectedly
*
* @return resource
*/
protected function defaultStream()
{
return fopen('php://output', 'a');
}

/**
* tryLog will attempt to write output to local stream. If unable, will kick-off re-open attempt
*
* @param string $msg
* @param int $tries
*/
protected function tryLog($msg, $tries = 0)
{
if ((bool)@fwrite($this->stream, $msg))
return;

if (0 < $tries)
{
trigger_error(sprintf('%s - Unable to log message: "%s"', get_called_class(), $tries, $msg));
return;
}

$this->attemptStreamRecovery();

$this->tryLog($msg, ++$tries);
}

/**
* Will attempt to re-open stream in the event that it was closed unexpectedly. Will use default if unable to
* re-open custom
*
* @see DefaultLogger::defaultStream()
*/
protected function attemptStreamRecovery()
{
if ('resource' === gettype($this->stream))
{
@fflush($this->stream);
@fclose($this->stream);
}

$this->stream = fopen($this->streamURI, $this->streamMode);
if (false === $this->stream)
{
trigger_error(sprintf(
'%s - Unable to write to "%s" and re-open attempt failed, will default to php-output',
get_called_class(),
$this->streamURI));

$this->stream = $this->defaultStream();
}
}
}
Loading

0 comments on commit 81b46da

Please sign in to comment.