@multiplayer-app/session-recorder-common 1.3.37 → 2.0.17-alpha.10

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.
Files changed (46) hide show
  1. package/package.json +2 -2
  2. package/dist/esm/tsconfig.esm.tsbuildinfo +0 -1
  3. package/dist/esnext/tsconfig.esnext.tsbuildinfo +0 -1
  4. package/docs/img/header-js.png +0 -0
  5. package/eslint.config.js +0 -226
  6. package/src/SessionRecorderIdGenerator.ts +0 -70
  7. package/src/SessionRecorderTraceIdRatioBasedSampler.ts +0 -89
  8. package/src/constants/constants.base.ts +0 -111
  9. package/src/constants/constants.browser.ts +0 -1
  10. package/src/constants/constants.node.ts +0 -5
  11. package/src/exporters/SessionRecorderBrowserTraceExporter.ts +0 -196
  12. package/src/exporters/SessionRecorderGrpcLogsExporter.ts +0 -52
  13. package/src/exporters/SessionRecorderGrpcTraceExporter.ts +0 -50
  14. package/src/exporters/SessionRecorderHttpLogsExporter.ts +0 -58
  15. package/src/exporters/SessionRecorderHttpTraceExporter.ts +0 -68
  16. package/src/exporters/SessionRecorderLogsExporterWrapper.ts +0 -36
  17. package/src/exporters/SessionRecorderTraceExporterWrapper.ts +0 -36
  18. package/src/exporters/index-browser.ts +0 -1
  19. package/src/exporters/index-node.ts +0 -6
  20. package/src/exporters/index.ts +0 -7
  21. package/src/index-browser.ts +0 -6
  22. package/src/index-node.ts +0 -7
  23. package/src/index.ts +0 -7
  24. package/src/instrumentations/SessionRecorderHttpInstrumentationHooksNode.ts +0 -356
  25. package/src/instrumentations/index-node.ts +0 -1
  26. package/src/sdk/capture-exception.ts +0 -102
  27. package/src/sdk/id-generator.ts +0 -17
  28. package/src/sdk/index.ts +0 -8
  29. package/src/sdk/is-gzip.ts +0 -7
  30. package/src/sdk/mask.ts +0 -161
  31. package/src/sdk/save-continuous-deb-session.ts +0 -28
  32. package/src/sdk/schemify.ts +0 -57
  33. package/src/sdk/set-attribute.ts +0 -210
  34. package/src/sdk/set-resource-attributes.ts +0 -9
  35. package/src/type/crash-buffer.ts +0 -64
  36. package/src/type/index.ts +0 -4
  37. package/src/type/session-type.enum.ts +0 -20
  38. package/src/type/session.ts +0 -84
  39. package/src/type/user-type.enum.ts +0 -5
  40. package/tsconfig.base.es5.json +0 -8
  41. package/tsconfig.base.esm.json +0 -7
  42. package/tsconfig.base.esnext.json +0 -10
  43. package/tsconfig.base.json +0 -38
  44. package/tsconfig.esm.json +0 -12
  45. package/tsconfig.esnext.json +0 -12
  46. package/tsconfig.json +0 -25
@@ -1,89 +0,0 @@
1
-
2
- import {
3
- isValidTraceId,
4
- Context,
5
- SpanKind,
6
- Attributes,
7
- Link,
8
- } from '@opentelemetry/api'
9
- import {
10
- Sampler,
11
- SamplingDecision,
12
- SamplingResult,
13
- } from '@opentelemetry/sdk-trace-base'
14
- import {
15
- ATTR_EXCEPTION_MESSAGE,
16
- ATTR_EXCEPTION_STACKTRACE,
17
- ATTR_EXCEPTION_TYPE,
18
- } from '@opentelemetry/semantic-conventions'
19
- import {
20
- MULTIPLAYER_TRACE_DEBUG_PREFIX,
21
- MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
22
- MULTIPLAYER_TRACE_SESSION_CACHE_PREFIX,
23
- // MULTIPLAYER_TRACE_CONTINUOUS_SESSION_CACHE_PREFIX,
24
- } from './constants/constants.base'
25
-
26
- export class SessionRecorderTraceIdRatioBasedSampler implements Sampler {
27
- private _upperBound: number
28
-
29
- constructor(private readonly _ratio: number = 0) {
30
- this._ratio = this._normalize(_ratio)
31
- this._upperBound = Math.floor(this._ratio * 0xffffffff)
32
- }
33
-
34
- shouldSample(
35
- context: Context,
36
- traceId: string,
37
- spanName: string,
38
- spanKind: SpanKind,
39
- attributes: Attributes,
40
- links: Link[],
41
- ): SamplingResult {
42
- if (attributes[ATTR_EXCEPTION_MESSAGE] || attributes[ATTR_EXCEPTION_STACKTRACE] || attributes[ATTR_EXCEPTION_TYPE]) {
43
- return {
44
- decision: SamplingDecision.RECORD_AND_SAMPLED,
45
- }
46
- }
47
-
48
- if (
49
- traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX)
50
- || traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
51
- || traceId.startsWith(MULTIPLAYER_TRACE_SESSION_CACHE_PREFIX)
52
- // || traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_SESSION_CACHE_PREFIX)
53
- ) {
54
- return {
55
- decision: SamplingDecision.RECORD_AND_SAMPLED,
56
- }
57
- }
58
-
59
- let decision: SamplingDecision = SamplingDecision.NOT_RECORD
60
-
61
- if (
62
- isValidTraceId(traceId)
63
- && this._accumulate(traceId) < this._upperBound
64
- ) {
65
- decision = SamplingDecision.RECORD_AND_SAMPLED
66
- }
67
-
68
- return { decision }
69
- }
70
-
71
- toString(): string {
72
- return `SessionRecorderTraceIdRatioBasedSampler{${this._ratio}}`
73
- }
74
-
75
- private _normalize(ratio: number): number {
76
- if (typeof ratio !== 'number' || isNaN(ratio)) return 0
77
- return ratio >= 1 ? 1 : ratio <= 0 ? 0 : ratio
78
- }
79
-
80
- private _accumulate(traceId: string): number {
81
- let accumulation = 0
82
- for (let i = 0; i < traceId.length / 8; i++) {
83
- const pos = i * 8
84
- const part = parseInt(traceId.slice(pos, pos + 8), 16)
85
- accumulation = (accumulation ^ part) >>> 0
86
- }
87
- return accumulation
88
- }
89
- }
@@ -1,111 +0,0 @@
1
- import { SessionType } from '../type'
2
-
3
- /**
4
- * @deprecated
5
- */
6
- export const MULTIPLAYER_TRACE_DOC_PREFIX = 'd0cd0c'
7
-
8
- export const MULTIPLAYER_TRACE_DEBUG_PREFIX = 'debdeb'
9
-
10
- export const MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX = 'cdbcdb'
11
-
12
- export const MULTIPLAYER_TRACE_SESSION_PREFIX = 'cdbcac'
13
-
14
- export const MULTIPLAYER_TRACE_SESSION_CACHE_PREFIX = 'debcdb'
15
-
16
- export const MULTIPLAYER_TRACE_PREFIX_MAP = {
17
- [SessionType.CONTINUOUS]: MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
18
- [SessionType.SESSION_CACHE]: MULTIPLAYER_TRACE_SESSION_CACHE_PREFIX,
19
- [SessionType.SESSION]: MULTIPLAYER_TRACE_SESSION_PREFIX,
20
- [SessionType.MANUAL]: MULTIPLAYER_TRACE_DEBUG_PREFIX,
21
- } as Record<SessionType, string>
22
-
23
- export const MULTIPLAYER_TRACE_DEBUG_SESSION_SHORT_ID_LENGTH = 8
24
-
25
- export const MULTIPLAYER_TRACE_CLIENT_ID_LENGTH = 4
26
-
27
- /**
28
- * @deprecated Use MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL instead
29
- */
30
- export const MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_URL = 'https://api.multiplayer.app/v1/traces'
31
-
32
- /**
33
- * @deprecated Use MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_HTTP_URL instead
34
- */
35
- export const MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_URL = 'https://api.multiplayer.app/v1/logs'
36
-
37
- export const MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL = 'https://otlp.multiplayer.app/v1/traces'
38
-
39
- export const MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_HTTP_URL = 'https://otlp.multiplayer.app/v1/logs'
40
-
41
- export const MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_GRPC_URL = 'https://otlp.multiplayer.app:4317/v1/traces'
42
-
43
- export const MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_GRPC_URL = 'https://otlp.multiplayer.app:4317/v1/logs'
44
-
45
- export const MULTIPLAYER_BASE_API_URL = 'https://api.multiplayer.app'
46
-
47
- export const MULTIPLAYER_ATTRIBUTE_PREFIX = 'multiplayer.'
48
-
49
- export const ATTR_MULTIPLAYER_WORKSPACE_ID = 'multiplayer.workspace.id'
50
-
51
- export const ATTR_MULTIPLAYER_PROJECT_ID = 'multiplayer.project.id'
52
-
53
- export const ATTR_MULTIPLAYER_PLATFORM_ID = 'multiplayer.platform.id'
54
-
55
- export const ATTR_MULTIPLAYER_CONTINUOUS_SESSION_AUTO_SAVE = 'multiplayer.session.auto-save'
56
-
57
- export const ATTR_MULTIPLAYER_CONTINUOUS_SESSION_AUTO_SAVE_REASON = 'multiplayer.session.auto-save.reason'
58
-
59
- export const ATTR_MULTIPLAYER_PLATFORM_NAME = 'multiplayer.platform.name'
60
-
61
- export const ATTR_MULTIPLAYER_CLIENT_ID = 'multiplayer.client.id'
62
-
63
- export const ATTR_MULTIPLAYER_INTEGRATION_ID = 'multiplayer.integration.id'
64
-
65
- export const ATTR_MULTIPLAYER_SESSION_ID = 'multiplayer.session.id'
66
-
67
- export const ATTR_MULTIPLAYER_SESSION_CLIENT_ID = 'multiplayer.session.client.id'
68
-
69
- export const ATTR_MULTIPLAYER_HTTP_PROXY = 'multiplayer.http.proxy'
70
-
71
- export const ATTR_MULTIPLAYER_HTTP_PROXY_TYPE = 'multiplayer.http.proxy.type'
72
-
73
- export const ATTR_MULTIPLAYER_HTTP_REQUEST_BODY = 'multiplayer.http.request.body'
74
-
75
- export const ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY = 'multiplayer.http.response.body'
76
-
77
- export const ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS = 'multiplayer.http.request.headers'
78
-
79
- export const ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS = 'multiplayer.http.response.headers'
80
-
81
- export const ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY_ENCODING = 'multiplayer.http.response.body.encoding'
82
-
83
- export const ATTR_MULTIPLAYER_RPC_REQUEST_MESSAGE = 'multiplayer.rpc.request.message'
84
-
85
- export const ATTR_MULTIPLAYER_RPC_REQUEST_MESSAGE_ENCODING = 'multiplayer.rpc.request.message.encoding'
86
-
87
- export const ATTR_MULTIPLAYER_RPC_RESPONSE_MESSAGE = 'multiplayer.rpc.response.message'
88
-
89
- export const ATTR_MULTIPLAYER_GRPC_REQUEST_MESSAGE = 'multiplayer.rpc.grpc.request.message'
90
-
91
- export const ATTR_MULTIPLAYER_GRPC_REQUEST_MESSAGE_ENCODING = 'multiplayer.rpc.request.message.encoding'
92
-
93
- export const ATTR_MULTIPLAYER_GRPC_RESPONSE_MESSAGE = 'multiplayer.rpc.grpc.response.message'
94
-
95
- export const ATTR_MULTIPLAYER_MESSAGING_MESSAGE_BODY = 'multiplayer.messaging.message.body'
96
-
97
- export const ATTR_MULTIPLAYER_MESSAGING_MESSAGE_BODY_ENCODING = 'multiplayer.messaging.message.body.encoding'
98
-
99
- export const ATTR_MULTIPLAYER_SESSION_RECORDER_VERSION = 'multiplayer.session-recorder.version'
100
-
101
- export const ATTR_MULTIPLAYER_ISSUE_CUSTOM_HASH = 'multiplayer.issue.custom-hash'
102
-
103
- export const ATTR_MULTIPLAYER_ISSUE_HASH = 'multiplayer.issue.hash'
104
-
105
- export const ATTR_MULTIPLAYER_ISSUE_COMPONENT_HASH = 'multiplayer.issue.component-hash'
106
-
107
- export const ATTR_MULTIPLAYER_ISSUE_TITLE_HASH = 'multiplayer.issue.title-hash'
108
-
109
- export const ATTR_MULTIPLAYER_USER_HASH = 'multiplayer.user.hash'
110
-
111
- export const MASK_PLACEHOLDER = '***MASKED***'
@@ -1 +0,0 @@
1
- export * from './constants.base'
@@ -1,5 +0,0 @@
1
- export * from './constants.base'
2
-
3
- export const MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE = process.env.MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE
4
- ? Number(process.env.MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE)
5
- : 500000
@@ -1,196 +0,0 @@
1
- import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'
2
-
3
- import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
4
- import {
5
- MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL,
6
- MULTIPLAYER_TRACE_DEBUG_PREFIX,
7
- MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
8
- MULTIPLAYER_TRACE_SESSION_CACHE_PREFIX,
9
- } from '../constants/constants.base'
10
-
11
- export interface SessionRecorderBrowserTraceExporterConfig {
12
- /** URL for the OTLP endpoint. Defaults to Multiplayer's default traces endpoint. */
13
- url?: string
14
- /** API key for authentication. Required. */
15
- apiKey?: string
16
- /** Additional headers to include in requests */
17
- headers?: Record<string, string>
18
- /** Request timeout in milliseconds */
19
- timeoutMillis?: number
20
- /** Whether to use keep-alive connections */
21
- keepAlive?: boolean
22
- /** Maximum number of concurrent requests */
23
- concurrencyLimit?: number
24
- /** Whether to use postMessage fallback for cross-origin requests */
25
- usePostMessageFallback?: boolean
26
- /** PostMessage type identifier */
27
- postMessageType?: string
28
- /** PostMessage target origin */
29
- postMessageTargetOrigin?: string
30
- }
31
-
32
- /**
33
- * Browser-specific trace exporter for Session Recorder
34
- * Exports traces via HTTP to Multiplayer's OTLP endpoint with browser-specific optimizations
35
- * Only exports spans with trace IDs starting with Multiplayer prefixes
36
- */
37
- export class SessionRecorderBrowserTraceExporter implements SpanExporter {
38
- private exporter: OTLPTraceExporter
39
- private usePostMessage: boolean = false
40
- private readonly postMessageType: string
41
- private readonly postMessageTargetOrigin: string
42
- private readonly config: SessionRecorderBrowserTraceExporterConfig
43
-
44
- constructor(config: SessionRecorderBrowserTraceExporterConfig = {}) {
45
- const {
46
- url = MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL,
47
- apiKey,
48
- headers = {},
49
- timeoutMillis = 30000,
50
- keepAlive = true,
51
- concurrencyLimit = 20,
52
- postMessageType = 'MULTIPLAYER_SESSION_DEBUGGER_LIB',
53
- postMessageTargetOrigin = '*',
54
- } = config
55
-
56
- this.config = {
57
- ...config,
58
- url,
59
- apiKey,
60
- headers,
61
- keepAlive,
62
- timeoutMillis,
63
- concurrencyLimit,
64
- }
65
- this.postMessageType = postMessageType
66
- this.postMessageTargetOrigin = postMessageTargetOrigin
67
-
68
- this.exporter = this._createExporter()
69
- }
70
- _export(spans: ReadableSpan[], resultCallback: (result: { code: number }) => void): void {
71
- // Only proceed if there are filtered spans
72
- if (spans.length === 0) {
73
- resultCallback({ code: 0 })
74
- return
75
- }
76
-
77
- if (this.usePostMessage) {
78
- this.exportViaPostMessage(spans, resultCallback)
79
- return
80
- }
81
-
82
- this.exporter.export(spans, (result) => {
83
- if (result.code === 0) {
84
- resultCallback(result)
85
- } else if (this.config.usePostMessageFallback) {
86
- this.usePostMessage = true
87
- this.exportViaPostMessage(spans, resultCallback)
88
- } else {
89
- resultCallback(result)
90
- }
91
- })
92
- }
93
-
94
- export(spans: ReadableSpan[], resultCallback: (result: { code: number }) => void): void {
95
- // Filter spans to only include those with Multiplayer trace prefixes
96
- const filteredSpans = spans.filter((span) => {
97
- const traceId = span.spanContext().traceId
98
- return (
99
- traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) ||
100
- traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
101
- )
102
- })
103
- this._export(filteredSpans, resultCallback)
104
- }
105
-
106
- exportBuffer(spans: ReadableSpan[], resultCallback: (result: { code: number }) => void): void {
107
- const filteredSpans = spans.filter((span) => {
108
- const traceId = span.spanContext().traceId
109
- return traceId.startsWith(MULTIPLAYER_TRACE_SESSION_CACHE_PREFIX)
110
- })
111
- this._export(filteredSpans, resultCallback)
112
- }
113
-
114
- shutdown(): Promise<void> {
115
- return this.exporter.shutdown()
116
- }
117
-
118
- private exportViaPostMessage(spans: ReadableSpan[], resultCallback: (result: { code: number }) => void): void {
119
- if (typeof window === 'undefined') {
120
- resultCallback({ code: 1 })
121
- return
122
- }
123
-
124
- try {
125
- window.postMessage(
126
- {
127
- action: 'traces',
128
- type: this.postMessageType,
129
- payload: spans.map((span) => this.serializeSpan(span)),
130
- },
131
- this.postMessageTargetOrigin,
132
- )
133
- resultCallback({ code: 0 })
134
- } catch (e) {
135
- resultCallback({ code: 1 })
136
- }
137
- }
138
-
139
- serializeSpan(span: ReadableSpan): any {
140
- const spanContext = span.spanContext()
141
- const instrumentationScope: any =
142
- // OTel SDK (modern)
143
- (span as any).instrumentationScope ||
144
- // Older SDKs
145
- (span as any).instrumentationLibrary || { name: 'unknown', version: undefined, schemaUrl: undefined }
146
-
147
- const normalizedScope = {
148
- name: instrumentationScope?.name || 'unknown',
149
- version: instrumentationScope?.version,
150
- schemaUrl: instrumentationScope?.schemaUrl,
151
- }
152
- return {
153
- _spanContext: spanContext,
154
- traceId: spanContext.traceId,
155
- spanId: spanContext.spanId,
156
- name: span.name,
157
- kind: span.kind,
158
- links: span.links,
159
- ended: span.ended,
160
- events: span.events,
161
- status: span.status,
162
- endTime: span.endTime,
163
- startTime: span.startTime,
164
- duration: span.duration,
165
- attributes: span.attributes,
166
- parentSpanId: span.parentSpanContext?.spanId,
167
- droppedAttributesCount: span.droppedAttributesCount,
168
- droppedEventsCount: span.droppedEventsCount,
169
- droppedLinksCount: span.droppedLinksCount,
170
- instrumentationScope: normalizedScope,
171
- resource: {
172
- attributes: span.resource.attributes,
173
- asyncAttributesPending: span.resource.asyncAttributesPending,
174
- },
175
- }
176
- }
177
-
178
- private _createExporter(): OTLPTraceExporter {
179
- return new OTLPTraceExporter({
180
- url: this.config.url,
181
- headers: {
182
- 'Content-Type': 'application/json',
183
- ...(this.config.apiKey ? { Authorization: this.config.apiKey } : {}),
184
- ...(this.config.headers || {}),
185
- },
186
- timeoutMillis: this.config.timeoutMillis,
187
- keepAlive: this.config.keepAlive,
188
- concurrencyLimit: this.config.concurrencyLimit,
189
- })
190
- }
191
-
192
- setApiKey(apiKey: string): void {
193
- this.config.apiKey = apiKey
194
- this.exporter = this._createExporter()
195
- }
196
- }
@@ -1,52 +0,0 @@
1
- import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'
2
- import {
3
- MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_GRPC_URL,
4
- MULTIPLAYER_TRACE_DEBUG_PREFIX,
5
- MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
6
- } from '../constants/constants.base'
7
-
8
- export interface SessionRecorderGrpcLogsExporterConfig {
9
- /** The URL to send logs to. Defaults to MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_GRPC_URL */
10
- url?: string
11
- /** API key for authentication. Required. */
12
- apiKey: string
13
- /** Timeout for gRPC requests in milliseconds. Defaults to 30000 */
14
- timeoutMillis?: number
15
- }
16
-
17
- /**
18
- * gRPC logs exporter for Session Recorder
19
- * Exports logs via gRPC to Multiplayer's OTLP endpoint
20
- * Only exports logs with trace IDs starting with Multiplayer prefixes
21
- * Note: API key authentication may need to be handled at the gRPC client level
22
- */
23
- export class SessionRecorderGrpcLogsExporter extends OTLPLogExporter {
24
- constructor(config: SessionRecorderGrpcLogsExporterConfig) {
25
- const {
26
- url = MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_GRPC_URL,
27
- timeoutMillis = 30000,
28
- } = config
29
-
30
- super({
31
- url,
32
- timeoutMillis,
33
- })
34
- }
35
-
36
- override export(logs: any[], resultCallback: (result: { code: number }) => void): void {
37
- // Filter logs to only include those with Multiplayer trace prefixes
38
- const filteredLogs = logs.filter(log => {
39
- const traceId = log.spanContext?.traceId || log.traceId
40
- return traceId && (traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) ||
41
- traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX))
42
- })
43
-
44
- // Only proceed if there are filtered logs
45
- if (filteredLogs.length === 0) {
46
- resultCallback({ code: 0 })
47
- return
48
- }
49
-
50
- super.export(filteredLogs, resultCallback)
51
- }
52
- }
@@ -1,50 +0,0 @@
1
- import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'
2
- import {
3
- MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_GRPC_URL,
4
- MULTIPLAYER_TRACE_DEBUG_PREFIX,
5
- MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
6
- } from '../constants/constants.base'
7
-
8
- export interface SessionRecorderGrpcTraceExporterConfig {
9
- /** The URL to send traces to. Defaults to MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_GRPC_URL */
10
- url?: string
11
- /** API key for authentication. Required. */
12
- apiKey: string
13
- /** Timeout for gRPC requests in milliseconds. Defaults to 30000 */
14
- timeoutMillis?: number
15
- }
16
-
17
- /**
18
- * gRPC trace exporter for Session Recorder
19
- * Exports traces via gRPC to Multiplayer's OTLP endpoint
20
- * Only exports spans with trace IDs starting with Multiplayer prefixes
21
- * Note: API key authentication may need to be handled at the gRPC client level
22
- */
23
- export class SessionRecorderGrpcTraceExporter extends OTLPTraceExporter {
24
- constructor(config: SessionRecorderGrpcTraceExporterConfig) {
25
- const {
26
- url = MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_GRPC_URL,
27
- timeoutMillis = 30000,
28
- } = config
29
-
30
- super({
31
- url,
32
- timeoutMillis,
33
- })
34
- }
35
-
36
- override export(spans: any[], resultCallback: (result: { code: number }) => void): void {
37
- const filteredSpans = spans.filter(span => {
38
- const traceId = span.spanContext().traceId
39
- return traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) ||
40
- traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
41
- })
42
-
43
- if (filteredSpans.length === 0) {
44
- resultCallback({ code: 0 })
45
- return
46
- }
47
-
48
- super.export(filteredSpans, resultCallback)
49
- }
50
- }
@@ -1,58 +0,0 @@
1
- import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'
2
- import {
3
- MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_HTTP_URL,
4
- MULTIPLAYER_TRACE_DEBUG_PREFIX,
5
- MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
6
- } from '../constants/constants.base'
7
-
8
- export interface SessionRecorderHttpLogsExporterConfig {
9
- /** The URL to send logs to. Defaults to MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_HTTP_URL */
10
- url?: string
11
- /** API key for authentication. Required. */
12
- apiKey: string
13
- /** Timeout for HTTP requests in milliseconds. Defaults to 30000 */
14
- timeoutMillis?: number
15
- /** Whether to keep the connection alive. Defaults to true */
16
- keepAlive?: boolean
17
- /** Maximum number of concurrent requests. Defaults to 20 */
18
- concurrencyLimit?: number
19
- }
20
-
21
- export class SessionRecorderHttpLogsExporter extends OTLPLogExporter {
22
- constructor(config: SessionRecorderHttpLogsExporterConfig) {
23
- const {
24
- url = MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_HTTP_URL,
25
- apiKey,
26
- timeoutMillis = 30000,
27
- keepAlive = true,
28
- concurrencyLimit = 20,
29
- } = config
30
-
31
- super({
32
- url,
33
- headers: {
34
- 'Content-Type': 'application/json',
35
- 'User-Agent': '@multiplayer-app/session-recorder-common/1.0.0',
36
- 'authorization': apiKey,
37
- },
38
- timeoutMillis,
39
- keepAlive,
40
- concurrencyLimit,
41
- })
42
- }
43
-
44
- override export(logs: any[], resultCallback: (result: { code: number }) => void): void {
45
- const filteredLogs = logs.filter(log => {
46
- const traceId = log.spanContext?.traceId || log.traceId
47
- return traceId && (traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) ||
48
- traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX))
49
- })
50
-
51
- if (filteredLogs.length === 0) {
52
- resultCallback({ code: 0 })
53
- return
54
- }
55
-
56
- super.export(filteredLogs, resultCallback)
57
- }
58
- }
@@ -1,68 +0,0 @@
1
- import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
2
- import {
3
- MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL,
4
- MULTIPLAYER_TRACE_DEBUG_PREFIX,
5
- MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
6
- } from '../constants/constants.base'
7
-
8
- export interface SessionRecorderHttpTraceExporterConfig {
9
- /** The URL to send traces to. Defaults to MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL */
10
- url?: string
11
- /** API key for authentication. Required. */
12
- apiKey: string
13
- /** Timeout for HTTP requests in milliseconds. Defaults to 30000 */
14
- timeoutMillis?: number
15
- /** Whether to keep the connection alive. Defaults to true */
16
- keepAlive?: boolean
17
- /** Maximum number of concurrent requests. Defaults to 20 */
18
- concurrencyLimit?: number
19
- }
20
-
21
- /**
22
- * HTTP trace exporter for Session Recorder
23
- * Exports traces via HTTP to Multiplayer's OTLP endpoint
24
- * Only exports spans with trace IDs starting with Multiplayer prefixes
25
- */
26
- export class SessionRecorderHttpTraceExporter extends OTLPTraceExporter {
27
- constructor(config: SessionRecorderHttpTraceExporterConfig) {
28
- const {
29
- url = MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL,
30
- apiKey,
31
- timeoutMillis = 30000,
32
- keepAlive = true,
33
- concurrencyLimit = 20,
34
- } = config
35
-
36
- super({
37
- url,
38
- headers: {
39
- 'Content-Type': 'application/json',
40
- 'User-Agent': '@multiplayer-app/session-recorder-common/1.0.0',
41
- ...apiKey
42
- ? { 'Authorization': apiKey }
43
- : {},
44
- },
45
- timeoutMillis,
46
- keepAlive,
47
- concurrencyLimit,
48
- })
49
- }
50
-
51
- override export(
52
- spans: any[],
53
- resultCallback: (result: { code: number }) => void,
54
- ): void {
55
- const filteredSpans = spans.filter(span => {
56
- const traceId = span.spanContext().traceId
57
- return traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) ||
58
- traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
59
- })
60
-
61
- if (filteredSpans.length === 0) {
62
- resultCallback({ code: 0 })
63
- return
64
- }
65
-
66
- super.export(filteredSpans, resultCallback)
67
- }
68
- }
@@ -1,36 +0,0 @@
1
- import { SdkLogRecord, LogRecordExporter } from '@opentelemetry/sdk-logs'
2
- import {
3
- MULTIPLAYER_TRACE_DEBUG_PREFIX,
4
- MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
5
- } from '../constants/constants.base'
6
-
7
- export interface SessionRecorderLogsExporterWrapperConfig {
8
- exporter: LogRecordExporter
9
- }
10
-
11
- export class SessionRecorderLogsExporterWrapper implements LogRecordExporter {
12
- private readonly exporter: LogRecordExporter
13
-
14
- constructor(config: SessionRecorderLogsExporterWrapperConfig) {
15
- this.exporter = config.exporter
16
- }
17
-
18
- export(logs: SdkLogRecord[], resultCallback: (result: { code: number }) => void): void {
19
- const filteredLogs = logs.filter(log => {
20
- const traceId = log.spanContext?.traceId
21
- return !traceId || (!traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) &&
22
- !traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX))
23
- })
24
-
25
- if (filteredLogs.length === 0) {
26
- resultCallback({ code: 0 })
27
- return
28
- }
29
-
30
- this.exporter.export(filteredLogs, resultCallback)
31
- }
32
-
33
- shutdown(): Promise<void> {
34
- return this.exporter.shutdown()
35
- }
36
- }