xref: /plugin/combo/ComboStrap/LogUtility.php (revision d61dea15956dd9566667ba7f10483feb8f216dc5)
137748cd8SNickeau<?php
237748cd8SNickeau/**
337748cd8SNickeau * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved.
437748cd8SNickeau *
537748cd8SNickeau * This source code is licensed under the GPL license found in the
637748cd8SNickeau * COPYING  file in the root directory of this source tree.
737748cd8SNickeau *
837748cd8SNickeau * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
937748cd8SNickeau * @author   ComboStrap <support@combostrap.com>
1037748cd8SNickeau *
1137748cd8SNickeau */
1237748cd8SNickeau
1337748cd8SNickeaunamespace ComboStrap;
1437748cd8SNickeau
1537748cd8SNickeaurequire_once(__DIR__ . '/PluginUtility.php');
1637748cd8SNickeau
1737748cd8SNickeauclass LogUtility
1837748cd8SNickeau{
1937748cd8SNickeau
2037748cd8SNickeau    /**
2137748cd8SNickeau     * Constant for the function {@link msg()}
2237748cd8SNickeau     * -1 = error, 0 = info, 1 = success, 2 = notify
2337748cd8SNickeau     * (Not even in order of importance)
2437748cd8SNickeau     */
2537748cd8SNickeau    const LVL_MSG_ERROR = 4; //-1;
2637748cd8SNickeau    const LVL_MSG_WARNING = 3; //2;
2737748cd8SNickeau    const LVL_MSG_SUCCESS = 2; //1;
2837748cd8SNickeau    const LVL_MSG_INFO = 1; //0;
2937748cd8SNickeau    const LVL_MSG_DEBUG = 0; //3;
3037748cd8SNickeau
3137748cd8SNickeau
3237748cd8SNickeau    /**
3337748cd8SNickeau     * Id level to name
3437748cd8SNickeau     */
3537748cd8SNickeau    const LVL_NAME = array(
3637748cd8SNickeau        0 => "debug",
3737748cd8SNickeau        1 => "info",
3837748cd8SNickeau        3 => "warning",
3937748cd8SNickeau        2 => "success",
4037748cd8SNickeau        4 => "error"
4137748cd8SNickeau    );
4237748cd8SNickeau
4337748cd8SNickeau    /**
4437748cd8SNickeau     * Id level to name
4537748cd8SNickeau     * {@link msg()} constant
4637748cd8SNickeau     */
4737748cd8SNickeau    const LVL_TO_MSG_LEVEL = array(
4837748cd8SNickeau        0 => 3,
4937748cd8SNickeau        1 => 0,
5037748cd8SNickeau        2 => 1,
5137748cd8SNickeau        3 => 2,
5237748cd8SNickeau        4 => -1
5337748cd8SNickeau    );
5437748cd8SNickeau
5537748cd8SNickeau
5637748cd8SNickeau    const LOGLEVEL_URI_QUERY_PROPERTY = "loglevel";
5737748cd8SNickeau
5837748cd8SNickeau    /**
5937748cd8SNickeau     * Send a message to a manager and log it
6037748cd8SNickeau     * Fail if in test
6137748cd8SNickeau     * @param string $message
6237748cd8SNickeau     * @param int $level - the level see LVL constant
6337748cd8SNickeau     * @param string $canonical - the canonical
6437748cd8SNickeau     */
65c3437056SNickeau    public static function msg(string $message, int $level = self::LVL_MSG_ERROR, string $canonical = "support")
6637748cd8SNickeau    {
6737748cd8SNickeau
68*d61dea15Sgerardnico        try {
69*d61dea15Sgerardnico            self::messageNotEmpty($message);
70*d61dea15Sgerardnico        } catch (ExceptionCombo $e) {
71*d61dea15Sgerardnico            self::log2file($e->getMessage(), LogUtility::LVL_MSG_ERROR, $canonical);
72e7bbc4b8Sgerardnico        }
73e7bbc4b8Sgerardnico
7437748cd8SNickeau        /**
7537748cd8SNickeau         * Log to frontend
7637748cd8SNickeau         */
77c3437056SNickeau        self::log2FrontEnd($message, $level, $canonical);
7837748cd8SNickeau
7937748cd8SNickeau        /**
8037748cd8SNickeau         * Log level passed for a page (only for file used)
8137748cd8SNickeau         * to not allow an attacker to see all errors in frontend
8237748cd8SNickeau         */
8337748cd8SNickeau        global $INPUT;
8437748cd8SNickeau        $loglevelProp = $INPUT->str(self::LOGLEVEL_URI_QUERY_PROPERTY, null);
8537748cd8SNickeau        if (!empty($loglevelProp)) {
8637748cd8SNickeau            $level = $loglevelProp;
8737748cd8SNickeau        }
882f4da794Sgerardnico        /**
892f4da794Sgerardnico         * TODO: Make it a configuration ?
902f4da794Sgerardnico         */
912f4da794Sgerardnico        if ($level >= self::LVL_MSG_WARNING) {
9237748cd8SNickeau            self::log2file($message, $level, $canonical);
932f4da794Sgerardnico        }
9437748cd8SNickeau
9537748cd8SNickeau        /**
9637748cd8SNickeau         * If test, we throw an error
9737748cd8SNickeau         */
98c3437056SNickeau        self::throwErrorIfTest($level, $message);
9937748cd8SNickeau    }
10037748cd8SNickeau
10137748cd8SNickeau    /**
10237748cd8SNickeau     * Print log to a  file
10337748cd8SNickeau     *
10437748cd8SNickeau     * Adapted from {@link dbglog}
10537748cd8SNickeau     * Note: {@link dbg()} dbg print to the web page
10637748cd8SNickeau     *
10737748cd8SNickeau     * @param string $msg
10837748cd8SNickeau     * @param int $logLevel
10937748cd8SNickeau     * @param null $canonical
11037748cd8SNickeau     */
111*d61dea15Sgerardnico    static function log2file(string $msg, int $logLevel = self::LVL_MSG_INFO, $canonical = null)
11237748cd8SNickeau    {
11337748cd8SNickeau
114*d61dea15Sgerardnico        try {
115*d61dea15Sgerardnico            self::messageNotEmpty($msg);
116*d61dea15Sgerardnico        } catch (ExceptionCombo $e) {
117*d61dea15Sgerardnico            $msg = $e->getMessage();
118*d61dea15Sgerardnico            $logLevel = self::LVL_MSG_ERROR;
119*d61dea15Sgerardnico        }
120*d61dea15Sgerardnico
121c3437056SNickeau        if (PluginUtility::isTest() || $logLevel >= self::LVL_MSG_WARNING) {
12237748cd8SNickeau
12337748cd8SNickeau            $prefix = PluginUtility::$PLUGIN_NAME;
12437748cd8SNickeau            if (!empty($canonical)) {
12537748cd8SNickeau                $prefix .= ' - ' . $canonical;
12637748cd8SNickeau            }
12737748cd8SNickeau            $msg = $prefix . ' - ' . $msg;
12837748cd8SNickeau
12937748cd8SNickeau            global $INPUT;
13037748cd8SNickeau            global $conf;
13137748cd8SNickeau
132c3437056SNickeau            /**
133c3437056SNickeau             * Adding page - context information
134c3437056SNickeau             * We are not using {@link Page::createPageFromRequestedPage()}
135c3437056SNickeau             * because it throws an error message when the environment
136c3437056SNickeau             * is not good, creating a recursive call.
137c3437056SNickeau             */
138c3437056SNickeau            $id = PluginUtility::getMainPageDokuwikiId();
13937748cd8SNickeau
14037748cd8SNickeau            $file = $conf['cachedir'] . '/debug.log';
14137748cd8SNickeau            $fh = fopen($file, 'a');
14237748cd8SNickeau            if ($fh) {
14337748cd8SNickeau                $sep = " - ";
14437748cd8SNickeau                fwrite($fh, date('c') . $sep . self::LVL_NAME[$logLevel] . $sep . $msg . $sep . $INPUT->server->str('REMOTE_ADDR') . $sep . $id . "\n");
14537748cd8SNickeau                fclose($fh);
14637748cd8SNickeau            }
147c3437056SNickeau
148c3437056SNickeau
149c3437056SNickeau            self::throwErrorIfTest($logLevel, $msg);
150c3437056SNickeau
151c3437056SNickeau
15237748cd8SNickeau        }
15337748cd8SNickeau
15437748cd8SNickeau    }
15537748cd8SNickeau
15637748cd8SNickeau    /**
15737748cd8SNickeau     * @param $message
15837748cd8SNickeau     * @param $level
159*d61dea15Sgerardnico     * @param string $canonical
16037748cd8SNickeau     * @param bool $withIconURL
16137748cd8SNickeau     */
16237748cd8SNickeau    public static function log2FrontEnd($message, $level, $canonical = "support", $withIconURL = true)
16337748cd8SNickeau    {
164*d61dea15Sgerardnico
165*d61dea15Sgerardnico        try {
166*d61dea15Sgerardnico            self::messageNotEmpty($message);
167*d61dea15Sgerardnico        } catch (ExceptionCombo $e) {
168*d61dea15Sgerardnico            $message = $e->getMessage();
169*d61dea15Sgerardnico            $level = self::LVL_MSG_ERROR;
170*d61dea15Sgerardnico        }
171*d61dea15Sgerardnico
17237748cd8SNickeau        /**
17337748cd8SNickeau         * If we are not in the console
17437748cd8SNickeau         * and not in test
17537748cd8SNickeau         * we test that the message comes in the front end
17637748cd8SNickeau         * (example {@link \plugin_combo_frontmatter_test}
17737748cd8SNickeau         */
178c3437056SNickeau        $isTerminal = Console::isConsoleRun();
179c3437056SNickeau        if ($isTerminal) {
18037748cd8SNickeau            if (!defined('DOKU_UNITTEST')) {
181c3437056SNickeau                /**
182c3437056SNickeau                 * such as {@link cli_plugin_combo}
183c3437056SNickeau                 */
184c3437056SNickeau                $userAgent = "cli";
185c3437056SNickeau            } else {
186c3437056SNickeau                $userAgent = "phpunit";
18737748cd8SNickeau            }
188c3437056SNickeau        } else {
189c3437056SNickeau            $userAgent = "browser";
19037748cd8SNickeau        }
191c3437056SNickeau
192c3437056SNickeau        switch ($userAgent) {
193c3437056SNickeau            case "cli":
194c3437056SNickeau                echo "$message\n";
195c3437056SNickeau                break;
196c3437056SNickeau            case "phpunit":
197c3437056SNickeau            case "browser":
198c3437056SNickeau            default:
199c3437056SNickeau                $htmlMsg = PluginUtility::getDocumentationHyperLink("", PluginUtility::$PLUGIN_NAME, $withIconURL);
20037748cd8SNickeau                if ($canonical != null) {
201c3437056SNickeau                    $htmlMsg = PluginUtility::getDocumentationHyperLink($canonical, ucfirst(str_replace(":", " ", $canonical)));
20237748cd8SNickeau                }
20337748cd8SNickeau
20437748cd8SNickeau                /**
20537748cd8SNickeau                 * Adding page - context information
20637748cd8SNickeau                 * We are not creating the page
207c3437056SNickeau                 * direction from {@link Page::createPageFromRequestedPage()}
20837748cd8SNickeau                 * because it throws an error message when the environment
20937748cd8SNickeau                 * is not good, creating a recursive call.
21037748cd8SNickeau                 */
211c3437056SNickeau                $id = PluginUtility::getMainPageDokuwikiId();
21237748cd8SNickeau                if ($id != null) {
213c3437056SNickeau
214c3437056SNickeau                    /**
215c3437056SNickeau                     * We don't use any Page object to not
216c3437056SNickeau                     * create a cycle while building it
217c3437056SNickeau                     */
218c3437056SNickeau                    $url = wl($id, [], true);
219c3437056SNickeau                    $htmlMsg .= " - <a href=\"$url\">$id</a>";
220c3437056SNickeau
22137748cd8SNickeau                }
22237748cd8SNickeau
22337748cd8SNickeau                /**
22437748cd8SNickeau                 *
22537748cd8SNickeau                 */
22637748cd8SNickeau                $htmlMsg .= " - " . $message;
22737748cd8SNickeau                if ($level > self::LVL_MSG_DEBUG) {
22837748cd8SNickeau                    $dokuWikiLevel = self::LVL_TO_MSG_LEVEL[$level];
22937748cd8SNickeau                    msg($htmlMsg, $dokuWikiLevel, '', '', MSG_USERS_ONLY);
23037748cd8SNickeau                }
23137748cd8SNickeau        }
23237748cd8SNickeau    }
23337748cd8SNickeau
23437748cd8SNickeau    /**
23537748cd8SNickeau     * Log a message to the browser console
23637748cd8SNickeau     * @param $message
23737748cd8SNickeau     */
23837748cd8SNickeau    public static function log2BrowserConsole($message)
23937748cd8SNickeau    {
24037748cd8SNickeau        // TODO
24137748cd8SNickeau    }
242c3437056SNickeau
243c3437056SNickeau    private static function throwErrorIfTest($level, $message)
244c3437056SNickeau    {
245c3437056SNickeau        if (PluginUtility::isTest()
246c3437056SNickeau            && ($level >= self::LVL_MSG_WARNING)
247c3437056SNickeau        ) {
248c3437056SNickeau            throw new LogException($message);
249c3437056SNickeau        }
250c3437056SNickeau    }
251*d61dea15Sgerardnico
252*d61dea15Sgerardnico    /**
253*d61dea15Sgerardnico     * @param string $message
254*d61dea15Sgerardnico     * @throws ExceptionCombo
255*d61dea15Sgerardnico     */
256*d61dea15Sgerardnico    private static function messageNotEmpty(string $message)
257*d61dea15Sgerardnico    {
258*d61dea15Sgerardnico        $message = trim($message);
259*d61dea15Sgerardnico        if ($message === "" || $message === null) {
260*d61dea15Sgerardnico            $newMessage = "The passed message to the log was empty or null. BackTrace: \n";
261*d61dea15Sgerardnico            ob_start();
262*d61dea15Sgerardnico            debug_print_backtrace();
263*d61dea15Sgerardnico            $trace = ob_get_contents();
264*d61dea15Sgerardnico            ob_end_clean();
265*d61dea15Sgerardnico            $newMessage .= $trace;
266*d61dea15Sgerardnico            throw new ExceptionCombo($newMessage);
267*d61dea15Sgerardnico        }
268*d61dea15Sgerardnico    }
26937748cd8SNickeau}
270