Completed
Push — stable8.2 ( 19b835...fb943f )
by Morris
74:57
created

Log::error()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1
Metric Value
dl 0
loc 3
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 2
crap 1
1
<?php
2
/**
3
 * @author Bart Visscher <[email protected]>
4
 * @author Bernhard Posselt <[email protected]>
5
 * @author Morris Jobke <[email protected]>
6
 * @author Olivier Paroz <[email protected]>
7
 * @author Robin Appelman <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 * @author Victor Dubiniuk <[email protected]>
10
 *
11
 * @copyright Copyright (c) 2015, ownCloud, Inc.
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OC;
29
30
use InterfaSys\LogNormalizer\Normalizer;
31
32
use \OCP\ILogger;
33
use OCP\Security\StringUtils;
34
35
/**
36
 * logging utilities
37
 *
38
 * This is a stand in, this should be replaced by a Psr\Log\LoggerInterface
39
 * compatible logger. See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
40
 * for the full interface specification.
41
 *
42
 * MonoLog is an example implementing this interface.
43
 */
44
45
class Log implements ILogger {
46
47
	/** @var string */
48
	private $logger;
49
	/** @var SystemConfig */
50
	private $config;
51
52
	/** @var boolean|null cache the result of the log condition check for the request */
53
	private $logConditionSatisfied = null;
54
	/** @var Normalizer */
55
	private $normalizer;
56
57
	/**
58
	 * @param string $logger The logger that should be used
59
	 * @param SystemConfig $config the system config object
60
	 * @param null $normalizer
61
	 */
62 163
	public function __construct($logger=null, SystemConfig $config=null, $normalizer = null) {
63
		// FIXME: Add this for backwards compatibility, should be fixed at some point probably
64 163
		if($config === null) {
65 143
			$config = \OC::$server->getSystemConfig();
66 143
		}
67
68 163
		$this->config = $config;
69
70
		// FIXME: Add this for backwards compatibility, should be fixed at some point probably
71 163
		if($logger === null) {
72 126
			$this->logger = 'OC_Log_'.ucfirst($this->config->getValue('log_type', 'owncloud'));
73 126
			call_user_func(array($this->logger, 'init'));
74 126
		} else {
75 37
			$this->logger = $logger;
76
		}
77 163
		if ($normalizer === null) {
78 163
			$this->normalizer = new Normalizer();
79 163
		} else {
80
			$this->normalizer = $normalizer;
81
		}
82
83 163
	}
84
85
86
	/**
87
	 * System is unusable.
88
	 *
89
	 * @param string $message
90
	 * @param array $context
91
	 */
92
	public function emergency($message, array $context = array()) {
93
		$this->log(\OCP\Util::FATAL, $message, $context);
94
	}
95
96
	/**
97
	 * Action must be taken immediately.
98
	 *
99
	 * Example: Entire website down, database unavailable, etc. This should
100
	 * trigger the SMS alerts and wake you up.
101
	 *
102
	 * @param string $message
103
	 * @param array $context
104
	 */
105
	public function alert($message, array $context = array()) {
106
		$this->log(\OCP\Util::ERROR, $message, $context);
107
	}
108
109
	/**
110
	 * Critical conditions.
111
	 *
112
	 * Example: Application component unavailable, unexpected exception.
113
	 *
114
	 * @param string $message
115
	 * @param array $context
116
	 */
117
	public function critical($message, array $context = array()) {
118
		$this->log(\OCP\Util::ERROR, $message, $context);
119
	}
120
121
	/**
122
	 * Runtime errors that do not require immediate action but should typically
123
	 * be logged and monitored.
124
	 *
125
	 * @param string $message
126
	 * @param array $context
127
	 */
128 18
	public function error($message, array $context = array()) {
129 18
		$this->log(\OCP\Util::ERROR, $message, $context);
130 18
	}
131
132
	/**
133
	 * Exceptional occurrences that are not errors.
134
	 *
135
	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
136
	 * that are not necessarily wrong.
137
	 *
138
	 * @param string $message
139
	 * @param array $context
140
	 */
141 8
	public function warning($message, array $context = array()) {
142 8
		$this->log(\OCP\Util::WARN, $message, $context);
143 8
	}
144
145
	/**
146
	 * Normal but significant events.
147
	 *
148
	 * @param string $message
149
	 * @param array $context
150
	 */
151 2
	public function notice($message, array $context = array()) {
152 2
		$this->log(\OCP\Util::INFO, $message, $context);
153 2
	}
154
155
	/**
156
	 * Interesting events.
157
	 *
158
	 * Example: User logs in, SQL logs.
159
	 *
160
	 * @param string $message
161
	 * @param array $context
162
	 */
163 4
	public function info($message, array $context = array()) {
164 4
		$this->log(\OCP\Util::INFO, $message, $context);
165 4
	}
166
167
	/**
168
	 * Detailed debug information.
169
	 *
170
	 * @param string $message
171
	 * @param array $context
172
	 */
173 226
	public function debug($message, array $context = array()) {
174 226
		$this->log(\OCP\Util::DEBUG, $message, $context);
175 226
	}
176
177
178
	/**
179
	 * Logs with an arbitrary level.
180
	 *
181
	 * @param mixed $level
182
	 * @param string $message
183
	 * @param array $context
184
	 */
185 849
	public function log($level, $message, array $context = array()) {
186 849
		$minLevel = min($this->config->getValue('loglevel', \OCP\Util::WARN), \OCP\Util::ERROR);
187 849
		$logCondition = $this->config->getValue('log.condition', []);
188
189 849
		array_walk($context, [$this->normalizer, 'format']);
190
191 849
		if (isset($context['app'])) {
192 830
			$app = $context['app'];
193
194
			/**
195
			 * check log condition based on the context of each log message
196
			 * once this is met -> change the required log level to debug
197
			 */
198 830
			if(!empty($logCondition)
199 830
				&& isset($logCondition['apps'])
200 830
				&& in_array($app, $logCondition['apps'], true)) {
201 1
				$minLevel = \OCP\Util::DEBUG;
202 1
			}
203
204 830
		} else {
205 20
			$app = 'no app in context';
206
		}
207
		// interpolate $message as defined in PSR-3
208 849
		$replace = array();
209 849
		foreach ($context as $key => $val) {
210 831
			$replace['{' . $key . '}'] = $val;
211 849
		}
212
213
		// interpolate replacement values into the message and return
214 849
		$message = strtr($message, $replace);
215
216
		/**
217
		 * check for a special log condition - this enables an increased log on
218
		 * a per request/user base
219
		 */
220 849
		if($this->logConditionSatisfied === null) {
221
			// default to false to just process this once per request
222 21
			$this->logConditionSatisfied = false;
223 21
			if(!empty($logCondition)) {
224
225
				// check for secret token in the request
226 1
				if(isset($logCondition['shared_secret'])) {
227
					$request = \OC::$server->getRequest();
228
229
					// if token is found in the request change set the log condition to satisfied
230
					if($request && StringUtils::equals($request->getParam('log_secret'), $logCondition['shared_secret'])) {
231
						$this->logConditionSatisfied = true;
232
					}
233
				}
234
235
				// check for user
236 1
				if(isset($logCondition['users'])) {
237
					$user = \OC::$server->getUserSession()->getUser();
238
239
					// if the user matches set the log condition to satisfied
240
					if($user !== null && in_array($user->getUID(), $logCondition['users'], true)) {
241
						$this->logConditionSatisfied = true;
242
					}
243
				}
244 1
			}
245 21
		}
246
247
		// if log condition is satisfied change the required log level to DEBUG
248 849
		if($this->logConditionSatisfied) {
249
			$minLevel = \OCP\Util::DEBUG;
250
		}
251
252 849
		if ($level >= $minLevel) {
253 120
			$logger = $this->logger;
254 120
			call_user_func(array($logger, 'write'), $app, $message, $level);
255 120
		}
256 849
	}
257
258
	/**
259
	 * Logs an exception very detailed
260
	 *
261
	 * @param \Exception $exception
262
	 * @param array $context
263
	 * @return void
264
	 * @since 8.2.0
265
	 */
266 18
	public function logException(\Exception $exception, array $context = array()) {
267
		$exception = array(
268 18
			'Exception' => get_class($exception),
269 18
			'Message' => $exception->getMessage(),
270 18
			'Code' => $exception->getCode(),
271 18
			'Trace' => $exception->getTraceAsString(),
272 18
			'File' => $exception->getFile(),
273 18
			'Line' => $exception->getLine(),
274 18
		);
275 18
		$exception['Trace'] = preg_replace('!(login|checkPassword)\(.*\)!', '$1(*** username and password replaced ***)', $exception['Trace']);
276 18
		$msg = isset($context['message']) ? $context['message'] : 'Exception';
277 18
		$msg .= ': ' . json_encode($exception);
278 18
		$this->error($msg, $context);
279 18
	}
280
}
281