DebugbarLogger::alert()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
use DebugBar\StandardDebugBar;
13
use DebugBar\DataCollector\MessagesCollector;
14
use Psr\Log\LoggerInterface;
15
use Psr\Log\LogLevel;
16
use Xoops\Core\Logger;
17
18
/**
19
 * Collects log information and present to PHPDebugBar for display.
20
 * Records information about database queries, blocks, and execution time
21
 * and various logs.
22
 *
23
 * @category  DebugbarLogger
24
 * @package   DebugbarLogger
25
 * @author    Richard Griffith <[email protected]>
26
 * @copyright 2013 XOOPS Project (http://xoops.org)
27
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
28
 * @version   Release: 1.0
29
 * @link      http://xoops.org
30
 * @since     1.0
31
 */
32
class DebugbarLogger implements LoggerInterface
33
{
34
    /**
35
     * @var object
36
     */
37
    private $debugbar = false;
38
39
    /**
40
     * @var object
41
     */
42
    private $renderer = false;
43
44
    /**
45
     * @var object
46
     */
47
    private $activated = false;
48
49
    /**
50
     * @var object
51
     */
52
    private $quietmode = false;
53
54
    /**
55
     * constructor
56
     */
57
    public function __construct()
58
    {
59
        Logger::getInstance()->addLogger($this);
60
    }
61
62
    /**
63
     * Get a reference to the only instance of this class
64
     *
65
     * @return  object LoggerAbstract  reference to the only instance
66
     */
67
    public static function getInstance()
68
    {
69
        static $instance;
70
        if (!isset($instance)) {
71
            $class = __CLASS__;
72
            $instance = new $class();
73
        }
74
75
        return $instance;
76
    }
77
78
    /**
79
     * Get our debugbar object
80
     *
81
     * @return \DebugBar\DebugBar
82
     */
83
    public function getDebugbar()
84
    {
85
        return $this->debugbar;
86
    }
87
88
    /**
89
     * disable logging
90
     *
91
     * @return void
92
     */
93
    public function disable()
94
    {
95
        //error_reporting(0);
96
        $this->activated = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type object of property $activated.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
97
    }
98
99
    /**
100
     * Enable logger output rendering
101
     * When output rendering is enabled, the logger will insert its output within the page content.
102
     * If the string <!--<xo-logger-output>--> is found in the page content, the logger output will
103
     * replace it, otherwise it will be inserted after all the page output.
104
     *
105
     * @return void
106
     */
107
    public function enable()
108
    {
109
        error_reporting(-1);
110
111
        $this->activated = true;
0 ignored issues
show
Documentation Bug introduced by
It seems like true of type true is incompatible with the declared type object of property $activated.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
112
113
        $this->enableRendering();
114
115
        if (!$this->debugbar) {
116
                $this->debugbar = new StandardDebugBar();
117
                $this->renderer = $this->debugbar->getJavascriptRenderer();
118
119
                //$this->debugbar->addCollector(new MessagesCollector('Errors'));
120
                $this->debugbar->addCollector(new MessagesCollector('Deprecated'));
121
                $this->debugbar->addCollector(new MessagesCollector('Blocks'));
122
                $this->debugbar->addCollector(new MessagesCollector('Extra'));
123
                //$this->debugbar->addCollector(new MessagesCollector('Queries'));
124
125
                $xoops = Xoops::getInstance();
126
                $debugStack = $xoops->db()->getConfiguration()->getSQLLogger();
127
                $this->debugbar->addCollector(new DebugBar\Bridge\DoctrineCollector($debugStack));
128
                //$this->debugbar->setStorage(new DebugBar\Storage\FileStorage(\XoopsBaseConfig::get('var-path').'/debugbar'));
129
        }
130
        $this->addToTheme();
131
    }
132
133
    /**
134
     * report enabled status
135
     *
136
     * @return bool
137
     */
138
    public function isEnable()
139
    {
140
        return $this->activated;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->activated returns the type object which is incompatible with the documented return type boolean.
Loading history...
141
    }
142
143
    /**
144
     * disable output for the benefit of ajax scripts
145
     *
146
     * @return void
147
     */
148
    public function quiet()
149
    {
150
        //$this->debugbar->sendDataInHeaders();
151
        $this->quietmode = true;
0 ignored issues
show
Documentation Bug introduced by
It seems like true of type true is incompatible with the declared type object of property $quietmode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
152
    }
153
154
    /**
155
     * Add our resources to the theme as soon as it is available, otherwise return
156
     *
157
     * @return void
158
     */
159
    private function addToTheme()
160
    {
161
        static $addedResource = false;
162
163
        if ($this->activated && !$addedResource) {
164
            if (isset($GLOBALS['xoTheme'])) {
165
                // get asset information provided by debugbar
166
                // don't include vendors - jquery already available, need workaround for font-awesome
167
                $this->renderer->setIncludeVendors(true);
168
                $this->renderer->setEnableJqueryNoConflict(false);
169
                list($cssAssets, $jsAssets) = $this->renderer->getAssets();
170
171
                // font-awesome requires some special handling with cssmin
172
                // see: https://code.google.com/p/cssmin/issues/detail?id=52&q=font
173
                // using our own copy of full css instead of minified version packaged
174
                // with debugbar avoids the issue.
175
176
                // Supress unwanted assets - exclude anything containing these strings
177
                $excludes = array(
178
                    //'/vendor/font-awesome/', // font-awesome needs special process
179
                    //'/vendor/highlightjs/',  // highlightjs has some negative side effects
180
                    '/vendor/jquery/',       // jquery is already available
181
                );
182
183
                $cssAssets = array_filter(
184
                    $cssAssets,
185
                    function ($filename) use ($excludes) {
186
                        foreach ($excludes as $exclude) {
187
                            if (false !== strpos($filename, $exclude)) {
188
                                return false;
189
                            }
190
                        }
191
                        return true;
192
                    }
193
                );
194
195
                $jsAssets = array_filter(
196
                    $jsAssets,
197
                    function ($filename) use ($excludes) {
198
                        foreach ($excludes as $exclude) {
199
                            if (false !== strpos($filename, $exclude)) {
200
                                return false;
201
                            }
202
                        }
203
                        return true;
204
                    }
205
                );
206
                //$cssAssets[] = 'modules/debugbar/assets/css/font-awesome.css';
207
208
                $xoops = Xoops::getInstance();
209
                $xoops->theme()->addStylesheetAssets($cssAssets, 'cssembed,?cssmin');
210
                $xoops->theme()->addScriptAssets($jsAssets, '?jsmin');
211
212
                $addedResource = true;
213
            }
214
        }
215
    }
216
217
    /**
218
     * Start a timer
219
     *
220
     * @param string      $name  name of the timer
221
     * @param string|null $label optional label for this timer
222
     *
223
     * @return void
224
     */
225
    public function startTime($name = 'XOOPS', $label = null)
226
    {
227
        if ($this->activated) {
228
            try {
229
                $this->debugbar['time']->startMeasure($name, $label);
230
            } catch (Throwable $e) {
231
                $this->addException($e);
232
            }
233
        }
234
    }
235
236
    /**
237
     * Stop a timer
238
     *
239
     * @param string $name name of the timer
240
     *
241
     * @return void
242
     */
243
    public function stopTime($name = 'XOOPS')
244
    {
245
        $this->addToTheme();
246
247
        if ($this->activated) {
248
            try {
249
                $this->debugbar['time']->stopMeasure($name);
250
            } catch (Throwable $e) {
251
                $this->addException($e);
252
            }
253
        }
254
    }
255
256
    /**
257
     * Log a database query
258
     *
259
     * @param string $sql        sql that was processed
260
     * @param string $error      error message
261
     * @param int    $errno      error number
262
     * @param float  $query_time execution time
263
     *
264
     * @return void
265
     */
266
    public function addQuery($sql, $error = null, $errno = null, $query_time = null)
267
    {
268
        if ($this->activated) {
269
            $level = LogLevel::INFO;
270
            if (!empty($error)) {
271
                $level = LogLevel::ERROR;
272
            }
273
            $context = array(
274
                'channel'=>'Queries',
275
                'error'=>$error,
276
                'errno'=>$errno,
277
                'query_time'=>$query_time
278
            );
279
            $this->log($level, $sql, $context);
280
        }
281
    }
282
283
    /**
284
     * Log display of a block
285
     *
286
     * @param string $name      name of the block
287
     * @param bool   $cached    was the block cached?
288
     * @param int    $cachetime cachetime of the block
289
     *
290
     * @return void
291
     */
292
    public function addBlock($name, $cached = false, $cachetime = 0)
293
    {
294
        if ($this->activated) {
295
            $context = array('channel'=>'Blocks', 'cached'=>$cached, 'cachetime'=>$cachetime);
296
            $this->log(LogLevel::INFO, $name, $context);
297
        }
298
    }
299
300
    /**
301
     * Log extra information
302
     *
303
     * @param string $name name for the entry
304
     * @param string $msg  text message for the entry
305
     *
306
     * @return void
307
     */
308
    public function addExtra($name, $msg)
309
    {
310
        if ($this->activated) {
311
            $context = array('channel'=>'Extra', 'name'=>$name);
312
            $this->log(LogLevel::INFO, $msg, $context);
313
        }
314
    }
315
316
    /**
317
     * Log messages for deprecated functions
318
     *
319
     * @param string $msg name for the entry
320
     *
321
     * @return void
322
     */
323
    public function addDeprecated($msg)
324
    {
325
        if ($this->activated) {
326
            $this->log(LogLevel::WARNING, $msg, array('channel'=>'Deprecated'));
327
        }
328
    }
329
330
    /**
331
     * Log exceptions
332
     *
333
     * @param Exception $e name for the entry
334
     *
335
     * @return void
336
     */
337
    public function addException($e)
338
    {
339
        if ($this->activated) {
340
            $this->debugbar['exceptions']->addThrowable($e);
341
        }
342
    }
343
344
    /**
345
     * Dump Smarty variables
346
     *
347
     * @return void
348
     */
349
    public function addSmarty()
350
    {
351
        if ($this->activated) {
352
            $data = Xoops::getInstance()->tpl()->getTemplateVars();
0 ignored issues
show
Bug introduced by
The method getTemplateVars() does not exist on Xoops\Core\XoopsTpl. ( Ignorable by Annotation )

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

352
            $data = Xoops::getInstance()->tpl()->/** @scrutinizer ignore-call */ getTemplateVars();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
353
            // fix values that don't display properly
354
            foreach ($data as $k => $v) {
355
                if ($v === '') {
356
                    $data[$k] = '(empty string)';
357
                } elseif ($v === null) {
358
                    $data[$k] = 'NULL';
359
                } elseif ($v === true) { // just to be consistent with false
360
                    $data[$k] = 'bool TRUE';
361
                } elseif ($v === false) {
362
                    $data[$k] = 'bool FALSE';
363
                }
364
            }
365
            ksort($data, SORT_NATURAL | SORT_FLAG_CASE);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type null; however, parameter $array of ksort() does only seem to accept array, 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

365
            ksort(/** @scrutinizer ignore-type */ $data, SORT_NATURAL | SORT_FLAG_CASE);
Loading history...
366
            $this->debugbar->addCollector(
367
                new DebugBar\DataCollector\ConfigCollector($data, 'Smarty')
368
            );
369
        }
370
    }
371
372
    /**
373
     * Dump a variable to the messages pane
374
     *
375
     * @param mixed $var variable to dump
376
     *
377
     * @return void
378
     */
379
    public function dump($var)
380
    {
381
        $this->log(LogLevel::DEBUG, $var);
382
    }
383
384
    /**
385
     * stackData - stash log data before a redirect
386
     *
387
     * @return void
388
     */
389
    public function stackData()
390
    {
391
        if ($this->activated) {
392
            $this->debugbar->stackData();
393
            $this->activated=false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type object of property $activated.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
394
            $this->renderingEnabled = false;
0 ignored issues
show
Bug Best Practice introduced by
The property renderingEnabled does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
395
        }
396
    }
397
398
    /**
399
     * Enable logger output rendering
400
     * When output rendering is enabled, the logger will insert its output within the page content.
401
     * If the string <!--<xo-logger-output>--> is found in the page content, the logger output will
402
     * replace it, otherwise it will be inserted after all the page output.
403
     *
404
     * @return void
405
     */
406
    public function enableRendering()
407
    {
408
        $this->renderingEnabled = true;
0 ignored issues
show
Bug Best Practice introduced by
The property renderingEnabled does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
409
    }
410
411
    /**
412
     * Output buffering callback inserting logger dump in page output
413
     *
414
     * @param string $output output buffer to add logger rendering to
415
     *
416
     * @return string output
417
     */
418
    public function render($output)
419
    {
420
        if (!$this->activated) {
421
            return $output;
422
        }
423
424
        $xoops = Xoops::getInstance();
425
        $head = '</script>'.$this->renderer->renderHead().'<script>';
426
        $xoops->theme()->addScript(null, null, $head);
427
428
        $log = $this->renderer->render();
429
        $this->renderingEnabled = $this->activated = false;
0 ignored issues
show
Bug Best Practice introduced by
The property renderingEnabled does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type object of property $activated.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
430
431
        $pattern = '<!--<xo-logger-output>-->';
432
        $pos = strpos($output, $pattern);
433
        if ($pos !== false) {
434
            return substr($output, 0, $pos) . $log . substr($output, $pos + strlen($pattern));
435
        } else {
436
            return $output . $log;
437
        }
438
    }
439
440
    /**
441
     * dump everything we have  // was __destruct()
442
     */
443
    public function renderDebugBar()
444
    {
445
        if ($this->activated) {
446
            // include any queued time data from Xmf\Debug
447
            $queue = \Xmf\Debug::dumpQueuedTimers(true);
448
            if (!empty($queue)) {
449
                foreach ($queue as $q) {
450
                    $this->debugbar['time']->addMeasure($q['label'], $q['start'], $q['start'] + $q['elapsed']);
451
                }
452
            }
453
            $this->addToTheme();
454
            $this->addExtra(_MD_DEBUGBAR_PHP_VERSION, PHP_VERSION);
455
            $this->addExtra(_MD_DEBUGBAR_INCLUDED_FILES, (string) count(get_included_files()));
456
            $conn = \Xoops::getInstance()->db()->getWrappedConnection();
457
            if ($conn instanceof \PDO) {
458
                $this->addExtra(
459
                    $conn->getAttribute(\PDO::ATTR_DRIVER_NAME) . ' version',
460
                    $conn->getAttribute(\PDO::ATTR_SERVER_VERSION)
461
                );
462
                $this->addExtra(
463
                    $conn->getAttribute(\PDO::ATTR_DRIVER_NAME) . ' stats',
464
                    $conn->getAttribute(\PDO::ATTR_SERVER_INFO)
465
                );
466
            }
467
468
            if (false === $this->quietmode) {
0 ignored issues
show
introduced by
The condition false === $this->quietmode is always false.
Loading history...
469
                if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])
470
                    && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
471
                    // default for ajax, do not initialize a new toolbar, just add dataset
472
                    $log = $this->renderer->render(false);
473
                } else {
474
                    $log = $this->renderer->render();
475
                }
476
                echo $log;
477
            } else {
478
                $this->debugbar->sendDataInHeaders();
479
            }
480
        }
481
    }
482
483
    /**
484
     * PSR-3 System is unusable.
485
     *
486
     * @param string $message message
487
     * @param array  $context array of additional context
488
     *
489
     * @return null
490
     */
491
    public function emergency($message, array $context = array())
492
    {
493
        if ($this->activated) {
494
            $this->log(LogLevel::EMERGENCY, $message, $context);
495
        }
496
    }
497
498
    /**
499
     * PSR-3 Action must be taken immediately.
500
     *
501
     * Example: Entire website down, database unavailable, etc. This should
502
     * trigger the SMS alerts and wake you up.
503
     *
504
     * @param string $message message
505
     * @param array  $context array of additional context
506
     *
507
     * @return null
508
     */
509
    public function alert($message, array $context = array())
510
    {
511
        if ($this->activated) {
512
            $this->log(LogLevel::ALERT, $message, $context);
513
        }
514
    }
515
516
    /**
517
     * PSR-3 Critical conditions.
518
     *
519
     * Example: Application component unavailable, unexpected exception.
520
     *
521
     * @param string $message message
522
     * @param array  $context array of additional context
523
     *
524
     * @return null
525
     */
526
    public function critical($message, array $context = array())
527
    {
528
        if ($this->activated) {
529
            $this->log(LogLevel::CRITICAL, $message, $context);
530
        }
531
    }
532
533
    /**
534
     * PSR-3 Runtime errors that do not require immediate action but should typically
535
     * be logged and monitored.
536
     *
537
     * @param string $message message
538
     * @param array  $context array of additional context
539
     *
540
     * @return null
541
     */
542
    public function error($message, array $context = array())
543
    {
544
        if ($this->activated) {
545
            $this->log(LogLevel::ERROR, $message, $context);
546
        }
547
    }
548
549
    /**
550
     * PSR-3 Exceptional occurrences that are not errors.
551
     *
552
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
553
     * that are not necessarily wrong.
554
     *
555
     * @param string $message message
556
     * @param array  $context array of additional context
557
     *
558
     * @return null
559
     */
560
    public function warning($message, array $context = array())
561
    {
562
        if ($this->activated) {
563
            $this->log(LogLevel::WARNING, $message, $context);
564
        }
565
    }
566
567
    /**
568
     * PSR-3 Normal but significant events.
569
     *
570
     * @param string $message message
571
     * @param array  $context array of additional context
572
     *
573
     * @return null
574
     */
575
    public function notice($message, array $context = array())
576
    {
577
        if ($this->activated) {
578
            $this->log(LogLevel::NOTICE, $message, $context);
579
        }
580
    }
581
582
    /**
583
     * PSR-3 Interesting events.
584
     *
585
     * Example: User logs in, SQL logs.
586
     *
587
     * @param string $message message
588
     * @param array  $context array of additional context
589
     *
590
     * @return null
591
     */
592
    public function info($message, array $context = array())
593
    {
594
        if ($this->activated) {
595
            $this->log(LogLevel::INFO, $message, $context);
596
        }
597
    }
598
599
    /**
600
     * PSR-3 Detailed debug information.
601
     *
602
     * @param string $message message
603
     * @param array  $context array of additional context
604
     *
605
     * @return null
606
     */
607
    public function debug($message, array $context = array())
608
    {
609
        if ($this->activated) {
610
            $this->log(LogLevel::DEBUG, $message, $context);
611
        }
612
    }
613
614
    /**
615
     * PSR-3 Logs with an arbitrary level.
616
     *
617
     * @param mixed  $level   logging level
618
     * @param string $message message
619
     * @param array  $context array of additional context
620
     *
621
     * @return null
622
     */
623
    public function log($level, $message, array $context = array())
624
    {
625
        if (!$this->activated) {
626
            return;
627
        }
628
629
        $channel = 'messages';
630
        $msg = $message;
631
632
        /**
633
         * If we have embedded channel in the context array, format the message
634
         * approriatly using context values.
635
         */
636
        if (isset($context['channel'])) {
637
            $chan = strtolower($context['channel']);
638
            switch ($chan) {
639
                case 'blocks':
640
                    $channel = 'Blocks';
641
                    $msg = $message . ': ';
642
                    if ($context['cached']) {
643
                        $msg .= sprintf(_MD_DEBUGBAR_CACHED, (int)($context['cachetime']));
644
                    } else {
645
                        $msg .= _MD_DEBUGBAR_NOT_CACHED;
646
                    }
647
                    break;
648
                case 'deprecated':
649
                    $channel = 'Deprecated';
650
                    $msg = $message;
651
                    break;
652
                case 'extra':
653
                    $channel = 'Extra';
654
                    $msg = $context['name'] . ': ' . $message;
655
                    break;
656
                case 'queries':
657
                    $channel = 'Queries';
658
                    $msg = $message;
659
                    $qt = empty($context['query_time']) ?
660
                        '' : sprintf('%0.6f - ', $context['query_time']);
661
                    if ($level == LogLevel::ERROR) {
662
                        //if (!is_scalar($context['errno']) ||  !is_scalar($context['errno'])) {
663
                        //    \Xmf\Debug::dump($context);
664
                        //}
665
                        $msg .= ' -- Error number: '
666
                            . (is_scalar($context['errno']) ?  $context['errno'] : '?')
667
                            . ' Error message: '
668
                            . (is_scalar($context['error']) ?  $context['error'] : '?');
669
                    }
670
                    $msg = $qt . $msg;
671
                    break;
672
            }
673
        }
674
        switch ($level) {
675
            case LogLevel::EMERGENCY:
676
                $this->debugbar[$channel]->emergency($msg);
677
                break;
678
            case LogLevel::ALERT:
679
                $this->debugbar[$channel]->alert($msg);
680
                break;
681
            case LogLevel::CRITICAL:
682
                $this->debugbar[$channel]->critical($msg);
683
                break;
684
            case LogLevel::ERROR:
685
                $this->debugbar[$channel]->error($msg);
686
                break;
687
            case LogLevel::WARNING:
688
                $this->debugbar[$channel]->warning($msg);
689
                break;
690
            case LogLevel::NOTICE:
691
                $this->debugbar[$channel]->notice($msg);
692
                break;
693
            case LogLevel::INFO:
694
                $this->debugbar[$channel]->info($msg);
695
                break;
696
            case LogLevel::DEBUG:
697
            default:
698
                $this->debugbar[$channel]->debug($msg);
699
                break;
700
        }
701
    }
702
}
703