summaryrefslogtreecommitdiffstats
path: root/lib/private/Log.php
diff options
context:
space:
mode:
authorMorris Jobke <hey@morrisjobke.de>2018-04-11 14:24:47 +0200
committerGitHub <noreply@github.com>2018-04-11 14:24:47 +0200
commit7a3ce073dac286eedfa3003c4f8567827cd5f10b (patch)
tree85eff08ff7778eb06e11dc7689c6705d07232d0d /lib/private/Log.php
parent0dabb26cc2e03e4aa96665fab28c02bb61132cad (diff)
parent15815c034f8f3720208e492713c79df8b0bc6e46 (diff)
downloadnextcloud-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.php134
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