/** * Log message * * @param string $message */ public static function log($level, $message) { // If message is other than scalar (object, array) then print_r it and log individual lines if (!is_scalar($message)) { foreach (explode("\n", print_r($message, true)) as $line) { self::log($level, $line); } return; } // Setup facilities if not already done self::setup(); // Default log level is error so that log calls without level will always be processed if (LogLevels::isValidValue($level) && !array_key_exists($level, self::$levels)) { $level = LogLevels::ERROR; } // Add call context data if level is debug if ($level == LogLevels::DEBUG) { // Fecth call stack $stack = debug_backtrace(); // Remove Logger internals while ($stack && array_key_exists('class', $stack[0]) && $stack[0]['class'] == 'Logger') { array_shift($stack); } // If call context is known if ($stack && array_key_exists('function', $stack[0]) && $stack[0]['function']) { $caller = $stack[0]; // Gather code location data $s = ''; if (array_key_exists('file', $caller)) { $s .= $caller['file'] . ':' . $caller['line'] . ' '; } if (array_key_exists('class', $caller)) { if (!array_key_exists('type', $caller)) { $caller['type'] = ' '; } if ($caller['type'] == '::') { $s .= $caller['class'] . '::'; } else { $s .= '(' . $caller['class'] . ')' . $caller['type']; } } // Resolve magics so that log is easier to read if (in_array($caller['function'], array('__call', '__callStatic'))) { $caller['function'] = $caller['args'][0]; $caller['args'] = $caller['args'][1]; } // Add arguments (objects are mentionned as just "object" without details) $args = array(); foreach ($caller['args'] as $arg) { $a = ''; if (is_bool($arg)) { $a = $arg ? '(true)' : '(false)'; } else { if (is_scalar($arg)) { $a = '(' . $arg . ')'; } else { if (is_array($arg)) { $a = array(); foreach ($arg as $k => $v) { $a[] = (is_numeric($k) ? '' : $k . ' => ') . gettype($v) . (is_scalar($v) ? is_bool($v) ? $v ? '(true)' : '(false)' : '(' . $v . ')' : ''); } $a = '(' . implode(', ', $a) . ')'; } } } $args[] = gettype($arg) . $a; } $s .= $caller['function'] . '(' . implode(', ', $args) . ')'; $message = $s . ' ' . $message; } } // Add authenticated user id if any, except in debug mode as line is already long if (self::$process != ProcessTypes::UPGRADE) { try { // No user id in log if we are recording a low level exception // as it may end up in throwing another one while getting // user / user id and create a loop ... $risky_exception = count(array_filter(debug_backtrace(), function ($t) { return array_key_exists('class', $t) && preg_match('`^(Core|Config|DBI).+Exception$`', $t['class']); })); if ($level != LogLevels::DEBUG && !$risky_exception && Auth::user()) { $message = '[user ' . Auth::user()->id . '] ' . $message; } } catch (Exception $e) { } } // Build final message ... $message = '[' . self::$process . ':' . $level . '] ' . $message; // ... and give it to defined facilities foreach (self::$facilities as $facility) { // Filter based on process if facility requires it if (array_key_exists('process', $facility)) { $accepted = array_filter(array_map('trim', preg_split('`[\\s,|]`', $facility['process']))); if (!in_array('*', $accepted) && !in_array(self::$process, $accepted)) { continue; } } // Filter based on level if facility requires it if (array_key_exists('level', $facility)) { $max = self::$levels[$facility['level']]; if (self::$levels[$level] > $max) { continue; } } // Forward to facility related method with config $method = get_called_class() . '::' . $facility['method']; call_user_func($method, $facility, $level, $message); } }
/** * Log message * * @param LogLevels $level The log level * @param string $message The message */ public static function log($level, $message) { if (!is_scalar($message)) { foreach (explode("\n", print_r($message, true)) as $line) { self::log($level, $line); } return; } self::setup(); //TODO: test level if (LogLevels::isValidValue($level) && !array_key_exists($level, self::$levels)) { $level = LogLevels::ERROR; } if ($level == LogLevels::DEBUG) { $stack = debug_backtrace(); while ($stack && array_key_exists('class', $stack[0]) && $stack[0]['class'] == 'Logger') { array_shift($stack); } if ($stack && array_key_exists('function', $stack[0]) && $stack[0]['function']) { $caller = $stack[0]; $s = $caller['file'] . ':' . $caller['line'] . ' '; if (array_key_exists('class', $caller)) { if (!array_key_exists('type', $caller)) { $caller['type'] = ' '; } if ($caller['type'] == '::') { $s .= $caller['class'] . '::'; } else { $s .= '(' . $caller['class'] . ')' . $caller['type']; } } if (in_array($caller['function'], array('__call', '__callStatic'))) { $caller['function'] = $caller['args'][0]; $caller['args'] = $caller['args'][1]; } $args = array(); foreach ($caller['args'] as $arg) { $a = ''; if (is_bool($arg)) { $a = $arg ? '(true)' : '(false)'; } else { if (is_scalar($arg)) { $a = '(' . $arg . ')'; } else { if (is_array($arg)) { $a = array(); foreach ($arg as $k => $v) { $a[] = (is_numeric($k) ? '' : $k . ' => ') . gettype($v) . (is_scalar($v) ? is_bool($v) ? $v ? '(true)' : '(false)' : '(' . $v . ')' : ''); } $a = '(' . implode(', ', $a) . ')'; } } } $args[] = gettype($arg) . $a; } $s .= $caller['function'] . '(' . implode(', ', $args) . ')'; $message = $s . ' ' . $message; } } try { $dbiexception = count(array_filter(debug_backtrace(), function ($t) { return array_key_exists('class', $t) && preg_match('`^DBI.+Exception$`', $t['class']); })); if ($level != LogLevels::DEBUG && !$dbiexception && Auth::isAuthenticated()) { $message = '[user ' . Auth::user()->email . '] ' . $message; } } catch (Exception $e) { } $message = '[' . self::$process . ':' . $level . '] ' . $message; foreach (self::$facilities as $facility) { if (array_key_exists('process', $facility)) { $accepted = array_filter(array_map('trim', preg_split('`[\\s,|]`', $facility['process']))); if (!in_array('*', $accepted) && !in_array(self::$process, $accepted)) { continue; } } if (array_key_exists('level', $facility)) { $max = self::$levels[$facility['level']]; if (self::$levels[$level] > $max) { continue; } } $method = get_called_class() . '::' . $facility['method']; call_user_func($method, $facility, $level, $message); } }