SentryReporterAdapter::report()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 5
b 0
f 0
nc 2
nop 2
dl 0
loc 10
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @author Christoph Wurst <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
namespace OCA\Sentry\Reporter;
26
27
use Exception;
28
use OCA\Sentry\Helper\CredentialStoreHelper;
29
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
30
use OCP\IConfig;
31
use OCP\ILogger;
32
use OCP\IUserSession;
33
use OCP\Support\CrashReport\ICollectBreadcrumbs;
34
use OCP\Support\CrashReport\IMessageReporter;
35
use function Sentry\addBreadcrumb;
36
use Sentry\Breadcrumb;
37
use function Sentry\captureException;
38
use function Sentry\captureMessage;
39
use function Sentry\configureScope;
40
use Sentry\Severity;
41
use Sentry\State\Scope;
42
use Throwable;
43
44
class SentryReporterAdapter implements IMessageReporter, ICollectBreadcrumbs, ISentryReporter {
45
46
	/** @var IUserSession */
47
	protected $userSession;
48
49
	/** @var CredentialStoreHelper */
50
	private $credentialStoreHelper;
51
52
	/** @var bool */
53
	private $userScopeSet = false;
54
55
	/** @var array mapping of log levels */
56
	private const levels = [
57
		ILogger::DEBUG => Severity::DEBUG,
58
		ILogger::INFO => Severity::INFO,
59
		ILogger::WARN => Severity::WARNING,
60
		ILogger::ERROR => Severity::ERROR,
61
		ILogger::FATAL => Severity::FATAL,
62
	];
63
64
	/** @var int */
65
	private $minimumLogLevel;
66
67
	public function __construct(IUserSession $userSession,
68
								IConfig $config,
69
								CredentialStoreHelper $credentialStoreHelper) {
70
		$this->userSession = $userSession;
71
		$this->minimumLogLevel = (int)$config->getSystemValue('sentry.minimum.log.level', ILogger::WARN);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::WARN has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

71
		$this->minimumLogLevel = (int)$config->getSystemValue('sentry.minimum.log.level', /** @scrutinizer ignore-deprecated */ ILogger::WARN);

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
72
		$this->credentialStoreHelper = $credentialStoreHelper;
73
	}
74
75
	/**
76
	 * Report an (unhandled) exception to Sentry
77
	 *
78
	 * @param Exception|Throwable $exception
79
	 * @param array $context
80
	 */
81
	public function report($exception, array $context = []) {
82
		if (isset($context['level'])
83
			&& $context['level'] < $this->minimumLogLevel) {
84
			// TODO: report as breadcrumb instead?
85
			return;
86
		}
87
88
		$this->setSentryScope($context);
89
90
		captureException($exception);
91
	}
92
93
	protected function setSentryScope(array $context): void {
94
		configureScope(function (Scope $scope) use ($context): void {
95
			if (isset($context['level'])) {
96
				$scope->setLevel(
97
					new Severity(self::levels[$context['level']])
98
				);
99
			}
100
			if (isset($context['app'])) {
101
				$scope->setTag('app', $context['app']);
102
			}
103
104
			if ($this->userScopeSet) {
105
				// Run the code below just once
106
				return;
107
			}
108
			$this->userScopeSet = true;
109
			$user = $this->userSession->getUser();
110
			if ($user !== null) {
111
				// Try to obtain the login name as well
112
				try {
113
					$credentials = $this->credentialStoreHelper->getLoginCredentials();
114
					$username = $credentials->getLoginName();
115
				} catch (CredentialsUnavailableException $e) {
116
					$username = null;
117
				}
118
119
				$scope->setUser([
120
					'id' => $user->getUID(),
121
					'username' => $username,
122
				]);
123
			}
124
		});
125
	}
126
127
	public function collect(string $message, string $category, array $context = []) {
128
		if (isset($context['app'])) {
129
			$message = "[" . $context['app'] . "] " . $message;
130
		}
131
132
		$this->setSentryScope($context);
133
134
		$level = $context['level'] ?? ILogger::WARN;
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::WARN has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

134
		$level = $context['level'] ?? /** @scrutinizer ignore-deprecated */ ILogger::WARN;

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
135
		$sentryLevel = self::levels[$level] ?? Breadcrumb::LEVEL_WARNING;
136
137
		addBreadcrumb(new Breadcrumb($sentryLevel, Breadcrumb::TYPE_ERROR, $category, $message));
138
	}
139
140
	/**
141
	 * Report a (error) message
142
	 *
143
	 * @param string $message
144
	 * @param array $context
145
	 */
146
	public function reportMessage(string $message, array $context = []): void {
147
		if (isset($context['level'])
148
			&& $context['level'] < $this->minimumLogLevel) {
149
			$this->collect($message, 'message', $context);
150
			return;
151
		}
152
153
		if (isset($context['app'])) {
154
			$message = "[" . $context['app'] . "] " . $message;
155
		}
156
157
		captureMessage(
158
			$message,
159
			new Severity(self::levels[$context['level'] ?? ILogger::WARN] ?? Severity::WARNING)
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::WARN has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

159
			new Severity(self::levels[$context['level'] ?? /** @scrutinizer ignore-deprecated */ ILogger::WARN] ?? Severity::WARNING)

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
160
		);
161
	}
162
163
}
164