Passed
Push — master ( be88e3...87c6b6 )
by Fran
04:17
created

Logger::addLog()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 3
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
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\helpers\GeneratorHelper;
13
use PSFS\base\types\helpers\Inspector;
14
use PSFS\base\types\helpers\SlackHelper;
15
use PSFS\base\types\traits\SingletonTrait;
16
17
18
if (!defined('LOG_DIR')) {
19
    GeneratorHelper::createDir(BASE_DIR . DIRECTORY_SEPARATOR . 'logs');
20
    define('LOG_DIR', BASE_DIR . DIRECTORY_SEPARATOR . 'logs');
21
}
22
23
/**
24
 * Class Logger
25
 * @package PSFS\base
26
 * Servicio de log
27
 */
28
class Logger
29
{
30
    const DEFAULT_NAMESPACE = 'PSFS';
31
    use SingletonTrait;
32
    /**
33
     * @var \Monolog\Logger
34
     */
35
    protected $logger;
36
    /**
37
     * @var resource
38
     */
39
    private $stream;
40
    /**
41
     * @var UidProcessor
42
     */
43
    private $uuid;
44
    /**
45
     * @var string
46
     */
47
    protected $logLevel;
48
49
    /**
50
     * Logger constructor.
51
     * @throws exception\GeneratorException
52
     */
53 2
    public function __construct()
54
    {
55 2
        $config = Config::getInstance();
56 2
        $args = func_get_args();
57 2
        list($logger, $debug, $path) = $this->setup($config, $args);
58 2
        $this->stream = fopen($path . DIRECTORY_SEPARATOR . date('Ymd') . '.log', 'a+');
0 ignored issues
show
Documentation Bug introduced by
It seems like fopen($path . PSFS\base\...('Ymd') . '.log', 'a+') can also be of type false. However, the property $stream is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
59 2
        $this->addPushLogger($logger, $debug, $config);
60 2
        $this->logLevel = Config::getParam('log.level', 'NOTICE');
61 2
    }
62
63 1
    public function __destruct()
64
    {
65 1
        fclose($this->stream);
66 1
    }
67
68
    /**
69
     * @param string $logger
70
     * @param boolean $debug
71
     * @param Config $config
72
     * @throws \Exception
73
     */
74 2
    private function addPushLogger($logger, $debug, Config $config)
75
    {
76 2
        $this->logger = new Monolog(strtoupper($logger));
77 2
        $this->logger->pushHandler($this->addDefaultStreamHandler($debug));
78 2
        if ($debug) {
79 2
            $phpFireLog = $config->get('logger.phpFire');
80 2
            if (!empty($phpFireLog)) {
81 1
                $this->logger->pushHandler(new FirePHPHandler());
82
            }
83 2
            $memoryLog = $config->get('logger.memory');
84 2
            if (!empty($memoryLog)) {
85 1
                $this->logger->pushProcessor(new MemoryUsageProcessor());
86
            }
87
        }
88 2
        $this->uuid = new UidProcessor();
89 2
        $this->logger->pushProcessor($this->uuid);
90 2
    }
91
92
    /**
93
     * @param Config $config
94
     * @param array $args
95
     * @return array
96
     * @throws exception\GeneratorException
97
     */
98 2
    private function setup(Config $config, array $args = [])
99
    {
100 2
        $args = $args ?? [];
101 2
        $debug = $config->getDebugMode();
102 2
        $namespace = self::DEFAULT_NAMESPACE;
103 2
        if (0 !== count($args)) {
104 2
            $namespace = $args[0][0] ?? 'PSFS';
105 2
            $debug = $args[0][1] ?? true;
106
        }
107 2
        $path = $this->createLoggerPath($config);
108 2
        return array($this->cleanLoggerName($namespace), $debug, $path);
109
    }
110
111
    /**
112
     * @param Config $config
113
     *
114
     * @return string
115
     */
116 2
    private function setLoggerName(Config $config)
117
    {
118 2
        $logger = $config->get('platform.name') ?: self::DEFAULT_NAMESPACE;
119 2
        $logger = $this->cleanLoggerName($logger);
120
121 2
        return $logger;
122
    }
123
124
    /**
125
     * @param $logger
126
     *
127
     * @return mixed
128
     */
129 2
    private function cleanLoggerName($logger)
130
    {
131 2
        $logger = str_replace(' ', '', $logger);
132 2
        $logger = preg_replace('/\\\/', ".", $logger);
133
134 2
        return $logger;
135
    }
136
137
    /**
138
     * @param Config $config
139
     * @return string
140
     * @throws exception\GeneratorException
141
     */
142 2
    private function createLoggerPath(Config $config)
143
    {
144 2
        $logger = $this->setLoggerName($config);
145 2
        $path = LOG_DIR . DIRECTORY_SEPARATOR . $logger . DIRECTORY_SEPARATOR . date('Y') . DIRECTORY_SEPARATOR . date('m');
146 2
        GeneratorHelper::createDir($path);
147
148 2
        return $path;
149
    }
150
151
    /**
152
     * @param string $msg
153
     * @param int $type
154
     * @param array $context
155
     * @return bool
156
     */
157 23
    public function addLog($msg, $type = \Monolog\Logger::NOTICE, array $context = []) {
158 23
        return $this->checkLogLevel($type) ? $this->logger->addRecord($type, $msg, $this->addMinimalContext($context)) : true;
159
    }
160
161
    /**
162
     * @param int $level
163
     * @return bool
164
     */
165 23
    private function checkLogLevel($level = \Monolog\Logger::NOTICE) {
166 23
        switch($this->logLevel) {
167 23
            case 'DEBUG': $logPass = Monolog::DEBUG; break;
168 23
            case 'INFO': $logPass = Monolog::INFO; break;
169
            default:
170 23
            case 'NOTICE': $logPass = Monolog::NOTICE; break;
171
            case 'WARNING': $logPass = Monolog::WARNING; break;
172
            case 'ERROR': $logPass = Monolog::ERROR; break;
173
            case 'CRITICAL': $logPass = Monolog::CRITICAL; break;
174
        }
175 23
        return $logPass <= $level;
176
    }
177
178
    /**
179
     * @param string $msg
180
     * @param int $type
181
     * @param array $context
182
     */
183 23
    public static function log($msg, $type = LOG_DEBUG, array $context = null)
184
    {
185 23
        if(null === $context) {
186 23
            $context = [];
187
        }
188 23
        if(Config::getParam('profiling.enable') && 'DEBUG' === Config::getParam('log.level', 'NOTICE')) {
189
            Inspector::stats($msg);
190
        }
191
        switch ($type) {
192 23
            case LOG_DEBUG:
193 22
                self::getInstance()->addLog($msg, \Monolog\Logger::DEBUG, $context);
194 22
                break;
195 7
            case LOG_WARNING:
196 2
                self::getInstance()->addLog($msg, \Monolog\Logger::WARNING, $context);
197 2
                break;
198 7
            case LOG_CRIT:
199 1
                if(Config::getParam('log.slack.hook')) {
200
                    SlackHelper::getInstance()->trace($msg, '', '', $context);
201
                }
202 1
                self::getInstance()->addLog($msg, \Monolog\Logger::CRITICAL, $context);
203 1
                break;
204 7
            case LOG_ERR:
205 4
                self::getInstance()->addLog($msg, \Monolog\Logger::ERROR, $context);
206 4
                break;
207 4
            case LOG_INFO:
208 4
                self::getInstance()->addLog($msg, \Monolog\Logger::INFO, $context);
209 4
                break;
210
            default:
211 1
                self::getInstance()->addLog($msg, \Monolog\Logger::NOTICE, $context);
212 1
                break;
213
        }
214 23
    }
215
216
    /**
217
     * @param bool $debug
218
     * @return StreamHandler
219
     * @throws \Exception
220
     */
221 2
    private function addDefaultStreamHandler($debug = false)
222
    {
223
        // the default date format is "Y-m-d H:i:s"
224 2
        $dateFormat = 'Y-m-d H:i:s.u';
225
        // the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
226 2
        $output = "[%datetime%] [%channel%:%level_name%]\t%message%\t%context%\t%extra%\n";
227
        // finally, create a formatter
228 2
        $formatter = new LineFormatter($output, $dateFormat);
229 2
        $stream = new StreamHandler($this->stream, $debug ? Monolog::DEBUG : Monolog::WARNING);
230 2
        $stream->setFormatter($formatter);
231 2
        return $stream;
232
    }
233
234
    /**
235
     * @param array $context
236
     * @return array
237
     */
238 5
    private function addMinimalContext(array $context = [])
239
    {
240 5
        $context['uri'] = null !== $_SERVER && array_key_exists('REQUEST_URI', $_SERVER) ? $_SERVER['REQUEST_URI'] : 'Unknow';
241 5
        $context['method'] = null !== $_SERVER && array_key_exists('REQUEST_METHOD', $_SERVER) ? $_SERVER['REQUEST_METHOD'] : 'Unknow';
242 5
        if(null !== $_SERVER && array_key_exists('HTTP_X_PSFS_UID', $_SERVER)) {
243
            $context['uid'] = $_SERVER['HTTP_X_PSFS_UID'];
244
        }
245 5
        return $context;
246
    }
247
248
    /**
249
     * @return string
250
     */
251
    public function getLogUid() {
252
        return $this->uuid->getUid();
253
    }
254
255
    /**
256
     * @return string
257
     */
258
    public static function getUid() {
259
        return self::getInstance()->getLogUid();
260
    }
261
}
262