xref: /plugin/combo/ComboStrap/LogUtility.php (revision 370d7a6ca27033c1f10c64be6427a3f5960adef8)
1<?php
2/**
3 * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved.
4 *
5 * This source code is licensed under the GPL license found in the
6 * COPYING  file in the root directory of this source tree.
7 *
8 * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
9 * @author   ComboStrap <support@combostrap.com>
10 *
11 */
12
13namespace ComboStrap;
14
15require_once(__DIR__ . '/PluginUtility.php');
16
17class LogUtility
18{
19
20    /**
21     * Constant for the function {@link msg()}
22     * -1 = error, 0 = info, 1 = success, 2 = notify
23     * (Not even in order of importance)
24     */
25    const LVL_MSG_ERROR = 4; //-1;
26    const LVL_MSG_WARNING = 3; //2;
27    const LVL_MSG_SUCCESS = 2; //1;
28    const LVL_MSG_INFO = 1; //0;
29    const LVL_MSG_DEBUG = 0; //3;
30
31
32    /**
33     * Id level to name
34     */
35    const LVL_NAME = array(
36        0 => "debug",
37        1 => "info",
38        3 => "warning",
39        2 => "success",
40        4 => "error"
41    );
42
43    /**
44     * Id level to name
45     * {@link msg()} constant
46     */
47    const LVL_TO_MSG_LEVEL = array(
48        0 => 3,
49        1 => 0,
50        2 => 1,
51        3 => 2,
52        4 => -1
53    );
54
55
56    const LOGLEVEL_URI_QUERY_PROPERTY = "loglevel";
57
58    /**
59     * Send a message to a manager and log it
60     * Fail if in test
61     * @param string $message
62     * @param int $level - the level see LVL constant
63     * @param string $canonical - the canonical
64     */
65    public static function msg(string $message, int $level = self::LVL_MSG_ERROR, string $canonical = "support")
66    {
67
68        try {
69            self::messageNotEmpty($message);
70        } catch (ExceptionCombo $e) {
71            self::log2file($e->getMessage(), LogUtility::LVL_MSG_ERROR, $canonical);
72        }
73
74        /**
75         * Log to frontend
76         */
77        self::log2FrontEnd($message, $level, $canonical);
78
79        /**
80         * Log level passed for a page (only for file used)
81         * to not allow an attacker to see all errors in frontend
82         */
83        global $INPUT;
84        $loglevelProp = $INPUT->str(self::LOGLEVEL_URI_QUERY_PROPERTY, null);
85        if (!empty($loglevelProp)) {
86            $level = $loglevelProp;
87        }
88        /**
89         * TODO: Make it a configuration ?
90         */
91        if ($level >= self::LVL_MSG_WARNING) {
92            self::log2file($message, $level, $canonical);
93        }
94
95        /**
96         * If test, we throw an error
97         */
98        self::throwErrorIfTest($level, $message);
99    }
100
101    /**
102     * Print log to a  file
103     *
104     * Adapted from {@link dbglog}
105     * Note: {@link dbg()} dbg print to the web page
106     *
107     * @param string $msg
108     * @param int $logLevel
109     * @param null $canonical
110     */
111    static function log2file(string $msg, int $logLevel = self::LVL_MSG_INFO, $canonical = null)
112    {
113
114        try {
115            self::messageNotEmpty($msg);
116        } catch (ExceptionCombo $e) {
117            $msg = $e->getMessage();
118            $logLevel = self::LVL_MSG_ERROR;
119        }
120
121        if (PluginUtility::isTest() || $logLevel >= self::LVL_MSG_WARNING) {
122
123            $prefix = PluginUtility::$PLUGIN_NAME;
124            if (!empty($canonical)) {
125                $prefix .= ' - ' . $canonical;
126            }
127            $msg = $prefix . ' - ' . $msg;
128
129            global $INPUT;
130            global $conf;
131
132            /**
133             * Adding page - context information
134             * We are not using {@link Page::createPageFromRequestedPage()}
135             * because it throws an error message when the environment
136             * is not good, creating a recursive call.
137             */
138            $id = PluginUtility::getMainPageDokuwikiId();
139
140            $file = $conf['cachedir'] . '/debug.log';
141            $fh = fopen($file, 'a');
142            if ($fh) {
143                $sep = " - ";
144                fwrite($fh, date('c') . $sep . self::LVL_NAME[$logLevel] . $sep . $msg . $sep . $INPUT->server->str('REMOTE_ADDR') . $sep . $id . "\n");
145                fclose($fh);
146            }
147
148
149            self::throwErrorIfTest($logLevel, $msg);
150
151
152        }
153
154    }
155
156    /**
157     * @param $message
158     * @param $level
159     * @param string $canonical
160     * @param bool $withIconURL
161     */
162    public static function log2FrontEnd($message, $level, $canonical = "support", $withIconURL = true)
163    {
164
165        try {
166            self::messageNotEmpty($message);
167        } catch (ExceptionCombo $e) {
168            $message = $e->getMessage();
169            $level = self::LVL_MSG_ERROR;
170        }
171
172        /**
173         * If we are not in the console
174         * and not in test
175         * we test that the message comes in the front end
176         * (example {@link \plugin_combo_frontmatter_test}
177         */
178        $isTerminal = Console::isConsoleRun();
179        if ($isTerminal) {
180            if (!defined('DOKU_UNITTEST')) {
181                /**
182                 * such as {@link cli_plugin_combo}
183                 */
184                $userAgent = "cli";
185            } else {
186                $userAgent = "phpunit";
187            }
188        } else {
189            $userAgent = "browser";
190        }
191
192        switch ($userAgent) {
193            case "cli":
194                echo "$message\n";
195                break;
196            case "phpunit":
197            case "browser":
198            default:
199                $htmlMsg = PluginUtility::getDocumentationHyperLink("", PluginUtility::$PLUGIN_NAME, $withIconURL);
200                if ($canonical != null) {
201                    $htmlMsg = PluginUtility::getDocumentationHyperLink($canonical, ucfirst(str_replace(":", " ", $canonical)));
202                }
203
204                /**
205                 * Adding page - context information
206                 * We are not creating the page
207                 * direction from {@link Page::createPageFromRequestedPage()}
208                 * because it throws an error message when the environment
209                 * is not good, creating a recursive call.
210                 */
211                $id = PluginUtility::getMainPageDokuwikiId();
212                if ($id != null) {
213
214                    /**
215                     * We don't use any Page object to not
216                     * create a cycle while building it
217                     */
218                    $url = wl($id, [], true);
219                    $htmlMsg .= " - <a href=\"$url\">$id</a>";
220
221                }
222
223                /**
224                 *
225                 */
226                $htmlMsg .= " - " . $message;
227                if ($level > self::LVL_MSG_DEBUG) {
228                    $dokuWikiLevel = self::LVL_TO_MSG_LEVEL[$level];
229                    msg($htmlMsg, $dokuWikiLevel, '', '', MSG_USERS_ONLY);
230                }
231        }
232    }
233
234    /**
235     * Log a message to the browser console
236     * @param $message
237     */
238    public static function log2BrowserConsole($message)
239    {
240        // TODO
241    }
242
243    private static function throwErrorIfTest($level, $message)
244    {
245        if (PluginUtility::isTest()
246            && ($level >= self::LVL_MSG_WARNING)
247        ) {
248            throw new LogException($message);
249        }
250    }
251
252    /**
253     * @param string $message
254     * @throws ExceptionCombo
255     */
256    private static function messageNotEmpty(string $message)
257    {
258        $message = trim($message);
259        if ($message === "" || $message === null) {
260            $newMessage = "The passed message to the log was empty or null. BackTrace: \n";
261            ob_start();
262            debug_print_backtrace();
263            $trace = ob_get_contents();
264            ob_end_clean();
265            $newMessage .= $trace;
266            throw new ExceptionCombo($newMessage);
267        }
268    }
269}
270