Skip to content

Commit c901c22

Browse files
authored
improve SDK metric reporting (#68)
## Summary * Correct error stacktrace reporting from new opentelemetry trace-based implementation * Fix reporting 0-value document_load durations * Fix document_load metrics not foorwarding to ld client * Refactor metrics to live in Observability plugin ## How did you test this change? [local deploy of react-router e2e app ](https://ld-stg.launchdarkly.com/projects/default/sessions/vAK4nlKb6C7jY33RMqphcppbwe2g?relativeTime=last_30_days&env=test&selected-env=test&related_resource=eyJ0eXBlIjoiZXJyb3IiLCJzZWN1cmVJZCI6IjFMWmk1UTFYc0NwZ0s2c04wRjNndVdMMHMwYTYiLCJpbnN0YW5jZUlkIjo1NDI4Mn0%3D) ## Are there any deployment considerations? changesets ## Does this work require review from our design team? no
1 parent 18008d0 commit c901c22

File tree

13 files changed

+221
-149
lines changed

13 files changed

+221
-149
lines changed

.changeset/eleven-results-smile.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'highlight.run': patch
3+
'@launchdarkly/observability': patch
4+
'@launchdarkly/session-replay': patch
5+
---
6+
7+
fix ErrorListener incorrectly reporting stacktrace via trace event

.changeset/every-results-report.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@launchdarkly/observability': minor
3+
'@launchdarkly/session-replay': minor
4+
---
5+
6+
move metrics listeners to Observability plugin from SessionReplay

.changeset/pink-kids-sniff.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'highlight.run': patch
3+
'@launchdarkly/observability': patch
4+
'@launchdarkly/session-replay': patch
5+
---
6+
7+
fix document_load metric not forwarding to ldClient

.changeset/sad-snakes-cheat.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'highlight.run': patch
3+
'@launchdarkly/observability': patch
4+
'@launchdarkly/session-replay': patch
5+
---
6+
7+
allow reporting 0-value document_load durations

e2e/react-router/src/routes/root.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,44 @@ export default function Root() {
7070
>
7171
LDRecord.start(forceNew)
7272
</button>
73+
<button
74+
onClick={() => {
75+
throw new Error('thrown error')
76+
}}
77+
>
78+
throw error
79+
</button>
80+
<button
81+
onClick={() => {
82+
LDObserve.recordGauge({
83+
name: 'my-random-metric',
84+
value: Math.floor(Math.random() * 100),
85+
})
86+
}}
87+
>
88+
LDObserve.recordGauge(random value)
89+
</button>
90+
<button
91+
onClick={() => {
92+
LDObserve.recordGauge({
93+
name: 'my-metric',
94+
value: 0,
95+
})
96+
}}
97+
>
98+
LDObserve.recordGauge(0 value)
99+
</button>
100+
<button
101+
onClick={() => {
102+
LDObserve.recordGauge({
103+
name: 'my-metric-attrs',
104+
value: 0,
105+
attributes: { foo: 'bar', baz: 42 },
106+
})
107+
}}
108+
>
109+
LDObserve.recordGauge(0 value w attrs)
110+
</button>
73111
<button
74112
onClick={async () => {
75113
setFlags(

sdk/highlight-run/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
"enforce-size": "size-limit",
3434
"test": "vitest --run",
3535
"test:watch": "vitest",
36-
"typegen": "FORMAT=d.ts vite build",
36+
"typegen": "yarn typegen:check && FORMAT=d.ts vite build",
37+
"typegen:check": "tsc --noEmit",
3738
"docs": "typedoc"
3839
},
3940
"type": "module",

sdk/highlight-run/src/client/listeners/error-listener.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ function handleError(
1414
source: string | undefined,
1515
error?: Error,
1616
) {
17-
let res = parseError(error ?? event)
17+
let e: Error = error ?? event
18+
let res = parseError(e)
1819
let payload: Object = {}
1920
if (event instanceof Error) {
2021
event = event.message
@@ -24,6 +25,7 @@ function handleError(
2425
}
2526
const framesToUse = removeHighlightFrameIfExists(res)
2627
callback({
28+
error: e,
2729
event: stringify(event),
2830
type: 'window.onerror',
2931
url: window.location.href,

sdk/highlight-run/src/client/otel/index.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -576,8 +576,9 @@ const assignDocumentDurations = (span: api.Span) => {
576576
request: calculateDuration('requestStart', 'requestEnd', events),
577577
response: calculateDuration('responseStart', 'responseEnd', events),
578578
}
579-
for (const _integration of otelConfig?.getIntegrations?.() ?? []) {
580-
if (durations_ns.document_load > 0) {
579+
const integrations = otelConfig?.getIntegrations?.() ?? []
580+
if (durations_ns.document_load !== undefined) {
581+
for (const _integration of integrations) {
581582
_integration.recordGauge(otelConfig?.sessionSecureId ?? '', {
582583
name: LD_METRIC_NAME_DOCUMENT_LOAD,
583584
value: durations_ns.document_load / 1e6,
@@ -586,7 +587,7 @@ const assignDocumentDurations = (span: api.Span) => {
586587
}
587588

588589
Object.entries(durations_ns).forEach(([key, value]) => {
589-
if (value > 0) {
590+
if (value !== undefined) {
590591
span.setAttribute(`timings.${key}.ns`, value)
591592
span.setAttribute(
592593
`timings.${key}.readable`,
@@ -610,7 +611,7 @@ function calculateDuration(
610611
const endEvent = events.find((e) => e.name === endEventName)
611612

612613
if (!startEvent || !endEvent) {
613-
return 0
614+
return undefined
614615
}
615616

616617
const startNs = startEvent.time[0] * 1e9 + startEvent.time[1]
@@ -624,20 +625,15 @@ const assignResourceFetchDurations = (
624625
) => {
625626
const durations = {
626627
domain_lookup:
627-
(resource.domainLookupEnd - resource.domainLookupStart) * 1e6,
628-
connect: (resource.connectEnd - resource.connectStart) * 1e6,
629-
request: (resource.responseEnd - resource.requestStart) * 1e6,
630-
response: (resource.responseEnd - resource.responseStart) * 1e6,
628+
(resource.domainLookupEnd - resource.domainLookupStart) * 1e9,
629+
connect: (resource.connectEnd - resource.connectStart) * 1e9,
630+
request: (resource.responseEnd - resource.requestStart) * 1e9,
631+
response: (resource.responseEnd - resource.responseStart) * 1e9,
631632
}
632633

633634
Object.entries(durations).forEach(([key, value]) => {
634-
if (value > 0) {
635-
span.setAttribute(`timings.${key}.ns`, value)
636-
span.setAttribute(
637-
`timings.${key}.readable`,
638-
humanizeDuration(value),
639-
)
640-
}
635+
span.setAttribute(`timings.${key}.ns`, value)
636+
span.setAttribute(`timings.${key}.readable`, humanizeDuration(value))
641637
})
642638
}
643639

sdk/highlight-run/src/client/types/shared-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ export type ErrorMessage = {
2828
/** The Unix Time of when the error was thrown. */
2929
timestamp: string
3030
payload?: string
31+
error?: Error
3132
}

sdk/highlight-run/src/plugins/record.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export class Record extends Plugin<RecordOptions> implements LDPlugin {
5151
environment: options?.environment || 'production',
5252
appVersion: options?.version,
5353
sessionSecureID: this.sessionSecureID,
54+
privacySetting: options?.privacySetting ?? 'strict',
5455
}
5556

5657
this.record = new RecordSDK(client_options)

0 commit comments

Comments
 (0)