sentry_top_errors 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 451faf0b74e71cc7d9ab082b35427881ce43d99d1908246fb4d2a111a16fe7bc
4
- data.tar.gz: 9684d29db554a2fbd8a660124d1cef85b2500afc6037d1bc8a4234b46a894831
3
+ metadata.gz: 312ff43ff1b7e67a60e97d53ce62420fdcb1a7e0d661df6fed257ad1f2fddea5
4
+ data.tar.gz: 3b2a17b9ca30d78d2a27f26d9c05802c1af5fe410a92c49eb2a7abb49f40bcbe
5
5
  SHA512:
6
- metadata.gz: b3dc5a3f0d23d95570d8f6627cdbec58da0a4213ca5c14085a775be7ba2c55154e6d1581ebf8dc67fb18df141c07b582051d2ff08e8c2952df4a39751f9078f8
7
- data.tar.gz: 8f9eb1cf3e1170c894ac8360a30cc0a636865bc5627e51e6e97d79ce4f7ef1ec131203a727b623785130ceea36f9a92528cacd992729bb60297f4f5c5236c039
6
+ metadata.gz: 4729a76870723d4941e0687d74a0947c1301fb80449037ed51b89f671f211a209fac35a9893d579471789e0c67d59cfd7f416f662a56e186d2a09a9eb36b9ce7
7
+ data.tar.gz: 81976c7433fe881e4f805366423527a6966bd8b6cdc550250efef0bfc803bc51703fe130bc50ba18bffac05d15e3862eba8acd5af3bad208be4444587593edc6
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  sentry_cache
2
- index.html
2
+ /index.html
3
3
  Gemfile.lock
4
4
  try_sentry_checker.rb
5
+ sentry_top_errors-*.gem
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "sentry_top_errors"
3
- s.version = "0.1.0"
3
+ s.version = "0.1.1"
4
4
  s.summary = "Generate top errors report for sentry"
5
5
  s.description = ""
6
6
  s.author = "Pavel Evstigneev"
@@ -0,0 +1,358 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Sentry Errors</title>
7
+
8
+ <style>
9
+ body {
10
+ background: linear-gradient(0deg, rgba(252,217,182,1) 0%, rgba(160,206,219,1) 100%);
11
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
12
+ font-size: 14px;
13
+ }
14
+
15
+ .page-content {
16
+ height: 100%;
17
+ min-height: 400px;
18
+ width: 92%;
19
+ max-width: 1200px;
20
+ margin: 30px auto;
21
+ background: #fff;
22
+ padding: 25px;
23
+ border-radius: 12px;
24
+ opacity: 0.95;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 1.5em;
29
+ background: #9d4f4f;
30
+ margin: -25px -25px 35px -25px;
31
+ padding: 12px 25px;
32
+ border-radius: 12px 12px 0 0;
33
+ color: white;
34
+ }
35
+
36
+ h1 a {
37
+ color: white;
38
+ text-decoration: none;
39
+ }
40
+
41
+ table.rows-table {
42
+ margin: 20px 0;
43
+ border-spacing: 0px;
44
+ border-collapse: collapse;
45
+ }
46
+
47
+ table.rows-table td {
48
+ vertical-align: top;
49
+ }
50
+
51
+ table.rows-table td a {
52
+ color: #000;
53
+ }
54
+
55
+ table.rows-table td, table.rows-table th {
56
+ padding: 3px 7px;
57
+ border: 1px solid #cfcfcf;
58
+ }
59
+
60
+ tr.is-non-prod-issue, tr.is-non-prod-issue td a {
61
+ color: #36487d;
62
+ background: #f5f5f5;
63
+ }
64
+
65
+ td.issue-count {
66
+ font-weight: bold;
67
+ }
68
+
69
+ td.issue-name {
70
+ /* word-break: break-all; */
71
+ }
72
+
73
+ td.issue-cause {
74
+ word-break: break-all;
75
+ max-width: 240px;
76
+ font-size: 80%;
77
+ }
78
+
79
+ td.project-name {
80
+ word-break: break-all;
81
+ max-width: 260px;
82
+ }
83
+
84
+ .full-width {
85
+ width: 100%;
86
+ max-width: 100%;
87
+ }
88
+ </style>
89
+ </head>
90
+ <body>
91
+ <div class='page-content'>
92
+ <h1>
93
+ <a href=''>Sentry Errors</a>
94
+ </h1>
95
+
96
+ <h2>Repeating Issues</h2>
97
+
98
+ <table class='rows-table full-width' id="issues-table">
99
+ <thead>
100
+ <tr>
101
+ <th>Count</th>
102
+ <th>Project</th>
103
+ <th>Issue</th>
104
+ <th>Cause</th>
105
+ </tr>
106
+ </thead>
107
+ <tbody></tbody>
108
+ </table>
109
+
110
+ <h2>New Issues</h2>
111
+
112
+ <table class='rows-table full-width' id="new-issues-table">
113
+ <thead>
114
+ <tr>
115
+ <th>Count</th>
116
+ <th>Project</th>
117
+ <th>Issue</th>
118
+ <th>Cause</th>
119
+ </tr>
120
+ </thead>
121
+ <tbody></tbody>
122
+ </table>
123
+ </div>
124
+
125
+ <script>
126
+ var ALL_ISSUE_COUNTS = ['ALL_ISSUE_COUNTS_PLACEHOLDER'];
127
+ var NEW_ISSUE_COUNTS = ['NEW_ISSUE_COUNTS_PLACEHOLDER'];
128
+ </script>
129
+ <script>
130
+
131
+ // Some sort of replacement for jquery
132
+ ///
133
+ // Usage:
134
+ // $(selector, paretn) - find an element
135
+ // $$(selector, paretn) - find elements, return as array
136
+ // $.element(html, {class: '', appendTo: '', html: '', text: '', hide: '', classes: ['']}) - create element
137
+ // $.ajax({url: '', method: 'GET', data: '', contentType: '', accepts: '', headers: '', before: fn, process: fn, uploadProgress: fn, complete: fn, error: fn, })
138
+ // $.ready - $(document).ready
139
+ // $.matches - polifill
140
+ // $.closest - same as jquery
141
+
142
+ var $ = function (selector, element) {
143
+ if (selector[0] == '<') {
144
+ return $.element(selector, element);
145
+ }
146
+ return (element || document).querySelector(selector);
147
+ };
148
+
149
+ var $$ = function (selector, element) {
150
+ return Array.from((element || document).querySelectorAll(selector));
151
+ };
152
+
153
+ $.element = function (html, attributes) {
154
+ if (!attributes) attributes = {};
155
+ var element;
156
+
157
+ if (html[0] == '<') {
158
+ var div = document.createElement('div');
159
+ div.innerHTML = html;
160
+ element = div.childNodes[0];
161
+ } else {
162
+ var element = document.createElement(html);
163
+ }
164
+
165
+ Object.keys(attributes).forEach(function (key) {
166
+ var value = attributes[key];
167
+
168
+ if (key == 'class') {
169
+ element.className = value;
170
+ } else if (key == 'classes') {
171
+ value.forEach(function (className) {
172
+ el.classList.add(className);
173
+ });
174
+ } else if (key == 'appendTo') {
175
+ value.appendChild(element);
176
+ } else if (key == 'html') {
177
+ element.innerHTML = value;
178
+ } else if (key == 'text') {
179
+ element.innerText = value;
180
+ } else if (key == 'hide') {
181
+ element.style.display = 'none';
182
+ } else {
183
+ element.setAttribute(key, value);
184
+ }
185
+ });
186
+
187
+ return element;
188
+ };
189
+
190
+ $.ajax = function (options) {
191
+ var request = new XMLHttpRequest();
192
+
193
+ if (options.query) {
194
+ var query = Object.keys(options.query).map(function (k) {
195
+ return encodeURIComponent(k) + '=' + encodeURIComponent(options.query[k]);
196
+ }).join('&');
197
+ options.url += (options.url.includes("?") ? "&" : "?") + query;
198
+ }
199
+
200
+ request.open(options.method || 'GET', options.url);
201
+
202
+ options.before && options.before(request);
203
+
204
+ if (options.contentType == 'json') {
205
+ request.setRequestHeader("Content-type", "application/json");
206
+ } else if (options.contentType) {
207
+ request.setRequestHeader("Content-type", options.contentType);
208
+ } else if (options.data && !(options.data instanceof FormData)) {
209
+ request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
210
+ }
211
+
212
+ request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
213
+ if (options.accepts) {
214
+ request.setRequestHeader('Accept', '*/*;q=0.5, ' + options.accepts);
215
+ }
216
+
217
+ if (options.headers) {
218
+ Object.keys(options.headers).forEach(function (key) {
219
+ request.setRequestHeader(key, options.headers[key]);
220
+ });
221
+ }
222
+
223
+ if (options.process) {
224
+ request.addEventListener("progress", function (event) {
225
+ options.process(request, event);
226
+ });
227
+ }
228
+ if (options.uploadProgress) {
229
+ request.upload.addEventListener("progress", function (event) {
230
+ options.uploadProgress(request, event);
231
+ });
232
+ }
233
+
234
+ request.addEventListener("load", function (event) {
235
+ //console.log('Request Status', request.status, request, event);
236
+ try {
237
+ var data;
238
+ var contentType = request.getResponseHeader('Content-type') || "";
239
+ if (contentType == "application/json" || contentType.match(/^application\/json/)) {
240
+ try {
241
+ data = JSON.parse(request.responseText);
242
+ request.responseJSON = data;
243
+ } catch (e) {
244
+ console.error(e);
245
+ }
246
+ }
247
+ if (request.status < 400) {
248
+ options.success && options.success(request, data, event);
249
+ } else {
250
+ options.error && options.error(request, event);
251
+ }
252
+ } catch (e) {
253
+ console.error(e);
254
+ }
255
+ options.complete && options.complete(request, event);
256
+ });
257
+
258
+ ['error', 'abort'].map(function (event) {
259
+ request.addEventListener(event, function (event) {
260
+ try {
261
+ options.error && options.error(request, event);
262
+ } catch (e) {
263
+ console.error(e);
264
+ }
265
+ options.complete && options.complete(request, event);
266
+ });
267
+ });
268
+
269
+ request.send(options.data);
270
+ };
271
+
272
+ $.ready = function (fn) {
273
+ if (document.readyState != 'loading') {
274
+ fn();
275
+ } else {
276
+ document.addEventListener('DOMContentLoaded', fn);
277
+ }
278
+ };
279
+
280
+ $.matches = function (el, selector) {
281
+ var p = Element.prototype;
282
+ var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
283
+ return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
284
+ };
285
+ return f.call(el, selector);
286
+ };
287
+
288
+ $.closest = function (element, selector) {
289
+ var parent = element;
290
+ while (parent && !$.matches(parent, selector)) {
291
+ parent = parent.parentNode;
292
+ if (parent instanceof HTMLDocument) {
293
+ return null;
294
+ }
295
+ }
296
+
297
+ return parent;
298
+ };
299
+
300
+ $.onClickOutside = function (element, optoins, callback) {
301
+ if (!optoins) optoins = {};
302
+
303
+ document.addEventListener('click', function cb(event) {
304
+ var parent = event.target;
305
+ while (!(parent instanceof HTMLDocument)) {
306
+ if (parent == element) {
307
+ //console.log('click inside');
308
+ return;
309
+ }
310
+ parent = parent.parentNode;
311
+ }
312
+
313
+ //console.log('click outside');
314
+ callback(event);
315
+
316
+ if (optoins.once) {
317
+ // for browsers that don't support "once: true"
318
+ event.currentTarget.removeEventListener(event.type, cb);
319
+ }
320
+ }, {once: optoins.once});
321
+ };
322
+ </script>
323
+
324
+ <script>
325
+ var issuesTable = $('#issues-table tbody');
326
+
327
+ ALL_ISSUE_COUNTS.forEach(issue => {
328
+ var tr = $.element('tr', {
329
+ appendTo: issuesTable,
330
+ class: issue.is_production ? 'is-prod-issue' : 'is-non-prod-issue',
331
+ });
332
+
333
+ $.element('td', {text: issue.issue_count, appendTo: tr, class: 'issue-count'});
334
+ var projectCell = $.element('td', {appendTo: tr, class: 'project-name'});
335
+ $.element('a', {href: issue.project_url, text: issue.project_name, target: '_blank', appendTo: projectCell})
336
+ var issueCell = $.element('td', {appendTo: tr, class: 'issue-name'});
337
+ $.element('a', {href: issue.issue_link, text: issue.issue, target: '_blank', appendTo: issueCell})
338
+ $.element('td', {text: issue.culprit, appendTo: tr, class: 'issue-cause'});
339
+ });
340
+
341
+ var issuesTable = $('#new-issues-table tbody');
342
+
343
+ NEW_ISSUE_COUNTS.forEach(issue => {
344
+ var tr = $.element('tr', {
345
+ appendTo: issuesTable,
346
+ class: issue.is_production ? 'is-prod-issue' : 'is-non-prod-issue',
347
+ });
348
+
349
+ $.element('td', {text: issue.issue_count, appendTo: tr, class: 'issue-count'});
350
+ var projectCell = $.element('td', {appendTo: tr, class: 'project-name'});
351
+ $.element('a', {href: issue.project_url, text: issue.project_name, target: '_blank', appendTo: projectCell})
352
+ var issueCell = $.element('td', {appendTo: tr, class: 'issue-name'});
353
+ $.element('a', {href: issue.issue_link, text: issue.issue, target: '_blank', appendTo: issueCell})
354
+ $.element('td', {text: issue.culprit, appendTo: tr, class: 'issue-cause'});
355
+ });
356
+ </script>
357
+ </body>
358
+ </html>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry_top_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Evstigneev
@@ -60,6 +60,7 @@ files:
60
60
  - lib/sentry_top_errors/reporter.rb
61
61
  - lib/sentry_top_errors/sentry_client.rb
62
62
  - senrty_top_errors.gemspec
63
+ - templates/index.html
63
64
  homepage: http://github.com/Paxa/sentry_top_errors
64
65
  licenses:
65
66
  - MIT