Passed
Push — master ( 7d851f...e6959b )
by Robin
15:52 queued 12s
created
lib/public/Log/BeforeMessageLoggedEvent.php 1 patch
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -31,48 +31,48 @@
 block discarded – undo
31 31
  * @since 28.0.0
32 32
  */
33 33
 class BeforeMessageLoggedEvent extends Event {
34
-	private int $level;
35
-	private string $app;
36
-	private $message;
34
+    private int $level;
35
+    private string $app;
36
+    private $message;
37 37
 
38
-	/**
39
-	 * @since 28.0.0
40
-	 */
41
-	public function __construct(string $app, int $level, $message) {
42
-		$this->level = $level;
43
-		$this->app = $app;
44
-		$this->message = $message;
45
-	}
38
+    /**
39
+     * @since 28.0.0
40
+     */
41
+    public function __construct(string $app, int $level, $message) {
42
+        $this->level = $level;
43
+        $this->app = $app;
44
+        $this->message = $message;
45
+    }
46 46
 
47
-	/**
48
-	 * Get the level of the log item
49
-	 *
50
-	 * @return int
51
-	 * @since 28.0.0
52
-	 */
53
-	public function getLevel(): int {
54
-		return $this->level;
55
-	}
47
+    /**
48
+     * Get the level of the log item
49
+     *
50
+     * @return int
51
+     * @since 28.0.0
52
+     */
53
+    public function getLevel(): int {
54
+        return $this->level;
55
+    }
56 56
 
57 57
 
58
-	/**
59
-	 * Get the app context of the log item
60
-	 *
61
-	 * @return string
62
-	 * @since 28.0.0
63
-	 */
64
-	public function getApp(): string {
65
-		return $this->app;
66
-	}
58
+    /**
59
+     * Get the app context of the log item
60
+     *
61
+     * @return string
62
+     * @since 28.0.0
63
+     */
64
+    public function getApp(): string {
65
+        return $this->app;
66
+    }
67 67
 
68 68
 
69
-	/**
70
-	 * Get the message of the log item
71
-	 *
72
-	 * @return string
73
-	 * @since 28.0.0
74
-	 */
75
-	public function getMessage(): string {
76
-		return $this->message;
77
-	}
69
+    /**
70
+     * Get the message of the log item
71
+     *
72
+     * @return string
73
+     * @since 28.0.0
74
+     */
75
+    public function getMessage(): string {
76
+        return $this->message;
77
+    }
78 78
 }
Please login to merge, or discard this patch.
lib/private/Log.php 1 patch
Indentation   +380 added lines, -380 removed lines patch added patch discarded remove patch
@@ -61,384 +61,384 @@
 block discarded – undo
61 61
  * MonoLog is an example implementing this interface.
62 62
  */
63 63
 class Log implements ILogger, IDataLogger {
64
-	private IWriter $logger;
65
-	private ?SystemConfig $config;
66
-	private ?bool $logConditionSatisfied = null;
67
-	private ?Normalizer $normalizer;
68
-	private ?IRegistry $crashReporters;
69
-	private ?IEventDispatcher $eventDispatcher;
70
-
71
-	/**
72
-	 * @param IWriter $logger The logger that should be used
73
-	 * @param SystemConfig $config the system config object
74
-	 * @param Normalizer|null $normalizer
75
-	 * @param IRegistry|null $registry
76
-	 */
77
-	public function __construct(
78
-		IWriter $logger,
79
-		SystemConfig $config = null,
80
-		Normalizer $normalizer = null,
81
-		IRegistry $registry = null
82
-	) {
83
-		// FIXME: Add this for backwards compatibility, should be fixed at some point probably
84
-		if ($config === null) {
85
-			$config = \OC::$server->getSystemConfig();
86
-		}
87
-
88
-		$this->config = $config;
89
-		$this->logger = $logger;
90
-		if ($normalizer === null) {
91
-			$this->normalizer = new Normalizer();
92
-		} else {
93
-			$this->normalizer = $normalizer;
94
-		}
95
-		$this->crashReporters = $registry;
96
-		$this->eventDispatcher = null;
97
-	}
98
-
99
-	public function setEventDispatcher(IEventDispatcher $eventDispatcher) {
100
-		$this->eventDispatcher = $eventDispatcher;
101
-	}
102
-
103
-	/**
104
-	 * System is unusable.
105
-	 *
106
-	 * @param string $message
107
-	 * @param array $context
108
-	 * @return void
109
-	 */
110
-	public function emergency(string $message, array $context = []) {
111
-		$this->log(ILogger::FATAL, $message, $context);
112
-	}
113
-
114
-	/**
115
-	 * Action must be taken immediately.
116
-	 *
117
-	 * Example: Entire website down, database unavailable, etc. This should
118
-	 * trigger the SMS alerts and wake you up.
119
-	 *
120
-	 * @param string $message
121
-	 * @param array $context
122
-	 * @return void
123
-	 */
124
-	public function alert(string $message, array $context = []) {
125
-		$this->log(ILogger::ERROR, $message, $context);
126
-	}
127
-
128
-	/**
129
-	 * Critical conditions.
130
-	 *
131
-	 * Example: Application component unavailable, unexpected exception.
132
-	 *
133
-	 * @param string $message
134
-	 * @param array $context
135
-	 * @return void
136
-	 */
137
-	public function critical(string $message, array $context = []) {
138
-		$this->log(ILogger::ERROR, $message, $context);
139
-	}
140
-
141
-	/**
142
-	 * Runtime errors that do not require immediate action but should typically
143
-	 * be logged and monitored.
144
-	 *
145
-	 * @param string $message
146
-	 * @param array $context
147
-	 * @return void
148
-	 */
149
-	public function error(string $message, array $context = []) {
150
-		$this->log(ILogger::ERROR, $message, $context);
151
-	}
152
-
153
-	/**
154
-	 * Exceptional occurrences that are not errors.
155
-	 *
156
-	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
157
-	 * that are not necessarily wrong.
158
-	 *
159
-	 * @param string $message
160
-	 * @param array $context
161
-	 * @return void
162
-	 */
163
-	public function warning(string $message, array $context = []) {
164
-		$this->log(ILogger::WARN, $message, $context);
165
-	}
166
-
167
-	/**
168
-	 * Normal but significant events.
169
-	 *
170
-	 * @param string $message
171
-	 * @param array $context
172
-	 * @return void
173
-	 */
174
-	public function notice(string $message, array $context = []) {
175
-		$this->log(ILogger::INFO, $message, $context);
176
-	}
177
-
178
-	/**
179
-	 * Interesting events.
180
-	 *
181
-	 * Example: User logs in, SQL logs.
182
-	 *
183
-	 * @param string $message
184
-	 * @param array $context
185
-	 * @return void
186
-	 */
187
-	public function info(string $message, array $context = []) {
188
-		$this->log(ILogger::INFO, $message, $context);
189
-	}
190
-
191
-	/**
192
-	 * Detailed debug information.
193
-	 *
194
-	 * @param string $message
195
-	 * @param array $context
196
-	 * @return void
197
-	 */
198
-	public function debug(string $message, array $context = []) {
199
-		$this->log(ILogger::DEBUG, $message, $context);
200
-	}
201
-
202
-
203
-	/**
204
-	 * Logs with an arbitrary level.
205
-	 *
206
-	 * @param int $level
207
-	 * @param string $message
208
-	 * @param array $context
209
-	 * @return void
210
-	 */
211
-	public function log(int $level, string $message, array $context = []) {
212
-		$minLevel = $this->getLogLevel($context);
213
-
214
-		array_walk($context, [$this->normalizer, 'format']);
215
-
216
-		$app = $context['app'] ?? 'no app in context';
217
-		$entry = $this->interpolateMessage($context, $message);
218
-
219
-		if ($this->eventDispatcher) {
220
-			$this->eventDispatcher->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $entry));
221
-		}
222
-
223
-		try {
224
-			if ($level >= $minLevel) {
225
-				$this->writeLog($app, $entry, $level);
226
-
227
-				if ($this->crashReporters !== null) {
228
-					$messageContext = array_merge(
229
-						$context,
230
-						[
231
-							'level' => $level
232
-						]
233
-					);
234
-					$this->crashReporters->delegateMessage($entry['message'], $messageContext);
235
-				}
236
-			} else {
237
-				if ($this->crashReporters !== null) {
238
-					$this->crashReporters->delegateBreadcrumb($entry['message'], 'log', $context);
239
-				}
240
-			}
241
-		} catch (Throwable $e) {
242
-			// make sure we dont hard crash if logging fails
243
-		}
244
-	}
245
-
246
-	public function getLogLevel($context) {
247
-		$logCondition = $this->config->getValue('log.condition', []);
248
-
249
-		/**
250
-		 * check for a special log condition - this enables an increased log on
251
-		 * a per request/user base
252
-		 */
253
-		if ($this->logConditionSatisfied === null) {
254
-			// default to false to just process this once per request
255
-			$this->logConditionSatisfied = false;
256
-			if (!empty($logCondition)) {
257
-				// check for secret token in the request
258
-				if (isset($logCondition['shared_secret'])) {
259
-					$request = \OC::$server->getRequest();
260
-
261
-					if ($request->getMethod() === 'PUT' &&
262
-						!str_contains($request->getHeader('Content-Type'), 'application/x-www-form-urlencoded') &&
263
-						!str_contains($request->getHeader('Content-Type'), 'application/json')) {
264
-						$logSecretRequest = '';
265
-					} else {
266
-						$logSecretRequest = $request->getParam('log_secret', '');
267
-					}
268
-
269
-					// if token is found in the request change set the log condition to satisfied
270
-					if ($request && hash_equals($logCondition['shared_secret'], $logSecretRequest)) {
271
-						$this->logConditionSatisfied = true;
272
-					}
273
-				}
274
-
275
-				// check for user
276
-				if (isset($logCondition['users'])) {
277
-					$user = \OC::$server->getUserSession()->getUser();
278
-
279
-					// if the user matches set the log condition to satisfied
280
-					if ($user !== null && in_array($user->getUID(), $logCondition['users'], true)) {
281
-						$this->logConditionSatisfied = true;
282
-					}
283
-				}
284
-			}
285
-		}
286
-
287
-		// if log condition is satisfied change the required log level to DEBUG
288
-		if ($this->logConditionSatisfied) {
289
-			return ILogger::DEBUG;
290
-		}
291
-
292
-		if (isset($context['app'])) {
293
-			$app = $context['app'];
294
-
295
-			/**
296
-			 * check log condition based on the context of each log message
297
-			 * once this is met -> change the required log level to debug
298
-			 */
299
-			if (!empty($logCondition)
300
-				&& isset($logCondition['apps'])
301
-				&& in_array($app, $logCondition['apps'], true)) {
302
-				return ILogger::DEBUG;
303
-			}
304
-		}
305
-
306
-		return min($this->config->getValue('loglevel', ILogger::WARN), ILogger::FATAL);
307
-	}
308
-
309
-	/**
310
-	 * Logs an exception very detailed
311
-	 *
312
-	 * @param Exception|Throwable $exception
313
-	 * @param array $context
314
-	 * @return void
315
-	 * @since 8.2.0
316
-	 */
317
-	public function logException(Throwable $exception, array $context = []) {
318
-		$app = $context['app'] ?? 'no app in context';
319
-		$level = $context['level'] ?? ILogger::ERROR;
320
-
321
-		$minLevel = $this->getLogLevel($context);
322
-		if ($level < $minLevel && ($this->crashReporters === null || !$this->crashReporters->hasReporters())) {
323
-			return;
324
-		}
325
-
326
-		// if an error is raised before the autoloader is properly setup, we can't serialize exceptions
327
-		try {
328
-			$serializer = $this->getSerializer();
329
-		} catch (Throwable $e) {
330
-			$this->error("Failed to load ExceptionSerializer serializer while trying to log " . $exception->getMessage());
331
-			return;
332
-		}
333
-		$data = $context;
334
-		unset($data['app']);
335
-		unset($data['level']);
336
-		$data = array_merge($serializer->serializeException($exception), $data);
337
-		$data = $this->interpolateMessage($data, $context['message'] ?? '--', 'CustomMessage');
338
-
339
-
340
-		array_walk($context, [$this->normalizer, 'format']);
341
-
342
-		if ($this->eventDispatcher) {
343
-			$this->eventDispatcher->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $data));
344
-		}
345
-
346
-		try {
347
-			if ($level >= $minLevel) {
348
-				if (!$this->logger instanceof IFileBased) {
349
-					$data = json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_UNESCAPED_SLASHES);
350
-				}
351
-				$this->writeLog($app, $data, $level);
352
-			}
353
-
354
-			$context['level'] = $level;
355
-			if (!is_null($this->crashReporters)) {
356
-				$this->crashReporters->delegateReport($exception, $context);
357
-			}
358
-		} catch (Throwable $e) {
359
-			// make sure we dont hard crash if logging fails
360
-		}
361
-	}
362
-
363
-	public function logData(string $message, array $data, array $context = []): void {
364
-		$app = $context['app'] ?? 'no app in context';
365
-		$level = $context['level'] ?? ILogger::ERROR;
366
-
367
-		$minLevel = $this->getLogLevel($context);
368
-
369
-		array_walk($context, [$this->normalizer, 'format']);
370
-
371
-		try {
372
-			if ($level >= $minLevel) {
373
-				$data['message'] = $message;
374
-				if (!$this->logger instanceof IFileBased) {
375
-					$data = json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_UNESCAPED_SLASHES);
376
-				}
377
-				$this->writeLog($app, $data, $level);
378
-			}
379
-
380
-			$context['level'] = $level;
381
-		} catch (Throwable $e) {
382
-			// make sure we dont hard crash if logging fails
383
-			error_log('Error when trying to log exception: ' . $e->getMessage() . ' ' . $e->getTraceAsString());
384
-		}
385
-	}
386
-
387
-	/**
388
-	 * @param string $app
389
-	 * @param string|array $entry
390
-	 * @param int $level
391
-	 */
392
-	protected function writeLog(string $app, $entry, int $level) {
393
-		$this->logger->write($app, $entry, $level);
394
-	}
395
-
396
-	public function getLogPath():string {
397
-		if ($this->logger instanceof IFileBased) {
398
-			return $this->logger->getLogFilePath();
399
-		}
400
-		throw new \RuntimeException('Log implementation has no path');
401
-	}
402
-
403
-	/**
404
-	 * Interpolate $message as defined in PSR-3
405
-	 *
406
-	 * Returns an array containing the context without the interpolated
407
-	 * parameters placeholders and the message as the 'message' - or
408
-	 * user-defined - key.
409
-	 */
410
-	private function interpolateMessage(array $context, string $message, string $messageKey = 'message'): array {
411
-		$replace = [];
412
-		$usedContextKeys = [];
413
-		foreach ($context as $key => $val) {
414
-			$fullKey = '{' . $key . '}';
415
-			$replace[$fullKey] = $val;
416
-			if (str_contains($message, $fullKey)) {
417
-				$usedContextKeys[$key] = true;
418
-			}
419
-		}
420
-		return array_merge(array_diff_key($context, $usedContextKeys), [$messageKey => strtr($message, $replace)]);
421
-	}
422
-
423
-	/**
424
-	 * @throws Throwable
425
-	 */
426
-	protected function getSerializer(): ExceptionSerializer {
427
-		$serializer = new ExceptionSerializer($this->config);
428
-		try {
429
-			/** @var Coordinator $coordinator */
430
-			$coordinator = \OCP\Server::get(Coordinator::class);
431
-			foreach ($coordinator->getRegistrationContext()->getSensitiveMethods() as $registration) {
432
-				$serializer->enlistSensitiveMethods($registration->getName(), $registration->getValue());
433
-			}
434
-			// For not every app might be initialized at this time, we cannot assume that the return value
435
-			// of getSensitiveMethods() is complete. Running delegates in Coordinator::registerApps() is
436
-			// not possible due to dependencies on the one hand. On the other it would work only with
437
-			// adding public methods to the PsrLoggerAdapter and this class.
438
-			// Thus, serializer cannot be a property.
439
-		} catch (Throwable $t) {
440
-			// ignore app-defined sensitive methods in this case - they weren't loaded anyway
441
-		}
442
-		return $serializer;
443
-	}
64
+    private IWriter $logger;
65
+    private ?SystemConfig $config;
66
+    private ?bool $logConditionSatisfied = null;
67
+    private ?Normalizer $normalizer;
68
+    private ?IRegistry $crashReporters;
69
+    private ?IEventDispatcher $eventDispatcher;
70
+
71
+    /**
72
+     * @param IWriter $logger The logger that should be used
73
+     * @param SystemConfig $config the system config object
74
+     * @param Normalizer|null $normalizer
75
+     * @param IRegistry|null $registry
76
+     */
77
+    public function __construct(
78
+        IWriter $logger,
79
+        SystemConfig $config = null,
80
+        Normalizer $normalizer = null,
81
+        IRegistry $registry = null
82
+    ) {
83
+        // FIXME: Add this for backwards compatibility, should be fixed at some point probably
84
+        if ($config === null) {
85
+            $config = \OC::$server->getSystemConfig();
86
+        }
87
+
88
+        $this->config = $config;
89
+        $this->logger = $logger;
90
+        if ($normalizer === null) {
91
+            $this->normalizer = new Normalizer();
92
+        } else {
93
+            $this->normalizer = $normalizer;
94
+        }
95
+        $this->crashReporters = $registry;
96
+        $this->eventDispatcher = null;
97
+    }
98
+
99
+    public function setEventDispatcher(IEventDispatcher $eventDispatcher) {
100
+        $this->eventDispatcher = $eventDispatcher;
101
+    }
102
+
103
+    /**
104
+     * System is unusable.
105
+     *
106
+     * @param string $message
107
+     * @param array $context
108
+     * @return void
109
+     */
110
+    public function emergency(string $message, array $context = []) {
111
+        $this->log(ILogger::FATAL, $message, $context);
112
+    }
113
+
114
+    /**
115
+     * Action must be taken immediately.
116
+     *
117
+     * Example: Entire website down, database unavailable, etc. This should
118
+     * trigger the SMS alerts and wake you up.
119
+     *
120
+     * @param string $message
121
+     * @param array $context
122
+     * @return void
123
+     */
124
+    public function alert(string $message, array $context = []) {
125
+        $this->log(ILogger::ERROR, $message, $context);
126
+    }
127
+
128
+    /**
129
+     * Critical conditions.
130
+     *
131
+     * Example: Application component unavailable, unexpected exception.
132
+     *
133
+     * @param string $message
134
+     * @param array $context
135
+     * @return void
136
+     */
137
+    public function critical(string $message, array $context = []) {
138
+        $this->log(ILogger::ERROR, $message, $context);
139
+    }
140
+
141
+    /**
142
+     * Runtime errors that do not require immediate action but should typically
143
+     * be logged and monitored.
144
+     *
145
+     * @param string $message
146
+     * @param array $context
147
+     * @return void
148
+     */
149
+    public function error(string $message, array $context = []) {
150
+        $this->log(ILogger::ERROR, $message, $context);
151
+    }
152
+
153
+    /**
154
+     * Exceptional occurrences that are not errors.
155
+     *
156
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
157
+     * that are not necessarily wrong.
158
+     *
159
+     * @param string $message
160
+     * @param array $context
161
+     * @return void
162
+     */
163
+    public function warning(string $message, array $context = []) {
164
+        $this->log(ILogger::WARN, $message, $context);
165
+    }
166
+
167
+    /**
168
+     * Normal but significant events.
169
+     *
170
+     * @param string $message
171
+     * @param array $context
172
+     * @return void
173
+     */
174
+    public function notice(string $message, array $context = []) {
175
+        $this->log(ILogger::INFO, $message, $context);
176
+    }
177
+
178
+    /**
179
+     * Interesting events.
180
+     *
181
+     * Example: User logs in, SQL logs.
182
+     *
183
+     * @param string $message
184
+     * @param array $context
185
+     * @return void
186
+     */
187
+    public function info(string $message, array $context = []) {
188
+        $this->log(ILogger::INFO, $message, $context);
189
+    }
190
+
191
+    /**
192
+     * Detailed debug information.
193
+     *
194
+     * @param string $message
195
+     * @param array $context
196
+     * @return void
197
+     */
198
+    public function debug(string $message, array $context = []) {
199
+        $this->log(ILogger::DEBUG, $message, $context);
200
+    }
201
+
202
+
203
+    /**
204
+     * Logs with an arbitrary level.
205
+     *
206
+     * @param int $level
207
+     * @param string $message
208
+     * @param array $context
209
+     * @return void
210
+     */
211
+    public function log(int $level, string $message, array $context = []) {
212
+        $minLevel = $this->getLogLevel($context);
213
+
214
+        array_walk($context, [$this->normalizer, 'format']);
215
+
216
+        $app = $context['app'] ?? 'no app in context';
217
+        $entry = $this->interpolateMessage($context, $message);
218
+
219
+        if ($this->eventDispatcher) {
220
+            $this->eventDispatcher->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $entry));
221
+        }
222
+
223
+        try {
224
+            if ($level >= $minLevel) {
225
+                $this->writeLog($app, $entry, $level);
226
+
227
+                if ($this->crashReporters !== null) {
228
+                    $messageContext = array_merge(
229
+                        $context,
230
+                        [
231
+                            'level' => $level
232
+                        ]
233
+                    );
234
+                    $this->crashReporters->delegateMessage($entry['message'], $messageContext);
235
+                }
236
+            } else {
237
+                if ($this->crashReporters !== null) {
238
+                    $this->crashReporters->delegateBreadcrumb($entry['message'], 'log', $context);
239
+                }
240
+            }
241
+        } catch (Throwable $e) {
242
+            // make sure we dont hard crash if logging fails
243
+        }
244
+    }
245
+
246
+    public function getLogLevel($context) {
247
+        $logCondition = $this->config->getValue('log.condition', []);
248
+
249
+        /**
250
+         * check for a special log condition - this enables an increased log on
251
+         * a per request/user base
252
+         */
253
+        if ($this->logConditionSatisfied === null) {
254
+            // default to false to just process this once per request
255
+            $this->logConditionSatisfied = false;
256
+            if (!empty($logCondition)) {
257
+                // check for secret token in the request
258
+                if (isset($logCondition['shared_secret'])) {
259
+                    $request = \OC::$server->getRequest();
260
+
261
+                    if ($request->getMethod() === 'PUT' &&
262
+                        !str_contains($request->getHeader('Content-Type'), 'application/x-www-form-urlencoded') &&
263
+                        !str_contains($request->getHeader('Content-Type'), 'application/json')) {
264
+                        $logSecretRequest = '';
265
+                    } else {
266
+                        $logSecretRequest = $request->getParam('log_secret', '');
267
+                    }
268
+
269
+                    // if token is found in the request change set the log condition to satisfied
270
+                    if ($request && hash_equals($logCondition['shared_secret'], $logSecretRequest)) {
271
+                        $this->logConditionSatisfied = true;
272
+                    }
273
+                }
274
+
275
+                // check for user
276
+                if (isset($logCondition['users'])) {
277
+                    $user = \OC::$server->getUserSession()->getUser();
278
+
279
+                    // if the user matches set the log condition to satisfied
280
+                    if ($user !== null && in_array($user->getUID(), $logCondition['users'], true)) {
281
+                        $this->logConditionSatisfied = true;
282
+                    }
283
+                }
284
+            }
285
+        }
286
+
287
+        // if log condition is satisfied change the required log level to DEBUG
288
+        if ($this->logConditionSatisfied) {
289
+            return ILogger::DEBUG;
290
+        }
291
+
292
+        if (isset($context['app'])) {
293
+            $app = $context['app'];
294
+
295
+            /**
296
+             * check log condition based on the context of each log message
297
+             * once this is met -> change the required log level to debug
298
+             */
299
+            if (!empty($logCondition)
300
+                && isset($logCondition['apps'])
301
+                && in_array($app, $logCondition['apps'], true)) {
302
+                return ILogger::DEBUG;
303
+            }
304
+        }
305
+
306
+        return min($this->config->getValue('loglevel', ILogger::WARN), ILogger::FATAL);
307
+    }
308
+
309
+    /**
310
+     * Logs an exception very detailed
311
+     *
312
+     * @param Exception|Throwable $exception
313
+     * @param array $context
314
+     * @return void
315
+     * @since 8.2.0
316
+     */
317
+    public function logException(Throwable $exception, array $context = []) {
318
+        $app = $context['app'] ?? 'no app in context';
319
+        $level = $context['level'] ?? ILogger::ERROR;
320
+
321
+        $minLevel = $this->getLogLevel($context);
322
+        if ($level < $minLevel && ($this->crashReporters === null || !$this->crashReporters->hasReporters())) {
323
+            return;
324
+        }
325
+
326
+        // if an error is raised before the autoloader is properly setup, we can't serialize exceptions
327
+        try {
328
+            $serializer = $this->getSerializer();
329
+        } catch (Throwable $e) {
330
+            $this->error("Failed to load ExceptionSerializer serializer while trying to log " . $exception->getMessage());
331
+            return;
332
+        }
333
+        $data = $context;
334
+        unset($data['app']);
335
+        unset($data['level']);
336
+        $data = array_merge($serializer->serializeException($exception), $data);
337
+        $data = $this->interpolateMessage($data, $context['message'] ?? '--', 'CustomMessage');
338
+
339
+
340
+        array_walk($context, [$this->normalizer, 'format']);
341
+
342
+        if ($this->eventDispatcher) {
343
+            $this->eventDispatcher->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $data));
344
+        }
345
+
346
+        try {
347
+            if ($level >= $minLevel) {
348
+                if (!$this->logger instanceof IFileBased) {
349
+                    $data = json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_UNESCAPED_SLASHES);
350
+                }
351
+                $this->writeLog($app, $data, $level);
352
+            }
353
+
354
+            $context['level'] = $level;
355
+            if (!is_null($this->crashReporters)) {
356
+                $this->crashReporters->delegateReport($exception, $context);
357
+            }
358
+        } catch (Throwable $e) {
359
+            // make sure we dont hard crash if logging fails
360
+        }
361
+    }
362
+
363
+    public function logData(string $message, array $data, array $context = []): void {
364
+        $app = $context['app'] ?? 'no app in context';
365
+        $level = $context['level'] ?? ILogger::ERROR;
366
+
367
+        $minLevel = $this->getLogLevel($context);
368
+
369
+        array_walk($context, [$this->normalizer, 'format']);
370
+
371
+        try {
372
+            if ($level >= $minLevel) {
373
+                $data['message'] = $message;
374
+                if (!$this->logger instanceof IFileBased) {
375
+                    $data = json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_UNESCAPED_SLASHES);
376
+                }
377
+                $this->writeLog($app, $data, $level);
378
+            }
379
+
380
+            $context['level'] = $level;
381
+        } catch (Throwable $e) {
382
+            // make sure we dont hard crash if logging fails
383
+            error_log('Error when trying to log exception: ' . $e->getMessage() . ' ' . $e->getTraceAsString());
384
+        }
385
+    }
386
+
387
+    /**
388
+     * @param string $app
389
+     * @param string|array $entry
390
+     * @param int $level
391
+     */
392
+    protected function writeLog(string $app, $entry, int $level) {
393
+        $this->logger->write($app, $entry, $level);
394
+    }
395
+
396
+    public function getLogPath():string {
397
+        if ($this->logger instanceof IFileBased) {
398
+            return $this->logger->getLogFilePath();
399
+        }
400
+        throw new \RuntimeException('Log implementation has no path');
401
+    }
402
+
403
+    /**
404
+     * Interpolate $message as defined in PSR-3
405
+     *
406
+     * Returns an array containing the context without the interpolated
407
+     * parameters placeholders and the message as the 'message' - or
408
+     * user-defined - key.
409
+     */
410
+    private function interpolateMessage(array $context, string $message, string $messageKey = 'message'): array {
411
+        $replace = [];
412
+        $usedContextKeys = [];
413
+        foreach ($context as $key => $val) {
414
+            $fullKey = '{' . $key . '}';
415
+            $replace[$fullKey] = $val;
416
+            if (str_contains($message, $fullKey)) {
417
+                $usedContextKeys[$key] = true;
418
+            }
419
+        }
420
+        return array_merge(array_diff_key($context, $usedContextKeys), [$messageKey => strtr($message, $replace)]);
421
+    }
422
+
423
+    /**
424
+     * @throws Throwable
425
+     */
426
+    protected function getSerializer(): ExceptionSerializer {
427
+        $serializer = new ExceptionSerializer($this->config);
428
+        try {
429
+            /** @var Coordinator $coordinator */
430
+            $coordinator = \OCP\Server::get(Coordinator::class);
431
+            foreach ($coordinator->getRegistrationContext()->getSensitiveMethods() as $registration) {
432
+                $serializer->enlistSensitiveMethods($registration->getName(), $registration->getValue());
433
+            }
434
+            // For not every app might be initialized at this time, we cannot assume that the return value
435
+            // of getSensitiveMethods() is complete. Running delegates in Coordinator::registerApps() is
436
+            // not possible due to dependencies on the one hand. On the other it would work only with
437
+            // adding public methods to the PsrLoggerAdapter and this class.
438
+            // Thus, serializer cannot be a property.
439
+        } catch (Throwable $t) {
440
+            // ignore app-defined sensitive methods in this case - they weren't loaded anyway
441
+        }
442
+        return $serializer;
443
+    }
444 444
 }
Please login to merge, or discard this patch.
lib/private/EventDispatcher/EventDispatcher.php 1 patch
Indentation   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -40,77 +40,77 @@
 block discarded – undo
40 40
 use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyDispatcher;
41 41
 
42 42
 class EventDispatcher implements IEventDispatcher {
43
-	/** @var SymfonyDispatcher */
44
-	private $dispatcher;
45
-
46
-	/** @var IContainer */
47
-	private $container;
48
-
49
-	/** @var LoggerInterface */
50
-	private $logger;
51
-
52
-	public function __construct(SymfonyDispatcher $dispatcher,
53
-								IServerContainer $container,
54
-								LoggerInterface $logger) {
55
-		$this->dispatcher = $dispatcher;
56
-		$this->container = $container;
57
-		$this->logger = $logger;
58
-
59
-		// inject the event dispatcher into the logger
60
-		// this is done here because there is a cyclic dependency between the event dispatcher and logger
61
-		if ($this->logger instanceof Log or $this->logger instanceof Log\PsrLoggerAdapter) {
62
-			$this->logger->setEventDispatcher($this);
63
-		}
64
-	}
65
-
66
-	public function addListener(string $eventName,
67
-								callable $listener,
68
-								int $priority = 0): void {
69
-		$this->dispatcher->addListener($eventName, $listener, $priority);
70
-	}
71
-
72
-	public function removeListener(string $eventName,
73
-								   callable $listener): void {
74
-		$this->dispatcher->removeListener($eventName, $listener);
75
-	}
76
-
77
-	public function addServiceListener(string $eventName,
78
-									   string $className,
79
-									   int $priority = 0): void {
80
-		$listener = new ServiceEventListener(
81
-			$this->container,
82
-			$className,
83
-			$this->logger
84
-		);
85
-
86
-		$this->addListener($eventName, $listener, $priority);
87
-	}
88
-
89
-	/**
90
-	 * @deprecated
91
-	 */
92
-	public function dispatch(string $eventName,
93
-							 Event $event): void {
94
-		$this->dispatcher->dispatch($event, $eventName);
95
-
96
-		if ($event instanceof ABroadcastedEvent && !$event->isPropagationStopped()) {
97
-			// Propagate broadcast
98
-			$this->dispatch(
99
-				IBroadcastEvent::class,
100
-				new BroadcastEvent($event)
101
-			);
102
-		}
103
-	}
104
-
105
-	public function dispatchTyped(Event $event): void {
106
-		$this->dispatch(get_class($event), $event);
107
-	}
108
-
109
-	/**
110
-	 * @return SymfonyDispatcher
111
-	 * @deprecated 20.0.0
112
-	 */
113
-	public function getSymfonyDispatcher(): SymfonyDispatcher {
114
-		return $this->dispatcher;
115
-	}
43
+    /** @var SymfonyDispatcher */
44
+    private $dispatcher;
45
+
46
+    /** @var IContainer */
47
+    private $container;
48
+
49
+    /** @var LoggerInterface */
50
+    private $logger;
51
+
52
+    public function __construct(SymfonyDispatcher $dispatcher,
53
+                                IServerContainer $container,
54
+                                LoggerInterface $logger) {
55
+        $this->dispatcher = $dispatcher;
56
+        $this->container = $container;
57
+        $this->logger = $logger;
58
+
59
+        // inject the event dispatcher into the logger
60
+        // this is done here because there is a cyclic dependency between the event dispatcher and logger
61
+        if ($this->logger instanceof Log or $this->logger instanceof Log\PsrLoggerAdapter) {
62
+            $this->logger->setEventDispatcher($this);
63
+        }
64
+    }
65
+
66
+    public function addListener(string $eventName,
67
+                                callable $listener,
68
+                                int $priority = 0): void {
69
+        $this->dispatcher->addListener($eventName, $listener, $priority);
70
+    }
71
+
72
+    public function removeListener(string $eventName,
73
+                                    callable $listener): void {
74
+        $this->dispatcher->removeListener($eventName, $listener);
75
+    }
76
+
77
+    public function addServiceListener(string $eventName,
78
+                                        string $className,
79
+                                        int $priority = 0): void {
80
+        $listener = new ServiceEventListener(
81
+            $this->container,
82
+            $className,
83
+            $this->logger
84
+        );
85
+
86
+        $this->addListener($eventName, $listener, $priority);
87
+    }
88
+
89
+    /**
90
+     * @deprecated
91
+     */
92
+    public function dispatch(string $eventName,
93
+                                Event $event): void {
94
+        $this->dispatcher->dispatch($event, $eventName);
95
+
96
+        if ($event instanceof ABroadcastedEvent && !$event->isPropagationStopped()) {
97
+            // Propagate broadcast
98
+            $this->dispatch(
99
+                IBroadcastEvent::class,
100
+                new BroadcastEvent($event)
101
+            );
102
+        }
103
+    }
104
+
105
+    public function dispatchTyped(Event $event): void {
106
+        $this->dispatch(get_class($event), $event);
107
+    }
108
+
109
+    /**
110
+     * @return SymfonyDispatcher
111
+     * @deprecated 20.0.0
112
+     */
113
+    public function getSymfonyDispatcher(): SymfonyDispatcher {
114
+        return $this->dispatcher;
115
+    }
116 116
 }
Please login to merge, or discard this patch.
lib/private/Log/PsrLoggerAdapter.php 1 patch
Indentation   +220 added lines, -220 removed lines patch added patch discarded remove patch
@@ -36,237 +36,237 @@
 block discarded – undo
36 36
 use function array_merge;
37 37
 
38 38
 final class PsrLoggerAdapter implements LoggerInterface, IDataLogger {
39
-	/** @var Log */
40
-	private $logger;
39
+    /** @var Log */
40
+    private $logger;
41 41
 
42
-	public function __construct(Log $logger) {
43
-		$this->logger = $logger;
44
-	}
42
+    public function __construct(Log $logger) {
43
+        $this->logger = $logger;
44
+    }
45 45
 
46
-	public function setEventDispatcher(IEventDispatcher $eventDispatcher) {
47
-		$this->logger->setEventDispatcher($eventDispatcher);
48
-	}
46
+    public function setEventDispatcher(IEventDispatcher $eventDispatcher) {
47
+        $this->logger->setEventDispatcher($eventDispatcher);
48
+    }
49 49
 
50
-	private function containsThrowable(array $context): bool {
51
-		return array_key_exists('exception', $context) && $context['exception'] instanceof Throwable;
52
-	}
50
+    private function containsThrowable(array $context): bool {
51
+        return array_key_exists('exception', $context) && $context['exception'] instanceof Throwable;
52
+    }
53 53
 
54
-	/**
55
-	 * System is unusable.
56
-	 *
57
-	 * @param string $message
58
-	 * @param array $context
59
-	 *
60
-	 * @return void
61
-	 */
62
-	public function emergency($message, array $context = []): void {
63
-		if ($this->containsThrowable($context)) {
64
-			$this->logger->logException($context['exception'], array_merge(
65
-				[
66
-					'message' => $message,
67
-					'level' => ILogger::FATAL,
68
-				],
69
-				$context
70
-			));
71
-		} else {
72
-			$this->logger->emergency($message, $context);
73
-		}
74
-	}
54
+    /**
55
+     * System is unusable.
56
+     *
57
+     * @param string $message
58
+     * @param array $context
59
+     *
60
+     * @return void
61
+     */
62
+    public function emergency($message, array $context = []): void {
63
+        if ($this->containsThrowable($context)) {
64
+            $this->logger->logException($context['exception'], array_merge(
65
+                [
66
+                    'message' => $message,
67
+                    'level' => ILogger::FATAL,
68
+                ],
69
+                $context
70
+            ));
71
+        } else {
72
+            $this->logger->emergency($message, $context);
73
+        }
74
+    }
75 75
 
76
-	/**
77
-	 * Action must be taken immediately.
78
-	 *
79
-	 * Example: Entire website down, database unavailable, etc. This should
80
-	 * trigger the SMS alerts and wake you up.
81
-	 *
82
-	 * @param string $message
83
-	 * @param array $context
84
-	 *
85
-	 * @return void
86
-	 */
87
-	public function alert($message, array $context = []) {
88
-		if ($this->containsThrowable($context)) {
89
-			$this->logger->logException($context['exception'], array_merge(
90
-				[
91
-					'message' => $message,
92
-					'level' => ILogger::ERROR,
93
-				],
94
-				$context
95
-			));
96
-		} else {
97
-			$this->logger->alert($message, $context);
98
-		}
99
-	}
76
+    /**
77
+     * Action must be taken immediately.
78
+     *
79
+     * Example: Entire website down, database unavailable, etc. This should
80
+     * trigger the SMS alerts and wake you up.
81
+     *
82
+     * @param string $message
83
+     * @param array $context
84
+     *
85
+     * @return void
86
+     */
87
+    public function alert($message, array $context = []) {
88
+        if ($this->containsThrowable($context)) {
89
+            $this->logger->logException($context['exception'], array_merge(
90
+                [
91
+                    'message' => $message,
92
+                    'level' => ILogger::ERROR,
93
+                ],
94
+                $context
95
+            ));
96
+        } else {
97
+            $this->logger->alert($message, $context);
98
+        }
99
+    }
100 100
 
101
-	/**
102
-	 * Critical conditions.
103
-	 *
104
-	 * Example: Application component unavailable, unexpected exception.
105
-	 *
106
-	 * @param string $message
107
-	 * @param array $context
108
-	 *
109
-	 * @return void
110
-	 */
111
-	public function critical($message, array $context = []) {
112
-		if ($this->containsThrowable($context)) {
113
-			$this->logger->logException($context['exception'], array_merge(
114
-				[
115
-					'message' => $message,
116
-					'level' => ILogger::ERROR,
117
-				],
118
-				$context
119
-			));
120
-		} else {
121
-			$this->logger->critical($message, $context);
122
-		}
123
-	}
101
+    /**
102
+     * Critical conditions.
103
+     *
104
+     * Example: Application component unavailable, unexpected exception.
105
+     *
106
+     * @param string $message
107
+     * @param array $context
108
+     *
109
+     * @return void
110
+     */
111
+    public function critical($message, array $context = []) {
112
+        if ($this->containsThrowable($context)) {
113
+            $this->logger->logException($context['exception'], array_merge(
114
+                [
115
+                    'message' => $message,
116
+                    'level' => ILogger::ERROR,
117
+                ],
118
+                $context
119
+            ));
120
+        } else {
121
+            $this->logger->critical($message, $context);
122
+        }
123
+    }
124 124
 
125
-	/**
126
-	 * Runtime errors that do not require immediate action but should typically
127
-	 * be logged and monitored.
128
-	 *
129
-	 * @param string $message
130
-	 * @param array $context
131
-	 *
132
-	 * @return void
133
-	 */
134
-	public function error($message, array $context = []) {
135
-		if ($this->containsThrowable($context)) {
136
-			$this->logger->logException($context['exception'], array_merge(
137
-				[
138
-					'message' => $message,
139
-					'level' => ILogger::ERROR,
140
-				],
141
-				$context
142
-			));
143
-		} else {
144
-			$this->logger->error($message, $context);
145
-		}
146
-	}
125
+    /**
126
+     * Runtime errors that do not require immediate action but should typically
127
+     * be logged and monitored.
128
+     *
129
+     * @param string $message
130
+     * @param array $context
131
+     *
132
+     * @return void
133
+     */
134
+    public function error($message, array $context = []) {
135
+        if ($this->containsThrowable($context)) {
136
+            $this->logger->logException($context['exception'], array_merge(
137
+                [
138
+                    'message' => $message,
139
+                    'level' => ILogger::ERROR,
140
+                ],
141
+                $context
142
+            ));
143
+        } else {
144
+            $this->logger->error($message, $context);
145
+        }
146
+    }
147 147
 
148
-	/**
149
-	 * Exceptional occurrences that are not errors.
150
-	 *
151
-	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
152
-	 * that are not necessarily wrong.
153
-	 *
154
-	 * @param string $message
155
-	 * @param array $context
156
-	 *
157
-	 * @return void
158
-	 */
159
-	public function warning($message, array $context = []) {
160
-		if ($this->containsThrowable($context)) {
161
-			$this->logger->logException($context['exception'], array_merge(
162
-				[
163
-					'message' => $message,
164
-					'level' => ILogger::WARN,
165
-				],
166
-				$context
167
-			));
168
-		} else {
169
-			$this->logger->warning($message, $context);
170
-		}
171
-	}
148
+    /**
149
+     * Exceptional occurrences that are not errors.
150
+     *
151
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
152
+     * that are not necessarily wrong.
153
+     *
154
+     * @param string $message
155
+     * @param array $context
156
+     *
157
+     * @return void
158
+     */
159
+    public function warning($message, array $context = []) {
160
+        if ($this->containsThrowable($context)) {
161
+            $this->logger->logException($context['exception'], array_merge(
162
+                [
163
+                    'message' => $message,
164
+                    'level' => ILogger::WARN,
165
+                ],
166
+                $context
167
+            ));
168
+        } else {
169
+            $this->logger->warning($message, $context);
170
+        }
171
+    }
172 172
 
173
-	/**
174
-	 * Normal but significant events.
175
-	 *
176
-	 * @param string $message
177
-	 * @param array $context
178
-	 *
179
-	 * @return void
180
-	 */
181
-	public function notice($message, array $context = []) {
182
-		if ($this->containsThrowable($context)) {
183
-			$this->logger->logException($context['exception'], array_merge(
184
-				[
185
-					'message' => $message,
186
-					'level' => ILogger::INFO,
187
-				],
188
-				$context
189
-			));
190
-		} else {
191
-			$this->logger->notice($message, $context);
192
-		}
193
-	}
173
+    /**
174
+     * Normal but significant events.
175
+     *
176
+     * @param string $message
177
+     * @param array $context
178
+     *
179
+     * @return void
180
+     */
181
+    public function notice($message, array $context = []) {
182
+        if ($this->containsThrowable($context)) {
183
+            $this->logger->logException($context['exception'], array_merge(
184
+                [
185
+                    'message' => $message,
186
+                    'level' => ILogger::INFO,
187
+                ],
188
+                $context
189
+            ));
190
+        } else {
191
+            $this->logger->notice($message, $context);
192
+        }
193
+    }
194 194
 
195
-	/**
196
-	 * Interesting events.
197
-	 *
198
-	 * Example: User logs in, SQL logs.
199
-	 *
200
-	 * @param string $message
201
-	 * @param array $context
202
-	 *
203
-	 * @return void
204
-	 */
205
-	public function info($message, array $context = []) {
206
-		if ($this->containsThrowable($context)) {
207
-			$this->logger->logException($context['exception'], array_merge(
208
-				[
209
-					'message' => $message,
210
-					'level' => ILogger::INFO,
211
-				],
212
-				$context
213
-			));
214
-		} else {
215
-			$this->logger->info($message, $context);
216
-		}
217
-	}
195
+    /**
196
+     * Interesting events.
197
+     *
198
+     * Example: User logs in, SQL logs.
199
+     *
200
+     * @param string $message
201
+     * @param array $context
202
+     *
203
+     * @return void
204
+     */
205
+    public function info($message, array $context = []) {
206
+        if ($this->containsThrowable($context)) {
207
+            $this->logger->logException($context['exception'], array_merge(
208
+                [
209
+                    'message' => $message,
210
+                    'level' => ILogger::INFO,
211
+                ],
212
+                $context
213
+            ));
214
+        } else {
215
+            $this->logger->info($message, $context);
216
+        }
217
+    }
218 218
 
219
-	/**
220
-	 * Detailed debug information.
221
-	 *
222
-	 * @param string $message
223
-	 * @param array $context
224
-	 *
225
-	 * @return void
226
-	 */
227
-	public function debug($message, array $context = []) {
228
-		if ($this->containsThrowable($context)) {
229
-			$this->logger->logException($context['exception'], array_merge(
230
-				[
231
-					'message' => $message,
232
-					'level' => ILogger::DEBUG,
233
-				],
234
-				$context
235
-			));
236
-		} else {
237
-			$this->logger->debug($message, $context);
238
-		}
239
-	}
219
+    /**
220
+     * Detailed debug information.
221
+     *
222
+     * @param string $message
223
+     * @param array $context
224
+     *
225
+     * @return void
226
+     */
227
+    public function debug($message, array $context = []) {
228
+        if ($this->containsThrowable($context)) {
229
+            $this->logger->logException($context['exception'], array_merge(
230
+                [
231
+                    'message' => $message,
232
+                    'level' => ILogger::DEBUG,
233
+                ],
234
+                $context
235
+            ));
236
+        } else {
237
+            $this->logger->debug($message, $context);
238
+        }
239
+    }
240 240
 
241
-	/**
242
-	 * Logs with an arbitrary level.
243
-	 *
244
-	 * @param mixed $level
245
-	 * @param string $message
246
-	 * @param array $context
247
-	 *
248
-	 * @return void
249
-	 *
250
-	 * @throws InvalidArgumentException
251
-	 */
252
-	public function log($level, $message, array $context = []) {
253
-		if (!is_int($level) || $level < ILogger::DEBUG || $level > ILogger::FATAL) {
254
-			throw new InvalidArgumentException('Nextcloud allows only integer log levels');
255
-		}
256
-		if ($this->containsThrowable($context)) {
257
-			$this->logger->logException($context['exception'], array_merge(
258
-				[
259
-					'message' => $message,
260
-					'level' => $level,
261
-				],
262
-				$context
263
-			));
264
-		} else {
265
-			$this->logger->log($level, $message, $context);
266
-		}
267
-	}
241
+    /**
242
+     * Logs with an arbitrary level.
243
+     *
244
+     * @param mixed $level
245
+     * @param string $message
246
+     * @param array $context
247
+     *
248
+     * @return void
249
+     *
250
+     * @throws InvalidArgumentException
251
+     */
252
+    public function log($level, $message, array $context = []) {
253
+        if (!is_int($level) || $level < ILogger::DEBUG || $level > ILogger::FATAL) {
254
+            throw new InvalidArgumentException('Nextcloud allows only integer log levels');
255
+        }
256
+        if ($this->containsThrowable($context)) {
257
+            $this->logger->logException($context['exception'], array_merge(
258
+                [
259
+                    'message' => $message,
260
+                    'level' => $level,
261
+                ],
262
+                $context
263
+            ));
264
+        } else {
265
+            $this->logger->log($level, $message, $context);
266
+        }
267
+    }
268 268
 
269
-	public function logData(string $message, array $data, array $context = []): void {
270
-		$this->logger->logData($message, $data, $context);
271
-	}
269
+    public function logData(string $message, array $data, array $context = []): void {
270
+        $this->logger->logData($message, $data, $context);
271
+    }
272 272
 }
Please login to merge, or discard this patch.