Passed
Push — master ( b269c0...1e4b3a )
by Ioannes
01:31
created

Log::notice()   A

Complexity

Conditions 3
Paths 5

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 9
rs 10
cc 3
nc 5
nop 2
1
<?php
2
namespace App;
3
4
use App\Monolog\ArrayFormatter;
5
use Bitrix\Main\Diag\Debug;
0 ignored issues
show
Bug introduced by
The type Bitrix\Main\Diag\Debug was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Bitrix\Main\Error;
0 ignored issues
show
Bug introduced by
The type Bitrix\Main\Error was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Monolog\Formatter\HtmlFormatter;
8
use Monolog\Formatter\LineFormatter;
9
use Monolog\Formatter\NormalizerFormatter;
10
use Monolog\Handler\StreamHandler;
11
use Monolog\Handler\TelegramBotHandler;
12
use Monolog\Logger;
13
use Monolog\Registry;
14
use Psr\Log\LoggerInterface;
15
16
class Log implements LoggerInterface {
17
18
    private $channel;
19
    private $minDebugLevel;
20
21
    /**
22
     * @param string $channel
23
     */
24
    public function __construct($channel = '') {
25
26
        $this->minDebugLevel = ($_ENV['APP_DEBUG_LEVEL'] ?: 'DEBUG');
27
        if(!empty($channel)) {
28
            $this->channel = $channel;
29
            //TODO: get channel options
30
        } else {
31
            $this->channel = ($_ENV['APP_LOG_BITRIX_CHANNEL'] ?: 'bitrix');
32
        }
33
    }
34
35
    /**
36
     * @param $message
37
     * @param array $context
38
     */
39
    public function alert($message, $context = [])
40
    {
41
        try {
42
            $logger = $this->getLogger();
43
            $message = $this->formatMessage($message);
44
            $logger->alert($message, (array) $context);
45
        } catch (\Exception $e) {
46
            self::logInnerException($e);
47
        }
48
    }
49
50
    /**
51
     * @param $message
52
     * @param array $context
53
     */
54
    public function critical($message, $context = [])
55
    {
56
        try {
57
            $logger = $this->getLogger();
58
            $message = $this->formatMessage($message);
59
            $logger->critical($message, (array) $context);
60
        } catch (\Exception $e) {
61
            self::logInnerException($e);
62
        }
63
    }
64
65
    /**
66
     * @param $message
67
     * @param array $context
68
     */
69
    public function error($message, $context = [])
70
    {
71
        if ($this->isDebugEnabled(Logger::ERROR)) {
72
            try {
73
                $logger = $this->getLogger();
74
                $message = $this->formatMessage($message);
75
                $logger->error($message, (array) $context);
76
            } catch (\Exception $e) {
77
                self::logInnerException($e);
78
            }
79
        }
80
    }
81
82
    /**
83
     * @param $message
84
     * @param array $context
85
     */
86
    public function warning($message, $context = [])
87
    {
88
        if ($this->isDebugEnabled(Logger::WARNING)) {
89
            try {
90
                $logger = $this->getLogger();
91
                $message = $this->formatMessage($message);
92
                $logger->warning($message, (array) $context);
93
            } catch (\Exception $e) {
94
                self::logInnerException($e);
95
            }
96
        }
97
    }
98
99
    /**
100
     * @param $message
101
     * @param array $context
102
     */
103
    public function notice($message, $context = [])
104
    {
105
        if ($this->isDebugEnabled(Logger::NOTICE)) {
106
            try {
107
                $logger = $this->getLogger();
108
                $message = $this->formatMessage($message);
109
                $logger->notice($message, (array) $context);
110
            } catch (\Exception $e) {
111
                self::logInnerException($e);
112
            }
113
        }
114
    }
115
116
    /**
117
     * @param $message
118
     * @param array $context
119
     */
120
    public function info($message, $context = [])
121
    {
122
        if ($this->isDebugEnabled(Logger::INFO)) {
123
            try {
124
                $logger = $this->getLogger();
125
                $message = $this->formatMessage($message);
126
                $logger->info($message, (array) $context);
127
            } catch (\Exception $e) {
128
                self::logInnerException($e);
129
            }
130
        }
131
    }
132
133
    /**
134
     * @param $message
135
     * @param array $context
136
     */
137
    public function debug($message, $context = [])
138
    {
139
        if ($this->isDebugEnabled(Logger::DEBUG)) {
140
            try {
141
                $logger = $this->getLogger();
142
                $message = $this->formatMessage($message);
143
                $logger->debug($message, (array) $context);
144
            } catch (\Exception $e) {
145
                self::logInnerException($e);
146
            }
147
        }
148
    }
149
150
    public function emergency($message, $context = [])
151
    {
152
        try {
153
            $logger = $this->getLogger();
154
            $message = $this->formatMessage($message);
155
            $logger->emergency($message, (array) $context);
156
        } catch (\Exception $e) {
157
            self::logInnerException($e);
158
        }
159
    }
160
161
    public function log($level, $message, $context = [])
162
    {
163
        $level = Logger::toMonologLevel($level);
164
        if ($this->isDebugEnabled($level)) {
165
            try {
166
                $logger = $this->getLogger();
167
                $message = $this->formatMessage($message);
168
                $logger->log($level, $message, (array) $context);
169
            } catch (\Exception $e) {
170
                self::logInnerException($e);
171
            }
172
        }
173
    }
174
175
    public function telegram($level, $message, $context = []) {
176
177
        $level = Logger::toMonologLevel($level);
178
        if (!$this->isDebugEnabled($level)) {
179
            return;
180
        }
181
182
        $isEnabled = false;
183
        if(isset($_ENV['APP_LOG_TELEGRAM'])) {
184
            $APP_LOG_TELEGRAM = trim(strtolower($_ENV['APP_LOG_TELEGRAM']));
185
            if($APP_LOG_TELEGRAM === 'on' || $APP_LOG_TELEGRAM === 'true' || $APP_LOG_TELEGRAM === '1') {
186
                $isEnabled = true;
187
            }
188
        }
189
190
        if(!isset($_ENV['APP_LOG_TELEGRAM_KEY']) || empty($_ENV['APP_LOG_TELEGRAM_KEY'])) {
191
            $isEnabled = false;
192
        }
193
        if(!isset($_ENV['APP_LOG_TELEGRAM_CHANNEL']) || empty($_ENV['APP_LOG_TELEGRAM_CHANNEL'])) {
194
            $isEnabled = false;
195
        }
196
197
        if(!$isEnabled) {
198
            return;
199
        }
200
201
        $sender = new TelegramBotHandler($_ENV['APP_LOG_TELEGRAM_KEY'], $_ENV['APP_LOG_TELEGRAM_CHANNEL']);
202
203
        if(isset($context['parse_mode']) && !empty($context['parse_mode'])) {
204
            $sender->setParseMode($context['parse_mode']);
205
            unset($context['parse_mode']);
206
        }
207
        if(isset($context['disable_notification']) && $context['disable_notification'] === true) {
208
            $sender->disableNotification(true);
209
            unset($context['disable_notification']);
210
        }
211
        if(isset($context['disable_preview']) && $context['disable_preview'] === true) {
212
            $sender->disableWebPagePreview(true);
213
            unset($context['disable_preview']);
214
        }
215
216
        $sender->setFormatter(new LineFormatter("[%datetime%] %level_name%: %message%"));
217
218
        $telegramLogger = new Logger('Telegram');
219
        $telegramLogger->pushHandler($sender);
220
        $telegramLogger->log($level, $message, $context);
221
    }
222
223
    /**
224
     * @param $message
225
     * @return string
226
     */
227
    private function formatMessage($message) {
228
229
        if($message instanceof \Exception || $message instanceof Error) {
230
            $message = (string) $message;
231
        } else if(is_array($message) || is_object($message)) {
232
            $message = json_encode((array) $message, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
233
            $message = str_replace('\\u0000', '', $message);
234
        }
235
        return (string) $message;
236
    }
237
238
    /**
239
     * @return Logger
240
     */
241
    public function getLogger() {
242
243
        if(Registry::hasLogger($this->channel)) {
244
            return Registry::getInstance($this->channel);
245
        }
246
        $logPath = $_SERVER['DOCUMENT_ROOT'] . ($_ENV['APP_LOG_FOLDER'] ?: '/log/');
247
        $logPath .= $this->channel . '/' . date('Y-m-d') . '.log';
248
        $logDir = pathinfo($logPath, PATHINFO_DIRNAME);
249
        if(!file_exists($logDir)) {
0 ignored issues
show
Bug introduced by
It seems like $logDir can also be of type array; however, parameter $filename of file_exists() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

249
        if(!file_exists(/** @scrutinizer ignore-type */ $logDir)) {
Loading history...
250
            $mode = 0775;
251
            if(defined('BX_DIR_PERMISSIONS') && BX_DIR_PERMISSIONS) {
0 ignored issues
show
Bug introduced by
The constant App\BX_DIR_PERMISSIONS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
252
                $mode = BX_DIR_PERMISSIONS;
253
            }
254
            mkdir($logDir, $mode, true);
0 ignored issues
show
Bug introduced by
It seems like $logDir can also be of type array; however, parameter $directory of mkdir() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

254
            mkdir(/** @scrutinizer ignore-type */ $logDir, $mode, true);
Loading history...
255
        }
256
257
        $handler = new StreamHandler($logPath);
258
        $handler->setFormatter(new ArrayFormatter());
259
260
        $logger = new Logger($this->channel);
261
        $logger->pushHandler($handler);
262
        Registry::addLogger($logger, $this->channel, true);
263
264
        return $logger;
265
    }
266
267
    /**
268
     * @return int|mixed
269
     */
270
    private function getMinErrorLevel() {
271
272
        $levels = Logger::getLevels();
273
274
        if($this->minDebugLevel && isset($levels[$this->minDebugLevel])) {
275
            return $levels[$this->minDebugLevel];
276
        } else {
277
            return Logger::DEBUG;
278
        }
279
    }
280
281
    /**
282
     * @param int $level
283
     * @return bool
284
     */
285
    private function isDebugEnabled($level = 0)
286
    {
287
        if (defined('FORCE_DEBUG') && FORCE_DEBUG) {
0 ignored issues
show
Bug introduced by
The constant App\FORCE_DEBUG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
288
            return true;
289
        }
290
291
        $min_level = $this->getMinErrorLevel();
292
        if($level >= $min_level) {
293
            return true;
294
        }
295
        return false;
296
    }
297
298
    /**
299
     * @param \Exception $exception
300
     */
301
    public static function logInnerException(\Exception $exception)
302
    {
303
        Debug::writeToFile((string) $exception, "", "inner_error.log");
304
    }
305
306
    public static function cleanLogs($daysAgo = 15) {
307
308
        $logPath = $_SERVER['DOCUMENT_ROOT'] . ($_ENV['APP_LOG_FOLDER'] ?: '/log/');
309
        $command = sprintf("find %s -mindepth 1 -type f -mtime +%d | xargs rm", $logPath, $daysAgo);
310
        exec($command);
311
        return sprintf('\App\Log::cleanLogs(%d);', $daysAgo);
312
    }
313
}
314