PluginProbe
Route ‑ Shipping Protection / 2.4.16
Route ‑ Shipping Protection v2.4.16
2.4.19 2.4.18 2.4.17 2.4.16 2.4.15 2.4.14 2.4.13 2.4.12 2.4.11 2.4.10 2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.2.4 2.2.5 2.2.6 2.2.8 2.2.9 2.3.0 2.3.1 All 153 releases
routeapp / includes / class-routeapp-logger-sentry.php

class-routeapp-logger-sentry.php in Route ‑ Shipping Protection 2.4.16, at includes/class-routeapp-logger-sentry.php

270 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Routeapp_Logger_Sentry
4 {
5 /**
6 * Sentry DSN key
7 */
8 const SENTRY_KEY= 'b1ddeaac648345389240bf5f2f1e2a19';
9
10 /**
11 * Sentry project id
12 */
13 const SENTRY_PROJECT_ID = '2048214';
14
15
16 /**
17 * Sentry log context lines
18 */
19 const SENTRY_LOG_CONTEXT_LINES = 10;
20
21 /**
22 * The Sentry API URL
23 * @var string
24 */
25 private $_api_url;
26
27 /**
28 * Data used for API call
29 * @var array
30 */
31 private $_extraData = [];
32
33 private static $instances = [];
34 /**
35 * Default contructor
36 */
37 public function __construct()
38 {
39 $this->_api_url = 'https://sentry.io/api/' . self::SENTRY_PROJECT_ID . '/store/';
40 }
41
42 /**
43 * Singletons should not be cloneable.
44 */
45 protected function __clone()
46 {}
47
48 public static function getInstance()
49 {
50 $cls = static::class;
51 if (!isset(static::$instances[$cls])) {
52 static::$instances[$cls] = new static;
53 }
54 return static::$instances[$cls];
55 }
56
57 /*
58 * Make the call to the API
59 * @param string $endpoint
60 * @param array $params
61 * @param string $method
62 * @return mixed|json string
63 */
64 private function _make_api_call($params = array())
65 {
66 $url = $this->_api_url;
67 $args = array(
68 'timeout' => 5,
69 'method' => 'POST',
70 'headers' => array(
71 'Content-Type' => 'application/json',
72 'X-Sentry-Auth' => $this->_get_sentry_auth(),
73 ),
74 'body' => json_encode($params),
75 );
76 return wp_remote_request($url, $args);
77 }
78
79 private function _get_sentry_auth() {
80 return 'Sentry sentry_version=7, sentry_key=' . self::SENTRY_KEY . ', sentry_client=raven-bash/0.1';
81 }
82
83 public function sentry_log($event, $extraData = false) {
84 $this->_extraData = $extraData;
85 $params = $this->_prepare_event($event);
86 $this->_make_api_call($params);
87 }
88
89 /**
90 * Prepare event in array
91 *
92 * @return array
93 */
94 private function _prepare_event($event) {
95 $eventArray = array();
96 $eventArray['platform'] = 'php';
97 if (is_object($event)) {
98 $eventArray['message'] = (string)$event->getMessage();
99 $reportLevel = strtolower(get_class($event));
100 $traces = $event->getTrace();
101 } else {
102 $eventArray['message'] = $event;
103 $reportLevel = 'debug';
104 $traces = debug_backtrace();
105 }
106 $eventArray['type'] = $eventArray['message'];
107 $eventArray['tags'] = [
108 ['module', 'Route Module'],
109 ['module.version', ROUTEAPP_VERSION],
110 ['url', wc_get_page_permalink( 'shop' )],
111 ['php.version', phpversion()],
112 ['report.level', $reportLevel],
113 ['http.server', $_SERVER['SERVER_SOFTWARE']],
114 ['woocommerce.version', $this->_get_woo_version_number()]
115 ];
116
117 $eventArray['exception'] = [
118 'values' => [
119 [
120 'type' => ucfirst($eventArray['type']),
121 'module' => 'Route WooCommerce Integration',
122 'value' => $eventArray['message'],
123 'stacktrace' => [
124 'frames' => $this->_prepare_stack_trace($traces)
125 ]
126 ]
127 ]
128 ];
129
130 $eventArray['extra']['url'] = wc_get_page_permalink( 'shop' );
131
132 if (!empty($this->_extraData)) {
133 $eventArray['extra']['extraData'] = $this->_extraData;
134 }
135
136 return $eventArray;
137 }
138
139 /**
140 * Get WooCommerce version number
141 * @return mixed|null
142 */
143 private function _get_woo_version_number() {
144 // If get_plugins() isn't available, require it
145 if ( ! function_exists( 'get_plugins' ) )
146 require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
147
148 // Create the plugins folder and file variables
149 $plugin_folder = get_plugins( '/' . 'woocommerce' );
150 $plugin_file = 'woocommerce.php';
151
152 // If the plugin version number is set, return it
153 if ( isset( $plugin_folder[$plugin_file]['Version'] ) ) {
154 return $plugin_folder[$plugin_file]['Version'];
155 } else {
156 // Otherwise return null
157 return NULL;
158 }
159 }
160
161 /**
162 * Receive error or exception traces, return formatted array for Sentry
163 *
164 * @return array
165 */
166 private function _prepare_stack_trace($traces) {
167 $tracesArray = array();
168 foreach (array_reverse($traces) as $trace) {
169 if ($this->_is_valid_trace($trace)) {
170 $traceArray = array();
171 $traceArray['filename'] = $trace['file'];
172 $traceArray['abs_path'] = $trace['file'];
173 $traceArray['lineno'] = (int)$trace['line'];
174 $traceArray['function'] = $trace['function'];
175 $traceArray['context_line'] = $trace['function'];
176 $traceArray['pre_context'][0] = "";
177 $traceArray['post_context'][0] = "";
178
179 $sourceCodeExcerpt = $this->_get_source_code_excerpt($traceArray['filename'],
180 $traceArray['lineno'],
181 self::SENTRY_LOG_CONTEXT_LINES);
182
183 if (isset($sourceCodeExcerpt['context_line'])) {
184 $traceArray['context_line'] = $sourceCodeExcerpt['context_line'];
185 }
186
187 if (isset($sourceCodeExcerpt['pre_context'])) {
188 $traceArray['pre_context'] = $sourceCodeExcerpt['pre_context'];
189 }
190 if (isset($sourceCodeExcerpt['post_context'])) {
191 $traceArray['post_context'] = $sourceCodeExcerpt['post_context'];
192 }
193 $traceArray['in_app'] = false;
194 $tracesArray[] = $traceArray;
195 }
196 }
197 return $tracesArray;
198 }
199
200 /**
201 * Check if is a valid trace
202 * @param $trace
203 * @return bool
204 */
205 private function _is_valid_trace($trace) {
206 if (isset($trace['file']) && isset($trace['line']) && isset($trace['function'])) {
207 if (!empty($trace['file']) && !empty($trace['line']) && !empty($trace['function'])) {
208 return true;
209 }
210 }
211 return false;
212 }
213
214 /**
215 * Gets an excerpt of the source code around a given line.
216 *
217 * @param $path The file path
218 * @param $lineNumber The line to centre about
219 * @param $maxLinesToFetch The maximum number of lines to fetch
220 */
221 private function _get_source_code_excerpt($path,$lineNumber, $maxLinesToFetch)
222 {
223 if (@!is_readable($path) || !is_file($path)) {
224 return [];
225 }
226
227 $frame = [
228 'pre_context' => [],
229 'context_line' => '',
230 'post_context' => [],
231 ];
232
233 $target = max(0, ($lineNumber - ($maxLinesToFetch + 1)));
234 $currentLineNumber = $target + 1;
235
236 try {
237 $file = new \SplFileObject($path);
238 $file->seek($target);
239
240 while (!$file->eof()) {
241 /** @var string $line */
242 $line = $file->current();
243 $line = rtrim($line, "\r\n");
244
245 if ($currentLineNumber == $lineNumber) {
246 $frame['context_line'] = $line;
247 } elseif ($currentLineNumber < $lineNumber) {
248 $frame['pre_context'][] = $line;
249 } elseif ($currentLineNumber > $lineNumber) {
250 $frame['post_context'][] = $line;
251 }
252
253 ++$currentLineNumber;
254
255 if ($currentLineNumber > $lineNumber + $maxLinesToFetch) {
256 break;
257 }
258
259 $file->next();
260 }
261 } catch (\Exception $exception) {
262 // Do nothing, if any error occurs while trying to get the excerpts
263 // it's not a drama
264 }
265
266 return $frame;
267 }
268
269 }
270