Skip to content

Commit c2d6c66

Browse files
committed
Add basic Sentry tracing instrumentation
1 parent 5bcb307 commit c2d6c66

5 files changed

Lines changed: 143 additions & 56 deletions

File tree

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
"@mdi/react": "^1.4.0",
77
"@mdi/svg": "^5.2.45",
88
"@mdi/util": "^0.3.2",
9-
"@sentry/browser": "^5.15.5",
10-
"@sentry/integrations": "^5.15.5",
9+
"@sentry/apm": "^5.17.0",
10+
"@sentry/browser": "^5.17.0",
11+
"@sentry/integrations": "^5.17.0",
1112
"@testing-library/jest-dom": "^5.7.0",
1213
"@testing-library/react": "^10.0.4",
1314
"@testing-library/user-event": "^10.3.1",
@@ -63,5 +64,8 @@
6364
"last 1 firefox version",
6465
"last 1 safari version"
6566
]
67+
},
68+
"devDependencies": {
69+
"@sentry/types": "^5.17.0"
6670
}
6771
}

src/components/PanelKit.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import styled from "styled-components";
33
import { ToastContainer, toast } from "react-toastify";
44
import { Flex, Box } from "reflexbox/styled-components";
55
import * as Sentry from "@sentry/browser";
6-
import { CaptureConsole as CaptureConsoleIntegration } from "@sentry/integrations";
76

87
import "react-toastify/dist/ReactToastify.css";
98
import "../Toast.css";
@@ -13,6 +12,7 @@ import HomeAssistant from "../hass";
1312
import EventManager from "./EventManager";
1413
import Header from "./Header";
1514
import TileErrorBoundary from "./TileErrorBoundary";
15+
import { setupSentry } from "../sentry";
1616

1717
const Container = styled.div``;
1818

@@ -44,14 +44,10 @@ export default class PanelKit extends Component<Props, State> {
4444
const sentryDsn =
4545
process.env.REACT_APP_SENTRY_DSN || this.props.config.sentryDsn;
4646
if (sentryDsn) {
47-
console.log(`[sentry] Initialized with DSN: ${sentryDsn}`);
48-
Sentry.init({
47+
setupSentry({
4948
dsn: sentryDsn,
50-
integrations: [
51-
new CaptureConsoleIntegration({
52-
levels: ["warn", "error"],
53-
}),
54-
],
49+
release: process.env.REACT_APP_GIT_SHA,
50+
environment: process.env.NODE_ENV || "development",
5551
});
5652
}
5753

src/hass.tsx

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Entity } from "./types";
2+
import { startSpan } from "./sentry";
3+
import { Span, SpanStatus } from "@sentry/apm";
24

35
enum State {
46
DISCONNECTED = "DISCONNECTED",
@@ -13,6 +15,19 @@ enum Phase {
1315

1416
const DEFAULT_TIMEOUT = 250; // ms
1517

18+
const ERROR_MAP: {
19+
[code: number]: SpanStatus;
20+
} = {
21+
// default
22+
0: SpanStatus.UnknownError,
23+
// A non-increasing identifier has been supplied.
24+
1: SpanStatus.InvalidArgument,
25+
// Received message is not in expected format (voluptuous validation error).
26+
2: SpanStatus.InvalidArgument,
27+
// Requested item cannot be found
28+
3: SpanStatus.NotFound,
29+
};
30+
1631
const makeSubscriberId = (): string => {
1732
const s4 = () => {
1833
return Math.floor((1 + Math.random()) * 0x10000)
@@ -59,6 +74,7 @@ export interface MessageResult {
5974
result: any;
6075
error: {
6176
message: string;
77+
code?: number;
6278
} | null;
6379
success: boolean;
6480
[key: string]: any;
@@ -89,7 +105,7 @@ export default class HomeAssistant {
89105
private _messageCounter: number = 1;
90106
private _hasPrepared: boolean = false;
91107
private _shouldReconnect: boolean = false;
92-
private _pendingRequests: Map<number, [Function, Function]>;
108+
private _pendingRequests: Map<number, [Function, Function, Span | null]>;
93109
private _pendingChanges: Map<number, SuggestedChanges>;
94110
private _eventSubscribers: EventSubscriber[];
95111
private _rootSubscriptions: Map<string, string>;
@@ -209,10 +225,17 @@ export default class HomeAssistant {
209225
switch (payload.type) {
210226
case "auth_required":
211227
if (this.accessToken) {
228+
// auth requires _no_ ID, which means we can't correlate the message directly
229+
const span = startSpan({
230+
op: "sendCommand",
231+
description: "auth",
232+
});
212233
this.sendMessage({
213234
type: "auth",
214235
access_token: this.accessToken,
215236
});
237+
// TODO(dcramer): this should finish only after auth response
238+
if (span) span.finish();
216239
} else {
217240
console.error("[hass] No authentication token configured");
218241
this.disconnect();
@@ -239,14 +262,22 @@ export default class HomeAssistant {
239262
if (!promiseHandler) {
240263
console.warn("[hass] No pending request found for event", payload.id);
241264
} else {
242-
let [resolve, reject] = promiseHandler;
265+
let [resolve, reject, span] = promiseHandler;
243266
this._pendingRequests.delete(payload.id);
244267
if (payload.success) {
268+
if (span) {
269+
span.setStatus(SpanStatus.Ok);
270+
}
245271
setTimeout(() => {
246272
this._pendingChanges.delete(payload.id);
247273
}, 1000);
248274
resolve(payload);
249275
} else if (payload.error) {
276+
if (span) {
277+
span.setStatus(
278+
ERROR_MAP[payload.error.code || 0] || SpanStatus.UnknownError
279+
);
280+
}
250281
const error = new Error(payload.error.message);
251282
(error as any).payload = payload;
252283
const changes = this._pendingChanges.get(payload.id);
@@ -258,6 +289,10 @@ export default class HomeAssistant {
258289
}
259290
reject(error);
260291
}
292+
293+
if (span) {
294+
span.finish();
295+
}
261296
}
262297
break;
263298
default:
@@ -429,8 +464,12 @@ export default class HomeAssistant {
429464
suggestedChanges: SuggestedChanges | null = null
430465
): CancellablePromise<MessageResult> {
431466
const id = this._messageCounter;
467+
const span = startSpan({
468+
op: "sendCommand",
469+
description: message.type,
470+
});
432471
const promise = new Promise((resolve, reject) => {
433-
this._pendingRequests.set(id, [resolve, reject]);
472+
this._pendingRequests.set(id, [resolve, reject, span]);
434473
if (suggestedChanges) {
435474
this._pendingChanges.set(id, suggestedChanges);
436475
// Object.keys(suggestedChanges).forEach((entityId) => {

src/sentry.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as Sentry from "@sentry/browser";
2+
import { Integrations as ApmIntegrations, Span } from "@sentry/apm";
3+
import { CaptureConsole as CaptureConsoleIntegration } from "@sentry/integrations";
4+
5+
const Tracing = ApmIntegrations.Tracing;
6+
7+
export const setupSentry = (options: { [key: string]: any }) => {
8+
console.log(`[sentry] Initialized with DSN: ${options.dsn}`);
9+
Sentry.init({
10+
tracesSampleRate: 1.0,
11+
...options,
12+
integrations: [
13+
new CaptureConsoleIntegration({
14+
levels: ["error"],
15+
}),
16+
new ApmIntegrations.Tracing(),
17+
],
18+
});
19+
};
20+
21+
export const startSpan = (options: {
22+
description?: string;
23+
op?: string;
24+
}): Span | null => {
25+
const tracingIntegration = Sentry.getCurrentHub().getIntegration(Tracing);
26+
if (!tracingIntegration) {
27+
console.warn("startSpan called without tracing integration");
28+
return null;
29+
}
30+
const transaction = (tracingIntegration as any).constructor.getTransaction();
31+
if (!transaction) {
32+
console.info("startSpan called without transaction");
33+
return null;
34+
}
35+
return transaction.startChild(options);
36+
};

yarn.lock

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,65 +1374,77 @@
13741374
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
13751375
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
13761376

1377-
"@sentry/browser@^5.15.5":
1378-
version "5.15.5"
1379-
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.15.5.tgz#d9a51f1388581067b50d30ed9b1aed2cbb333a36"
1380-
integrity sha512-rqDvjk/EvogfdbZ4TiEpxM/lwpPKmq23z9YKEO4q81+1SwJNua53H60dOk9HpRU8nOJ1g84TMKT2Ov8H7sqDWA==
1381-
dependencies:
1382-
"@sentry/core" "5.15.5"
1383-
"@sentry/types" "5.15.5"
1384-
"@sentry/utils" "5.15.5"
1377+
"@sentry/apm@^5.17.0":
1378+
version "5.17.0"
1379+
resolved "https://registry.yarnpkg.com/@sentry/apm/-/apm-5.17.0.tgz#c3e6d07f4f488f77c8677cdc8d0e2fb58e302d72"
1380+
integrity sha512-raJcPa04TP8mVocSTHe0PdULpRWhw0NaLq9Rk8KCTFBJvLsgzY2krph5/LgEfBBX78vWt70FrwSw+DdIfYIJ6g==
1381+
dependencies:
1382+
"@sentry/browser" "5.17.0"
1383+
"@sentry/hub" "5.17.0"
1384+
"@sentry/minimal" "5.17.0"
1385+
"@sentry/types" "5.17.0"
1386+
"@sentry/utils" "5.17.0"
13851387
tslib "^1.9.3"
13861388

1387-
"@sentry/core@5.15.5":
1388-
version "5.15.5"
1389-
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.15.5.tgz#40ea79bff5272d3fbbeeb4a98cdc59e1adbd2c92"
1390-
integrity sha512-enxBLv5eibBMqcWyr+vApqeix8uqkfn0iGsD3piKvoMXCgKsrfMwlb/qo9Ox0lKr71qIlZVt+9/A2vZohdgnlg==
1389+
"@sentry/browser@5.17.0", "@sentry/browser@^5.17.0":
1390+
version "5.17.0"
1391+
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.17.0.tgz#0c3796cb02df3ec8db13341564fae0bc83e148c5"
1392+
integrity sha512-++pXpCHtdek1cRUwVeLvlxUJ2w1s+eiC9qN1N+7+HdAjHpBz2/tA1sKBCqwwVQZ490Cf2GLll9Ao7fuPPmveRQ==
13911393
dependencies:
1392-
"@sentry/hub" "5.15.5"
1393-
"@sentry/minimal" "5.15.5"
1394-
"@sentry/types" "5.15.5"
1395-
"@sentry/utils" "5.15.5"
1394+
"@sentry/core" "5.17.0"
1395+
"@sentry/types" "5.17.0"
1396+
"@sentry/utils" "5.17.0"
13961397
tslib "^1.9.3"
13971398

1398-
"@sentry/hub@5.15.5":
1399-
version "5.15.5"
1400-
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.15.5.tgz#f5abbcdbe656a70e2ff02c02a5a4cffa0f125935"
1401-
integrity sha512-zX9o49PcNIVMA4BZHe//GkbQ4Jx+nVofqU/Il32/IbwKhcpPlhGX3c1sOVQo4uag3cqd/JuQsk+DML9TKkN0Lw==
1399+
"@sentry/core@5.17.0":
1400+
version "5.17.0"
1401+
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.17.0.tgz#b2deef95465c766076d5cffd8534a67100f9b821"
1402+
integrity sha512-Kfx4rGKDC7V1YJjTGJXyl12VVHxM8Cjpu61YOyF8kXoXXg9u06C3n0G1dmfzLQERKXasUVMtXRBdKx/OjYpl1g==
14021403
dependencies:
1403-
"@sentry/types" "5.15.5"
1404-
"@sentry/utils" "5.15.5"
1404+
"@sentry/hub" "5.17.0"
1405+
"@sentry/minimal" "5.17.0"
1406+
"@sentry/types" "5.17.0"
1407+
"@sentry/utils" "5.17.0"
14051408
tslib "^1.9.3"
14061409

1407-
"@sentry/integrations@^5.15.5":
1408-
version "5.15.5"
1409-
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-5.15.5.tgz#7f7bc488d838cd50e9ca50d5f933680632827826"
1410-
integrity sha512-s9N9altnGkDH+vNNUZu1dKuMVLAgJNYtgs6DMJTrZRswFl8gzZytYTZCdpzjBgTsqkLaGbRDIjQeE/yP3gnrqw==
1410+
"@sentry/hub@5.17.0":
1411+
version "5.17.0"
1412+
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.17.0.tgz#b7d255ca3f766385911d9414af97f388e869d996"
1413+
integrity sha512-lyUbEmshwaMYdAzy4iwgizgvKODVVloB2trnefpq90AuWCdvzcxMLIGULx1ou+KohccqdNorYICKWeuRscKq5A==
14111414
dependencies:
1412-
"@sentry/types" "5.15.5"
1413-
"@sentry/utils" "5.15.5"
1415+
"@sentry/types" "5.17.0"
1416+
"@sentry/utils" "5.17.0"
14141417
tslib "^1.9.3"
14151418

1416-
"@sentry/minimal@5.15.5":
1417-
version "5.15.5"
1418-
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.15.5.tgz#a0e4e071f01d9c4d808094ae7203f6c4cca9348a"
1419-
integrity sha512-zQkkJ1l9AjmU/Us5IrOTzu7bic4sTPKCatptXvLSTfyKW7N6K9MPIIFeSpZf9o1yM2sRYdK7GV08wS2eCT3JYw==
1419+
"@sentry/integrations@^5.17.0":
1420+
version "5.17.0"
1421+
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-5.17.0.tgz#afff7759d82111de030b4a6703388c423fdbe6e7"
1422+
integrity sha512-H4CLH+fej/EjbI5WKXnAVkyVK3MeHUcTMbnjPcUlAsxpu1+PckFzpw3t4S5la9WGwcfL3WDo24b+fb4iKf9t4Q==
14201423
dependencies:
1421-
"@sentry/hub" "5.15.5"
1422-
"@sentry/types" "5.15.5"
1424+
"@sentry/types" "5.17.0"
1425+
"@sentry/utils" "5.17.0"
14231426
tslib "^1.9.3"
14241427

1425-
"@sentry/types@5.15.5":
1426-
version "5.15.5"
1427-
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.15.5.tgz#16c97e464cf09bbd1d2e8ce90d130e781709076e"
1428-
integrity sha512-F9A5W7ucgQLJUG4LXw1ZIy4iLevrYZzbeZ7GJ09aMlmXH9PqGThm1t5LSZlVpZvUfQ2rYA8NU6BdKJSt7B5LPw==
1428+
"@sentry/minimal@5.17.0":
1429+
version "5.17.0"
1430+
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.17.0.tgz#b40e4b4109b098840277def3b51cc20ae6767164"
1431+
integrity sha512-v8xfkySXKrliZO6er6evlVe/ViUcqN0O8BhGyauK28Mf+KnKEOs5W6oWbt4qCDIttw9ynKIYyRrkAl/9oUR76A==
1432+
dependencies:
1433+
"@sentry/hub" "5.17.0"
1434+
"@sentry/types" "5.17.0"
1435+
tslib "^1.9.3"
1436+
1437+
"@sentry/types@5.17.0", "@sentry/types@^5.17.0":
1438+
version "5.17.0"
1439+
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.17.0.tgz#b8d245ac7d5caa749c549e9f72aab2d6522afe63"
1440+
integrity sha512-1z8EXzvg8GcsBNnSXgB5/G7mz2PwmMt9mjOrVG1jhtSGH1c7WvB32F5boqoMcjIJmy5MrBGaaXwrF/RRJrwUQg==
14291441

1430-
"@sentry/utils@5.15.5":
1431-
version "5.15.5"
1432-
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.15.5.tgz#dec1d4c79037c4da08b386f5d34409234dcbfb15"
1433-
integrity sha512-Nl9gl/MGnzSkuKeo3QaefoD/OJrFLB8HmwQ7HUbTXb6E7yyEzNKAQMHXGkwNAjbdYyYbd42iABP6Y5F/h39NtA==
1442+
"@sentry/utils@5.17.0":
1443+
version "5.17.0"
1444+
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.17.0.tgz#b809b067665f3ebaea77ba7b5d1d1d14a4ed76cb"
1445+
integrity sha512-qn8WgZcSkV/rx0ezp9q/xFjP7aMaYZO1/JYLXV4o6pYrQ9tvMmmwAZT39FpJunhhbkR36WNEuRB9C2K250cb/A==
14341446
dependencies:
1435-
"@sentry/types" "5.15.5"
1447+
"@sentry/types" "5.17.0"
14361448
tslib "^1.9.3"
14371449

14381450
"@sinonjs/commons@^1.7.0":

0 commit comments

Comments
 (0)