Skip to content

Commit

Permalink
Merge pull request #99 from Nekland/feature/logger
Browse files Browse the repository at this point in the history
Logger feature
  • Loading branch information
folliked committed Jan 3, 2017
2 parents 82da5dd + 6d18d2e commit 012a809
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 16 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"require": {
"react/event-loop": "~0.4.0",
"react/socket": "~0.4.0",
"nekland/tools": "^1.0"
"nekland/tools": "^1.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^5.3"
Expand Down
19 changes: 19 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ The `Websocket` instantiation take the following parameters:
- `"127.0.0.1"`: the host you bind on, this is the default value and what you need most part of the time
- `[]`: an (optional) array of configuration option documented in the [configuration reference](#configuration-reference)

The `Connection` object has the following methods you can use:
- `write($message, $opCode = Frame::OP_TEXT)`, you may change to `Frame::OP_BINARY` if you want to send binary data
- `getIp()`, that returns the current IP
- `getLogger()`, that returns the logger of woketo

### Use it your way

Here are some helpers you can use depending on your use-case:
Expand Down Expand Up @@ -98,6 +103,20 @@ $defaultConfiguration = [
];
```

### Logs

Woketo provides a custom logger but you may want to log with yours. It's easy as Woketo uses psr-3 log system.

```php
<?php

$server = new WebSocketServer(1337);
$server->setLogger($myLogger);
$server->run();
```

> Notice that the logger you give will be accessible from `Connection::getLogger()`.
### Message Handler

A message handler is an object you can re-use that handle a specific type of message and throw a specific related
Expand Down
43 changes: 36 additions & 7 deletions src/Server/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@
use Nekland\Woketo\Rfc6455\Message;
use Nekland\Woketo\Rfc6455\MessageProcessor;
use Nekland\Woketo\Rfc6455\ServerHandshake;
use Psr\Log\LoggerAwareTrait;
use React\EventLoop\LoopInterface;
use React\EventLoop\Timer\TimerInterface;
use React\Socket\ConnectionInterface;

class Connection
{
use LoggerAwareTrait;

/**
* 5 seconds
*/
Expand Down Expand Up @@ -71,8 +74,13 @@ class Connection
*/
private $timeout;

public function __construct(ConnectionInterface $socketStream, MessageHandlerInterface $messageHandler, LoopInterface $loop, MessageProcessor $messageProcessor, ServerHandshake $handshake = null)
{
public function __construct(
ConnectionInterface $socketStream,
MessageHandlerInterface $messageHandler,
LoopInterface $loop,
MessageProcessor $messageProcessor,
ServerHandshake $handshake = null
) {
$this->socketStream = $socketStream;
$this->initListeners();
$this->handler = $messageHandler;
Expand All @@ -86,7 +94,9 @@ private function initListeners()
$this->socketStream->on('data', function ($data) {
$this->processData($data);
});
$this->socketStream->on('error', [$this, 'error']);
$this->socketStream->on('error', function ($data) {
$this->error($data);
});
}

private function processData($data)
Expand All @@ -101,6 +111,7 @@ private function processData($data)
return;
} catch (WebsocketException $e) {
$this->messageProcessor->close($this->socketStream);
$this->logger->notice('Connection to ' . $this->getIp() . ' closed with error : ' . $e->getMessage());
$this->handler->onError($e, $this);
}
}
Expand Down Expand Up @@ -135,11 +146,11 @@ protected function processMessage($data)
} else {
// We wait for more data so we start a timeout.
$this->timeout = $this->loop->addTimer(Connection::DEFAULT_TIMEOUT, function () {
$this->logger->notice('Connection to ' . $this->getIp() . ' timed out.');
$this->messageProcessor->timeout($this->socketStream);
});
}
}

}

/**
Expand All @@ -157,11 +168,13 @@ public function write($frame, int $opCode = Frame::OP_TEXT)
}

/**
* @param $data
* @param mixed $data
*/
public function error($data)
protected function error($data)
{
echo "There is an error : \n" . $data . "\n\n";
$message = "A connectivity error occurred: " . $data;
$this->logger->error($message);
$this->handler->onError(new WebsocketException($message), $this);
}

/**
Expand All @@ -184,4 +197,20 @@ protected function processHandcheck($data)
$this->handshakeDone = true;
$this->handler->onConnection($this);
}

/**
* @return string
*/
public function getIp()
{
return $this->socketStream->getRemoteAddress();
}

/**
* @return \Psr\Log\LoggerInterface
*/
public function getLogger()
{
return $this->logger;
}
}
51 changes: 43 additions & 8 deletions src/Server/WebSocketServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,23 @@
use Nekland\Woketo\Rfc6455\MessageHandler\PingFrameHandler;
use Nekland\Woketo\Rfc6455\MessageProcessor;
use Nekland\Woketo\Rfc6455\ServerHandshake;
use Nekland\Woketo\Utils\SimpleLogger;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use React\EventLoop\LoopInterface;
use React\Socket\ConnectionInterface;

class WebSocketServer
{
/**
* @var int Store the port for debug purpose.
* @var int
*/
private $port;

/**
* @var string
*/
private $address;
private $host;

/**
* @var ServerHandshake
Expand Down Expand Up @@ -67,16 +70,19 @@ class WebSocketServer
private $config;

/**
* Websocket constructor.
*
* @var LoggerInterface
*/
private $logger;

/**
* @param int $port The number of the port to bind
* @param string $address The address to listen on (by default 127.0.0.1)
* @param string $host The host to listen on (by default 127.0.0.1)
* @param array $config
*/
public function __construct($port, $address = '127.0.0.1', $config = [])
public function __construct($port, $host = '127.0.0.1', $config = [])
{
$this->setConfig($config);
$this->address = $address;
$this->host = $host;
$this->port = $port;
$this->handshake = new ServerHandshake();
$this->connections = [];
Expand Down Expand Up @@ -119,6 +125,8 @@ public function start()
});
$socket->listen($this->port);

$this->getLogger()->info('Listening on ' . $this->host . ':' . $this->port);

$this->loop->run();
}

Expand All @@ -132,7 +140,9 @@ private function onNewConnection(ConnectionInterface $socketStream)
$messageHandler = new $messageHandler;
}

$this->connections[] = new Connection($socketStream, $messageHandler, $this->loop, $this->messageProcessor);
$connection = new Connection($socketStream, $messageHandler, $this->loop, $this->messageProcessor);
$connection->setLogger($this->getLogger());
$this->connections[] = $connection;
}

/**
Expand Down Expand Up @@ -170,4 +180,29 @@ private function setConfig(array $config)
'prod' => true
], $config);
}

/**
* @return SimpleLogger|LoggerInterface
*/
public function getLogger()
{
if (null === $this->logger) {
return $this->logger = new SimpleLogger(!$this->config['prod']);
}

return $this->logger;
}

/**
* Allows you to set a custom logger
*
* @param LoggerInterface $logger
* @return WebSocketServer
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;

return $this;
}
}
44 changes: 44 additions & 0 deletions src/Utils/SimpleLogger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* This file is a part of Woketo package.
*
* (c) Nekland <dev@nekland.fr>
*
* For the full license, take a look to the LICENSE file
* on the root directory of this project
*/

namespace Nekland\Woketo\Utils;


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

class SimpleLogger extends AbstractLogger
{
/**
* Modify the log behavior
* @var bool
*/
private $debug;

public function __construct($debug = false)
{
$this->debug = $debug;
}

/**
* Log
*
* @param mixed $level
* @param string $message
* @param array $context
*/
public function log($level, $message, array $context = array())
{
// Doesn't log everything in not debug context
if ($this->debug || \in_array($level, [LogLevel::CRITICAL, LogLevel::ERROR])) {
echo '[' . date('Y-m-d H:i:s') . '][' . $level . '] ' . $message ."\n";
}
}
}
44 changes: 44 additions & 0 deletions tests/Woketo/Utils/SimpleLoggerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* This file is a part of Woketo package.
*
* (c) Nekland <dev@nekland.fr>
*
* For the full license, take a look to the LICENSE file
* on the root directory of this project
*/

namespace Test\Woketo\Utils;


use Nekland\Woketo\Utils\SimpleLogger;

class SimpleLoggerTest extends \PHPUnit_Framework_TestCase
{
public function testItEchoesLog()
{
$logger = new SimpleLogger();

\ob_start();
$logger->info('Just some information.');
$logger->critical('God, something went wrong !');

$res = \ob_get_clean();

$this->assertContains('God, something went wrong !', $res);
$this->assertNotContains('Just some information.', $res);
}

public function testItEchoesEverythingInDebugMode()
{
$logger = new SimpleLogger(true);

\ob_start();
$logger->critical('Oops!');
$logger->debug('Normal log');
$res = \ob_get_clean();

$this->assertContains('Oops!', $res);
$this->assertContains('Normal log', $res);
}
}

0 comments on commit 012a809

Please sign in to comment.