diff options
author | Morris Jobke <hey@morrisjobke.de> | 2018-04-11 14:24:47 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-11 14:24:47 +0200 |
commit | 7a3ce073dac286eedfa3003c4f8567827cd5f10b (patch) | |
tree | 85eff08ff7778eb06e11dc7689c6705d07232d0d /lib/private/Log.php | |
parent | 0dabb26cc2e03e4aa96665fab28c02bb61132cad (diff) | |
parent | 15815c034f8f3720208e492713c79df8b0bc6e46 (diff) | |
download | nextcloud-server-7a3ce073dac286eedfa3003c4f8567827cd5f10b.tar.gz nextcloud-server-7a3ce073dac286eedfa3003c4f8567827cd5f10b.zip |
Merge pull request #8946 from nextcloud/log-exceptions-as-nested-array-2
Log exceptions as nested array instead of encoded json
Diffstat (limited to 'lib/private/Log.php')
-rw-r--r-- | lib/private/Log.php | 134 |
1 files changed, 90 insertions, 44 deletions
diff --git a/lib/private/Log.php b/lib/private/Log.php index e47f68807d3..2c2b7ccb08d 100644 --- a/lib/private/Log.php +++ b/lib/private/Log.php @@ -37,6 +37,7 @@ namespace OC; use InterfaSys\LogNormalizer\Normalizer; +use OC\Log\File; use OCP\ILogger; use OCP\Support\CrashReport\IRegistry; use OCP\Util; @@ -50,7 +51,6 @@ use OCP\Util; * * MonoLog is an example implementing this interface. */ - class Log implements ILogger { /** @var string */ @@ -78,7 +78,7 @@ class Log implements ILogger { 'updatePrivateKeyPassword', 'validateUserPass', 'loginWithToken', - '\{closure\}', + '{closure}', // TokenProvider 'getToken', @@ -120,14 +120,14 @@ class Log implements ILogger { */ public function __construct($logger = null, SystemConfig $config = null, $normalizer = null, IRegistry $registry = null) { // FIXME: Add this for backwards compatibility, should be fixed at some point probably - if($config === null) { + if ($config === null) { $config = \OC::$server->getSystemConfig(); } $this->config = $config; // FIXME: Add this for backwards compatibility, should be fixed at some point probably - if($logger === null) { + if ($logger === null) { $logType = $this->config->getValue('log_type', 'file'); $this->logger = static::getLogClass($logType); call_user_func([$this->logger, 'init']); @@ -251,61 +251,50 @@ class Log implements ILogger { * @return void */ public function log(int $level, string $message, array $context = []) { - $minLevel = min($this->config->getValue('loglevel', Util::WARN), Util::FATAL); - $logCondition = $this->config->getValue('log.condition', []); + $minLevel = $this->getLogLevel($context); array_walk($context, [$this->normalizer, 'format']); - if (isset($context['app'])) { - $app = $context['app']; - - /** - * check log condition based on the context of each log message - * once this is met -> change the required log level to debug - */ - if(!empty($logCondition) - && isset($logCondition['apps']) - && in_array($app, $logCondition['apps'], true)) { - $minLevel = Util::DEBUG; - } + $app = $context['app'] ?? 'no app in context'; - } else { - $app = 'no app in context'; - } // interpolate $message as defined in PSR-3 $replace = []; foreach ($context as $key => $val) { $replace['{' . $key . '}'] = $val; } - - // interpolate replacement values into the message and return $message = strtr($message, $replace); + if ($level >= $minLevel) { + $this->writeLog($app, $message, $level); + } + } + + private function getLogLevel($context) { /** * check for a special log condition - this enables an increased log on * a per request/user base */ - if($this->logConditionSatisfied === null) { + if ($this->logConditionSatisfied === null) { // default to false to just process this once per request $this->logConditionSatisfied = false; - if(!empty($logCondition)) { + if (!empty($logCondition)) { // check for secret token in the request - if(isset($logCondition['shared_secret'])) { + if (isset($logCondition['shared_secret'])) { $request = \OC::$server->getRequest(); // if token is found in the request change set the log condition to satisfied - if($request && hash_equals($logCondition['shared_secret'], $request->getParam('log_secret', ''))) { + if ($request && hash_equals($logCondition['shared_secret'], $request->getParam('log_secret', ''))) { $this->logConditionSatisfied = true; } } // check for user - if(isset($logCondition['users'])) { + if (isset($logCondition['users'])) { $user = \OC::$server->getUserSession()->getUser(); // if the user matches set the log condition to satisfied - if($user !== null && in_array($user->getUID(), $logCondition['users'], true)) { + if ($user !== null && in_array($user->getUID(), $logCondition['users'], true)) { $this->logConditionSatisfied = true; } } @@ -313,14 +302,55 @@ class Log implements ILogger { } // if log condition is satisfied change the required log level to DEBUG - if($this->logConditionSatisfied) { - $minLevel = Util::DEBUG; + if ($this->logConditionSatisfied) { + return Util::DEBUG; } - if ($level >= $minLevel) { - $logger = $this->logger; - call_user_func([$logger, 'write'], $app, $message, $level); + if (isset($context['app'])) { + $logCondition = $this->config->getValue('log.condition', []); + $app = $context['app']; + + /** + * check log condition based on the context of each log message + * once this is met -> change the required log level to debug + */ + if (!empty($logCondition) + && isset($logCondition['apps']) + && in_array($app, $logCondition['apps'], true)) { + return Util::DEBUG; + } } + + return min($this->config->getValue('loglevel', Util::WARN), Util::FATAL); + } + + private function filterTrace(array $trace) { + $sensitiveValues = []; + $trace = array_map(function (array $traceLine) use (&$sensitiveValues) { + foreach ($this->methodsWithSensitiveParameters as $sensitiveMethod) { + if (strpos($traceLine['function'], $sensitiveMethod) !== false) { + $sensitiveValues = array_merge($sensitiveValues, $traceLine['args']); + $traceLine['args'] = ['*** sensitive parameters replaced ***']; + return $traceLine; + } + } + return $traceLine; + }, $trace); + return array_map(function (array $traceLine) use ($sensitiveValues) { + $traceLine['args'] = $this->removeValuesFromArgs($traceLine['args'], $sensitiveValues); + return $traceLine; + }, $trace); + } + + private function removeValuesFromArgs($args, $values) { + foreach($args as &$arg) { + if (in_array($arg, $values, true)) { + $arg = '*** sensitive parameter replaced ***'; + } else if (is_array($arg)) { + $arg = $this->removeValuesFromArgs($arg, $values); + } + } + return $args; } /** @@ -332,26 +362,33 @@ class Log implements ILogger { * @since 8.2.0 */ public function logException(\Throwable $exception, array $context = []) { - $level = Util::ERROR; - if (isset($context['level'])) { - $level = $context['level']; - unset($context['level']); - } + $app = $context['app'] ?? 'no app in context'; + $level = $context['level'] ?? Util::ERROR; + $data = [ + 'CustomMessage' => $context['message'] ?? '--', 'Exception' => get_class($exception), 'Message' => $exception->getMessage(), 'Code' => $exception->getCode(), - 'Trace' => $exception->getTraceAsString(), + 'Trace' => $this->filterTrace($exception->getTrace()), 'File' => $exception->getFile(), 'Line' => $exception->getLine(), ]; - $data['Trace'] = preg_replace('!(' . implode('|', $this->methodsWithSensitiveParameters) . ')\(.*\)!', '$1(*** sensitive parameters replaced ***)', $data['Trace']); if ($exception instanceof HintException) { $data['Hint'] = $exception->getHint(); } - $msg = isset($context['message']) ? $context['message'] : 'Exception'; - $msg .= ': ' . json_encode($data); - $this->log($level, $msg, $context); + + $minLevel = $this->getLogLevel($context); + + array_walk($context, [$this->normalizer, 'format']); + + if ($level >= $minLevel) { + if ($this->logger !== File::class) { + $data = json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR); + } + $this->writeLog($app, $data, $level); + } + $context['level'] = $level; if (!is_null($this->crashReporters)) { $this->crashReporters->delegateReport($exception, $context); @@ -359,6 +396,15 @@ class Log implements ILogger { } /** + * @param string $app + * @param string|array $entry + * @param int $level + */ + protected function writeLog(string $app, $entry, int $level) { + call_user_func([$this->logger, 'write'], $app, $entry, $level); + } + + /** * @param string $logType * @return string * @internal |