Skip to content

Commit 72c6594

Browse files
committed
WIP
1 parent 2211bd3 commit 72c6594

File tree

7 files changed

+1784
-0
lines changed

7 files changed

+1784
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { LDClientMin } from '../integrations/launchdarkly/types/LDClient'
2+
import type { Observability } from './observability'
3+
import type { Record } from './replay'
4+
5+
export interface Client extends Record, Observability {
6+
registerLD: (client: LDClientMin) => void
7+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import type { Context, Span, SpanOptions } from '@opentelemetry/api'
2+
import type { Metric } from '../client'
3+
import type { ErrorMessageType } from '../client/types/shared-types'
4+
5+
export interface Observability {
6+
7+
/**
8+
* @deprecated with replacement by `consumeError` for an in-app stacktrace.
9+
*/
10+
error: (message: string, payload?: { [key: string]: string }) => void
11+
/**
12+
* Calling this method will report metrics to Highlight. You can graph metrics or configure
13+
* alerts on metrics that exceed a threshold.
14+
* @see {@link https://docs.highlight.run/frontend-observability} for more information.
15+
*/
16+
metrics: (metrics: Metric[]) => void
17+
/**
18+
* Record arbitrary metric values via as a Gauge.
19+
* A Gauge records any point-in-time measurement, such as the current CPU utilization %.
20+
* Values with the same metric name and attributes are aggregated via the OTel SDK.
21+
* See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
22+
*/
23+
recordMetric: (metric: Metric) => void
24+
/**
25+
* Record arbitrary metric values via as a Counter.
26+
* A Counter efficiently records an increment in a metric, such as number of cache hits.
27+
* Values with the same metric name and attributes are aggregated via the OTel SDK.
28+
* See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
29+
*/
30+
recordCount: (metric: Metric) => void
31+
/**
32+
* Record arbitrary metric values via as a Counter.
33+
* A Counter efficiently records an increment in a metric, such as number of cache hits.
34+
* Values with the same metric name and attributes are aggregated via the OTel SDK.
35+
* See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
36+
*/
37+
recordIncr: (metric: Omit<Metric, 'value'>) => void
38+
/**
39+
* Record arbitrary metric values via as a Histogram.
40+
* A Histogram efficiently records near-by point-in-time measurement into a bucketed aggregate.
41+
* Values with the same metric name and attributes are aggregated via the OTel SDK.
42+
* See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
43+
*/
44+
recordHistogram: (metric: Metric) => void
45+
/**
46+
* Record arbitrary metric values via as a UpDownCounter.
47+
* A UpDownCounter efficiently records an increment or decrement in a metric, such as number of paying customers.
48+
* Values with the same metric name and attributes are aggregated via the OTel SDK.
49+
* See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
50+
*/
51+
recordUpDownCounter: (metric: Metric) => void
52+
/**
53+
* Starts a new span for tracing in Highlight. The span will be ended when the
54+
* callback function returns.
55+
*
56+
* @example
57+
* ```typescript
58+
* H.startSpan('span-name', callbackFn)
59+
* ```
60+
* @example
61+
* ```typescript
62+
* H.startSpan('span-name', options, callbackFn)
63+
* ```
64+
* @example
65+
* ```typescript
66+
* H.startSpan('span-name', options, context, callbackFn)
67+
* ```
68+
* @example
69+
* ```typescript
70+
* H.startSpan('span-name', async (span) => {
71+
* span.setAttribute('key', 'value')
72+
* await someAsyncFunction()
73+
* })
74+
* ```
75+
*
76+
* @param name The name of the span.
77+
* @param options Options for the span.
78+
* @param context The context for the span.
79+
* @param callbackFn The function to run in the span.
80+
*/
81+
startSpan: {
82+
<F extends (span?: Span) => ReturnType<F>>(
83+
name: string,
84+
fn: F,
85+
): ReturnType<F>
86+
<F extends (span?: Span) => ReturnType<F>>(
87+
name: string,
88+
options: SpanOptions,
89+
fn: F,
90+
): ReturnType<F>
91+
<F extends (span?: Span) => ReturnType<F>>(
92+
name: string,
93+
options: SpanOptions,
94+
context: Context,
95+
fn: F,
96+
): ReturnType<F>
97+
}
98+
/**
99+
* Starts a new span for tracing in Highlight. The span will be ended when the
100+
* `end()` is called on the span. It returns whatever is returned from the
101+
* callback function.
102+
*
103+
* @example
104+
* ```typescript
105+
* H.startManualSpan('span-name', options, (span) => {
106+
* span.addEvent('event-name', { key: 'value' })
107+
* span.setAttribute('key', 'value')
108+
* await someAsyncFunction()
109+
* span.end()
110+
* })
111+
* ```
112+
*
113+
* @example
114+
* ```typescript
115+
* const span = H.startManualSpan('span-name', (s) => s)
116+
* span.addEvent('event-name', { key: 'value' })
117+
* await someAsyncFunction()
118+
* span.end()
119+
* ```
120+
*
121+
* @param name The name of the span.
122+
* @param options Options for the span.
123+
* @param context The context for the span.
124+
* @param fn The function to run in the span.
125+
*/
126+
startManualSpan: {
127+
<F extends (span: Span) => ReturnType<F>>(
128+
name: string,
129+
fn: F,
130+
): ReturnType<F>
131+
<F extends (span: Span) => ReturnType<F>>(
132+
name: string,
133+
options: SpanOptions,
134+
fn: F,
135+
): ReturnType<F>
136+
<F extends (span: Span) => ReturnType<F>>(
137+
name: string,
138+
options: SpanOptions,
139+
context: Context,
140+
fn: F,
141+
): ReturnType<F>
142+
}
143+
/**
144+
* Calling this method will report an error in Highlight and map it to the current session being recorded.
145+
* A common use case for `H.error` is calling it right outside of an error boundary.
146+
* @see {@link https://docs.highlight.run/grouping-errors} for more information.
147+
*/
148+
consumeError: (
149+
error: Error,
150+
message?: string,
151+
payload?: { [key: string]: string },
152+
) => void
153+
/**
154+
* Calling this method will report an error in Highlight
155+
* while allowing additional attributes to be sent over as metadata.
156+
* @see {consumeError} for more information.
157+
*/
158+
consume: (
159+
error: Error,
160+
opts: {
161+
message?: string
162+
payload?: object
163+
source?: string
164+
type?: ErrorMessageType
165+
},
166+
) => void
167+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { Source } from '../client/types/shared-types'
2+
import type {
3+
HighlightOptions,
4+
SessionDetails,
5+
StartOptions,
6+
} from '../client/types/types'
7+
8+
export interface Record {
9+
init: (
10+
projectID?: string | number,
11+
debug?: HighlightOptions,
12+
) => { sessionSecureID: string } | undefined
13+
/**
14+
* Calling this will assign an identifier to the session.
15+
* @example identify('teresa@acme.com', { accountAge: 3, cohort: 8 })
16+
* @param identifier Is commonly set as an email or UUID.
17+
* @param metadata Additional details you want to associate to the user.
18+
*/
19+
identify: (identifier: string, metadata?: Metadata, source?: Source) => void
20+
/**
21+
* Call this to record when you want to track a specific event happening in your application.
22+
* @example track('startedCheckoutProcess', { cartSize: 10, value: 85 })
23+
* @param event The name of the event.
24+
* @param metadata Additional details you want to associate to the event.
25+
*/
26+
track: (event: string, metadata?: Metadata) => void
27+
28+
getSession: () => SessionDetails | null
29+
start: (options?: StartOptions) => void
30+
/** Stops the session and error recording. */
31+
stop: (options?: StartOptions) => void
32+
getRecordingState: () => 'NotRecording' | 'Recording'
33+
snapshot: (element: HTMLCanvasElement) => Promise<void>
34+
}

sdk/highlight-run/src/sdk.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import type { Client } from '../api/client'
2+
3+
class SDK implements Client {
4+
constructor() {
5+
this.load()
6+
}
7+
8+
async load() {
9+
const modules = {
10+
record: import('./sdk/record'),
11+
observability: import('./sdk/observability'),
12+
}
13+
}
14+
15+
registerLD(client) {
16+
// TODO(vkorolik): consolidate once firstload/client are merged
17+
// client integration necessary to track events from ErrorListener
18+
H.onHighlightReady(() => {
19+
highlight_obj.registerLD(client)
20+
})
21+
// firstload integration necessary to immediately capture ld.identify
22+
setupLaunchDarklyIntegration(this, client)
23+
}
24+
}
25+
26+
// sdk-core.js
27+
class SDKCore {
28+
constructor() {
29+
if (SDKCore._instance) {
30+
return SDKCore._instance
31+
}
32+
SDKCore._instance = this
33+
this._modules = {}
34+
return this
35+
}
36+
37+
use(module) {
38+
if (!module.name) {
39+
throw new Error("Module must have a 'name' property.")
40+
}
41+
this._modules[module.name] = module
42+
}
43+
44+
// Provide simpler named getters:
45+
get moduleA() {
46+
return this.getModule('moduleA')
47+
}
48+
49+
get moduleB() {
50+
return this.getModule('moduleB')
51+
}
52+
53+
// Internal method still uses Proxy fallback
54+
getModule(name) {
55+
const module = this._modules[name]
56+
if (!module) {
57+
return new Proxy(
58+
{},
59+
{
60+
get() {
61+
return () => {}
62+
},
63+
},
64+
)
65+
}
66+
return module
67+
}
68+
}
69+
70+
const instance = new SDKCore()
71+
export default instance
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Span, SpanOptions, Context } from '@opentelemetry/api'
2+
import { Metric } from 'client'
3+
import { ErrorMessageType } from 'client/types/shared-types'
4+
import type { Observability } from '../api/observability'
5+
6+
export class ObservabilitySDK implements Observability {
7+
error: (message: string, payload?: { [key: string]: string }) => void
8+
metrics: (metrics: Metric[]) => void
9+
recordMetric: (metric: Metric) => void
10+
recordCount: (metric: Metric) => void
11+
recordIncr: (metric: Omit<Metric, 'value'>) => void
12+
recordHistogram: (metric: Metric) => void
13+
recordUpDownCounter: (metric: Metric) => void
14+
startSpan: {
15+
<F extends (span?: Span) => ReturnType<F>>(
16+
name: string,
17+
fn: F,
18+
): ReturnType<F>
19+
<F extends (span?: Span) => ReturnType<F>>(
20+
name: string,
21+
options: SpanOptions,
22+
fn: F,
23+
): ReturnType<F>
24+
<F extends (span?: Span) => ReturnType<F>>(
25+
name: string,
26+
options: SpanOptions,
27+
context: Context,
28+
fn: F,
29+
): ReturnType<F>
30+
}
31+
startManualSpan: {
32+
<F extends (span: Span) => ReturnType<F>>(
33+
name: string,
34+
fn: F,
35+
): ReturnType<F>
36+
<F extends (span: Span) => ReturnType<F>>(
37+
name: string,
38+
options: SpanOptions,
39+
fn: F,
40+
): ReturnType<F>
41+
<F extends (span: Span) => ReturnType<F>>(
42+
name: string,
43+
options: SpanOptions,
44+
context: Context,
45+
fn: F,
46+
): ReturnType<F>
47+
}
48+
consumeError: (
49+
error: Error,
50+
message?: string,
51+
payload?: { [key: string]: string },
52+
) => void
53+
consume: (
54+
error: Error,
55+
opts: {
56+
message?: string
57+
payload?: object
58+
source?: string
59+
type?: ErrorMessageType
60+
},
61+
) => void
62+
}

0 commit comments

Comments
 (0)