Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/three-lines-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'highlight.run': minor
---

Set up new data emission in highlight SDK from launchdarkly SDK.
* adds H.log function to report custom logs from the highlight SDK
* use traces instead of track events from LD track calls
* record logs for identify integration from LD identify calls
15 changes: 14 additions & 1 deletion sdk/highlight-run/src/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,17 @@ import type { HighlightClientRequestWorker } from './workers/highlight-client-wo
import HighlightClientWorker from './workers/highlight-client-worker?worker&inline'
import { MessageType, PropertyType } from './workers/types'
import { parseError } from './utils/errors'
import { Counter, Gauge, Histogram, UpDownCounter } from '@opentelemetry/api'
import {
Attributes,
Counter,
Gauge,
Histogram,
UpDownCounter,
} from '@opentelemetry/api'
import { IntegrationClient } from '../integrations'
import { LaunchDarklyIntegration } from '../integrations/launchdarkly'
import { LDClientMin } from '../integrations/launchdarkly/types/LDClient'
import { createLog, defaultLogOptions } from './listeners/console-listener'

export const HighlightWarning = (context: string, msg: any) => {
console.warn(`Highlight Warning: (${context}): `, { output: msg })
Expand Down Expand Up @@ -476,6 +483,12 @@ export class Highlight {
}
}

log(message: any, level: string, metadata?: Attributes) {
this._firstLoadListeners.messages.push(
createLog(level, defaultLogOptions, message, metadata),
)
}

pushCustomError(message: string, payload?: string) {
return this.consumeCustomError(new Error(message), undefined, payload)
}
Expand Down
62 changes: 39 additions & 23 deletions sdk/highlight-run/src/client/listeners/console-listener.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { StackFrame } from 'error-stack-parser'
import { ConsoleMethods } from '../types/client'
import { ALL_CONSOLE_METHODS, ConsoleMethods } from '../types/client'
import { ConsoleMessage } from '../types/shared-types'
import { patch, stringify } from '../utils/utils'
import { parseError } from '../utils/errors'
Expand Down Expand Up @@ -51,6 +51,16 @@ export type Logger = {
warn?: typeof console.warn
}

export const defaultLogOptions: LogRecordOptions = {
level: [...ALL_CONSOLE_METHODS],
logger: 'console',
stringifyOptions: {
depthOfLimit: 10,
numOfKeysLimit: 100,
stringLengthLimit: 1000,
},
}

export function ConsoleListener(
callback: (c: ConsoleMessage) => void,
logOptions: LogRecordOptions,
Expand Down Expand Up @@ -115,32 +125,38 @@ export function ConsoleListener(
// @ts-expect-error
original.apply(this, data)
try {
const trace = parseError(new Error())
const message = logOptions.serializeConsoleAttributes
? data.map((o) =>
typeof o === 'object'
? stringify(o, logOptions.stringifyOptions)
: o,
)
: data
.filter((o) => typeof o !== 'object')
.map((o) => `${o}`)
callback({
type: level,
trace: trace.slice(1),
value: message,
attributes: stringify(
data
.filter((d) => typeof d === 'object')
.reduce((a, b) => ({ ...a, ...b }), {}),
logOptions.stringifyOptions,
),
time: Date.now(),
})
callback(createLog(level, logOptions, data))
} catch (error) {
original('highlight logger error:', error, ...data)
}
}
})
}
}

export function createLog(
level: string,
logOptions: LogRecordOptions,
...data: Array<any>
) {
const trace = parseError(new Error())
const message = logOptions.serializeConsoleAttributes
? data.map((o) =>
typeof o === 'object'
? stringify(o, logOptions.stringifyOptions)
: o,
)
: data.filter((o) => typeof o !== 'object').map((o) => `${o}`)
return {
type: level,
trace: trace.slice(1),
value: message,
attributes: stringify(
data
.filter((d) => typeof d === 'object')
.reduce((a, b) => ({ ...a, ...b }), {}),
logOptions.stringifyOptions,
),
time: Date.now(),
}
}
3 changes: 2 additions & 1 deletion sdk/highlight-run/src/client/types/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Context, Span, SpanOptions } from '@opentelemetry/api'
import { Attributes, Context, Span, SpanOptions } from '@opentelemetry/api'
import {
ConsoleMethods,
DebugOptions,
Expand Down Expand Up @@ -288,6 +288,7 @@ export declare interface HighlightPublicInterface {
* @param metadata Additional details you want to associate to the event.
*/
track: (event: string, metadata?: Metadata) => void
log: (message: any, level: string, metadata?: Attributes) => void
/**
* @deprecated with replacement by `consumeError` for an in-app stacktrace.
*/
Expand Down
27 changes: 23 additions & 4 deletions sdk/highlight-run/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ import {
loadCookieSessionData,
} from './client/utils/sessionStorage/highlightSession.js'
import { setCookieWriteEnabled } from './client/utils/storage'
import { Context, Span, SpanOptions, Tracer } from '@opentelemetry/api'
import {
Attributes,
Context,
Span,
SpanOptions,
Tracer,
} from '@opentelemetry/api'
import firstloadVersion from './__generated/version.js'
import { listenToChromeExtensionMessage } from './browserExtension/extensionListener.js'
import configureElectronHighlight from './environments/electron.js'
Expand Down Expand Up @@ -263,9 +269,13 @@ const H: HighlightPublicInterface = {
},
track: (event: string, metadata: Metadata = {}) => {
try {
H.onHighlightReady(() =>
highlight_obj.addProperties({ ...metadata, event: event }),
)
H.onHighlightReady(() => {
highlight_obj.addProperties({ ...metadata, event: event })
highlight_obj.log('H.track', 'INFO', {
...(metadata ?? {}),
event,
})
})
const highlightUrl = highlight_obj?.getCurrentSessionURL()

if (!H.options?.integrations?.mixpanel?.disabled) {
Expand Down Expand Up @@ -295,6 +305,15 @@ const H: HighlightPublicInterface = {
HighlightWarning('track', e)
}
},
log: (message: any, level: string, metadata?: Attributes) => {
try {
H.onHighlightReady(() =>
highlight_obj.log(message, level, metadata ?? {}),
)
} catch (e) {
HighlightWarning('log', e)
}
},
start: (options) => {
if (highlight_obj?.state === 'Recording' && !options?.forceNew) {
if (!options?.silent) {
Expand Down
31 changes: 13 additions & 18 deletions sdk/highlight-run/src/integrations/launchdarkly/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
IdentifySeriesData,
IdentifySeriesResult,
} from './types/Hooks'
import { trace } from '@opentelemetry/api'
import { type HighlightPublicInterface, MetricCategory } from '../../client'
import type { ErrorMessage, Source } from '../../client/types/shared-types'
import type { IntegrationClient } from '../index'
Expand Down Expand Up @@ -66,9 +65,16 @@ export function setupLaunchDarklyIntegration(
data: IdentifySeriesData,
_result: IdentifySeriesResult,
) => {
hClient.log('LD.identify', 'INFO', {
key: getCanonicalKey(hookContext.context),
timeout: hookContext.timeout,
})
hClient.identify(
getCanonicalKey(hookContext.context),
hookContext.context,
{
key: getCanonicalKey(hookContext.context),
timeout: hookContext.timeout,
},
'LaunchDarkly',
)
return data
Expand All @@ -87,18 +93,11 @@ export function setupLaunchDarklyIntegration(
getCanonicalKey(hookContext.context)
}

let span = trace.getActiveSpan()
if (span) {
span.addEvent(FEATURE_FLAG_SCOPE, eventAttributes)
} else {
hClient.startSpan(FEATURE_FLAG_SPAN_NAME, (s) => {
if (s) {
s.addEvent(FEATURE_FLAG_SCOPE, eventAttributes)
}
})
}

hClient.track(FEATURE_FLAG_SPAN_NAME, eventAttributes)
hClient.startSpan(FEATURE_FLAG_SPAN_NAME, (s) => {
if (s) {
s.addEvent(FEATURE_FLAG_SCOPE, eventAttributes)
}
})

return data
},
Expand Down Expand Up @@ -154,10 +153,6 @@ export class LaunchDarklyIntegration implements IntegrationClient {

track(sessionSecureID: string, metadata: object) {
const event = (metadata as unknown as { event?: string }).event
// skip integration hClient.track() calls
if (event === FEATURE_FLAG_SPAN_NAME) {
return
}
this.client.track(
event ? `${LD_TRACK_EVENT}:${event}` : LD_TRACK_EVENT,
{
Expand Down
Loading