Completed
Push — master ( 8a02a1...c877ec )
by Fran
04:56 queued 14s
created

Logger::addDefaultStreamHandler()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 7
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 12
rs 9.4285
ccs 7
cts 7
cp 1
crap 2
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 17 and the first side effect is on line 16.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
namespace PSFS\base;
4
5
use Monolog\Formatter\LineFormatter;
6
use Monolog\Handler\FirePHPHandler;
7
use Monolog\Handler\StreamHandler;
8
use Monolog\Logger as Monolog;
9
use Monolog\Processor\MemoryUsageProcessor;
10
use Monolog\Processor\UidProcessor;
11
use PSFS\base\config\Config;
12
use PSFS\base\types\SingletonTrait;
13
14
15 1
if (!defined("LOG_DIR")) {
16
    Config::createDir(BASE_DIR . DIRECTORY_SEPARATOR . 'logs');
17
    define("LOG_DIR", BASE_DIR . DIRECTORY_SEPARATOR . 'logs');
18
}
19
20
/**
21
 * Class Logger
22
 * @package PSFS\base
23
 * Servicio de log
24
 */
25
class Logger
26
{
27
    const DEFAULT_NAMESPACE = 'PSFS';
28
    use SingletonTrait;
29
    /**
30
     * @var \Monolog\Logger
31
     */
32
    protected $logger;
33
    /**
34
     * @var resource
35
     */
36
    private $stream;
37
38
    /**
39
     * @internal param string $path
40
     */
41 1
    public function __construct()
42
    {
43 1
        $config = Config::getInstance();
44 1
        $args = func_get_args();
45 1
        list($logger, $debug, $path) = $this->setup($config, $args);
46 1
        $this->stream = fopen($path . DIRECTORY_SEPARATOR . date("Ymd") . ".log", "a+");
47 1
        $this->addPushLogger($logger, $debug, $config);
48 1
    }
49
50
    /**
51
     * Destruye el recurso
52
     */
53
    public function __destroy()
54
    {
55
        fclose($this->stream);
56
    }
57
58
    /**
59
     * Método que escribe un log de información
60
     * @param string $msg
61
     * @param array $context
62
     *
63
     * @return bool
64
     */
65
    public function infoLog($msg = '', $context = [])
66
    {
67
        return $this->logger->addInfo($msg, $this->addMinimalContext($context));
68
    }
69
70
    /**
71
     * Método que escribe un log de Debug
72
     * @param string $msg
73
     * @param array $context
74
     *
75
     * @return bool
76
     */
77 8
    public function debugLog($msg = '', $context = [])
78
    {
79 8
        return $this->logger->addDebug($msg, $this->addMinimalContext($context));
80
    }
81
82
    /**
83
     * Método que escribe un log de Error
84
     * @param $msg
85
     * @param array $context
86
     *
87
     * @return bool
88
     */
89 3
    public function errorLog($msg, $context = [])
90
    {
91 3
        return $this->logger->addError($msg, $this->addMinimalContext($context));
92
    }
93
94
    /**
95
     * Método que escribe un log de Warning
96
     * @param $msg
97
     * @param array $context
98
     * @return bool
99
     */
100
    public function warningLog($msg, $context = [])
101
    {
102
        return $this->logger->addWarning($msg, $this->addMinimalContext($context));
103
    }
104
105
    /**
106
     * Método que añade los push processors
107
     * @param string $logger
108
     * @param boolean $debug
109
     * @param Config $config
110
     */
111 1
    private function addPushLogger($logger, $debug, Config $config)
112
    {
113 1
        $this->logger = new Monolog(strtoupper($logger));
114 1
        $this->logger->pushHandler($this->addDefaultStreamHandler($debug));
115 1
        if ($debug) {
116
            $phpFireLog = $config->get("logger.phpFire");
117
            if (!empty($phpFireLog)) {
118
                $this->logger->pushHandler(new FirePHPHandler());
119
            }
120
            $memoryLog = $config->get("logger.memory");
121
            if (!empty($memoryLog)) {
122
                $this->logger->pushProcessor(new MemoryUsageProcessor());
123
            }
124
        }
125 1
        $this->logger->pushProcessor(new UidProcessor());
126 1
    }
127
128
    /**
129
     * Método que inicializa el Logger
130
     * @param Config $config
131
     * @param array $args
132
     *
133
     * @return array
134
     */
135 1
    private function setup(Config $config, array $args = array())
136
    {
137 1
        $debug = $config->getDebugMode();
138 1
        $namespace = self::DEFAULT_NAMESPACE;
139 1
        if (0 !== count($args)) {
140 1
            if (array_key_exists(0, $args) && array_key_exists(0, $args[0])) {
141
                $namespace = $args[0][0];
142
            }
143 1
            if (array_key_exists(0, $args) && array_key_exists(1, $args[0])) {
144
                $debug = $args[0][1];
145
            }
146 1
        }
147 1
        $path = $this->createLoggerPath($config);
148 1
        return array($this->cleanLoggerName($namespace), $debug, $path);
149
    }
150
151
    /**
152
     * Método que construye el nombre del logger
153
     * @param Config $config
154
     *
155
     * @return string
156
     */
157 1
    private function setLoggerName(Config $config)
158
    {
159 1
        $logger = $config->get("platform_name") ?: self::DEFAULT_NAMESPACE;
160 1
        $logger = $this->cleanLoggerName($logger);
161
162 1
        return $logger;
163
    }
164
165
    /**
166
     * Método para limpiar el nombre del logger
167
     * @param $logger
168
     *
169
     * @return mixed
170
     */
171 1
    private function cleanLoggerName($logger)
172
    {
173 1
        $logger = str_replace(' ', '', $logger);
174 1
        $logger = preg_replace('/\\\/', ".", $logger);
175
176 1
        return $logger;
177
    }
178
179
    /**
180
     * Método que crea el path del logger
181
     * @param Config $config
182
     *
183
     * @return string
184
     */
185 1
    private function createLoggerPath(Config $config)
186
    {
187 1
        $logger = $this->setLoggerName($config);
188 1
        $path = LOG_DIR . DIRECTORY_SEPARATOR . $logger . DIRECTORY_SEPARATOR . date('Y') . DIRECTORY_SEPARATOR . date('m');
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
189 1
        Config::createDir($path);
190
191 1
        return $path;
192
    }
193
194
    /**
195
     * Static method to trace logs
196
     * @param string $msg
197
     * @param int $type
198
     * @param array $context
199
     */
200 8
    public static function log($msg, $type = LOG_DEBUG, $context = [])
201
    {
202
        switch ($type) {
203 8
            case LOG_DEBUG:
204 8
                Logger::getInstance()->debugLog($msg, $context);
205 8
                break;
206 3
            case LOG_WARNING:
207
                Logger::getInstance()->warningLog($msg, $context);
208
                break;
209 3
            case LOG_CRIT:
210 3
            case LOG_ERR:
211 3
                Logger::getInstance()->errorLog($msg, $context);
212 3
                break;
213
            case LOG_INFO:
214
                Logger::getInstance()->infoLog($msg, $context);
215
                break;
216
            default:
217
                Logger::getInstance()->log($msg, $context);
0 ignored issues
show
Documentation introduced by
$context is of type array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
218
                break;
219
        }
220 8
    }
221
222
    /**
223
     * Add the default stream handler
224
     * @param bool $debug
225
     * @return StreamHandler
226
     */
227 1
    private function addDefaultStreamHandler($debug = false)
228
    {
229
        // the default date format is "Y-m-d H:i:s"
230 1
        $dateFormat = "Y-m-d H:i:s.u";
231
        // the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
232 1
        $output = "[%datetime%] [%channel%:%level_name%]\t%message%\t%context%\t%extra%\n";
233
        // finally, create a formatter
234 1
        $formatter = new LineFormatter($output, $dateFormat);
235 1
        $stream = new StreamHandler($this->stream, $debug ? Monolog::DEBUG : Monolog::WARNING);
236 1
        $stream->setFormatter($formatter);
237 1
        return $stream;
238
    }
239
240
    /**
241
     * Add a minimum context to the log
242
     * @param array $context
243
     * @return array
244
     */
245 8
    private function addMinimalContext(array $context = [])
0 ignored issues
show
Coding Style introduced by
addMinimalContext uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
246
    {
247 8
        $context['uri'] = null !== $_SERVER && array_key_exists('REQUEST_URI', $_SERVER) ? $_SERVER['REQUEST_URI'] : 'Unknow';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 126 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
248 8
        $context['method'] = null !== $_SERVER && array_key_exists('REQUEST_METHOD', $_SERVER) ? $_SERVER['REQUEST_METHOD'] : 'Unknow';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 135 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
249 8
        return $context;
250
    }
251
}
252