@multiplayer-app/session-recorder-common
Version:
Multiplayer Fullstack Session Recorder - opentelemetry
261 lines (212 loc) • 9.96 kB
Markdown

<div align="center">
<a href="https://github.com/multiplayer-app/multiplayer-session-recorder-javascript">
<img src="https://img.shields.io/github/stars/multiplayer-app/multiplayer-session-recorder-javascript?style=social&label=Star&maxAge=2592000" alt="GitHub stars">
</a>
<a href="https://github.com/multiplayer-app/multiplayer-session-recorder-javascript/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/multiplayer-app/multiplayer-session-recorder-javascript" alt="License">
</a>
<a href="https://multiplayer.app">
<img src="https://img.shields.io/badge/Visit-multiplayer.app-blue" alt="Visit Multiplayer">
</a>
</div>
<div>
<p align="center">
<a href="https://x.com/trymultiplayer">
<img src="https://img.shields.io/badge/Follow%20on%20X-000000?style=for-the-badge&logo=x&logoColor=white" alt="Follow on X" />
</a>
<a href="https://www.linkedin.com/company/multiplayer-app/">
<img src="https://img.shields.io/badge/Follow%20on%20LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white" alt="Follow on LinkedIn" />
</a>
<a href="https://discord.com/invite/q9K3mDzfrx">
<img src="https://img.shields.io/badge/Join%20our%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Join our Discord" />
</a>
</p>
</div>
# Multiplayer Full Stack Session Recorder Common
This package provides implementations of the OpenTelemetry API for trace and metrics. It's intended for use both on the server and in the browser.
## Built-in Implementations
- [Session Recorder OpenTelemetry Core](#session-recorder-opentelemetry-core)
- [Built-in Implementations](#built-in-implementations)
- [Constants](#constants)
- [Setup opentelemetry for capturing http request/response body](#session-recorder-http-instrumentation-hooks-node)
- [Session Recorder Http Trace exporter web](#session-recorder-http-trace-exporter-web)
- [Session Recorder id generator](#session-recorder-id-generator)
- [Trace id ratio based sampler](#trace-id-ratio-based-sampler)
- [Helper for capturing exception in session recording](#helper-for-capturing-exceptions)
- [Helpers for adding content to session recording](#helper-for-setting-attributes-to-span)
- [License](#license)
### Constants
```javascript
import {
MULTIPLAYER_TRACE_DOC_PREFIX,
MULTIPLAYER_TRACE_DEBUG_PREFIX,
MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_URL,
MULTIPLAYER_OTEL_DEFAULT_LOGS_EXPORTER_URL,
MULTIPLAYER_ATTRIBUTE_PREFIX,
MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE,
ATTR_MULTIPLAYER_DEBUG_SESSION,
ATTR_MULTIPLAYER_HTTP_REQUEST_BODY,
ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY,
ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS,
ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS,
ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY_ENCODING,
ATTR_MULTIPLAYER_RPC_REQUEST_MESSAGE,
ATTR_MULTIPLAYER_RPC_RESPONSE_MESSAGE,
ATTR_MULTIPLAYER_GRPC_REQUEST_MESSAGE,
ATTR_MULTIPLAYER_GRPC_RESPONSE_MESSAGE,
ATTR_MULTIPLAYER_MESSAGING_MESSAGE_BODY,
} from '-app/session-recorder-common'
```
### Setup opentelemetry for capturing http request/response body
Session Recorder hooks for nodejs http instrumentation for injecting http request/response headers and payload to span.
```javascript
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
import { type Instrumentation } from '@opentelemetry/instrumentation'
import { SessionRecorderHttpInstrumentationHooks } from '@multiplayer-app/session-recorder-common'
export const instrumentations: Instrumentation[] = getNodeAutoInstrumentations({
'/instrumentation-http': {
enabled: true,
responseHook: SessionRecorderHttpInstrumentationHooks.responseHook({
maxPayloadSizeBytes: 1000,
uncompressPayload: true,
captureHeaders: true,
captureBody: true,
isMaskBodyEnabled: true,
isMaskHeadersEnabled: true,
maskBody: (data, span) => {
// mask logic here
return data
},
maskHeaders: (data, span) => {
// mask logic here
return data
},
maskBodyFieldsList: ['password', 'card'],
maskHeadersList: ['x-trace-id'],
headersToInclude: ['Set-Cookie', 'Authorization'],
headersToExclude: ['Cookie'],
}),
requestHook: SessionRecorderHttpInstrumentationHooks.requestHook({
maxPayloadSizeBytes: 1000,
captureHeaders: true,
captureBody: true,
isMaskBodyEnabled: true,
isMaskHeadersEnabled: true,
maskBody: (data, span) => {
// mask logic here
return data
},
maskHeaders: (data, span) => {
// mask logic here
return data
},
maskBodyFieldsList: ['password', 'card'],
maskHeadersList: ['x-trace-id'],
headersToInclude: ['Set-Cookie', 'Authorization'],
headersToExclude: ['Cookie'],
}),
},
)
```
### Session Recorder Http Trace exporter web
```javascript
import { BatchSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { SessionRecorderHttpTraceExporterBrowser } from '@multiplayer-app/session-recorder-common'
const collectorOptions = {
url: '<opentelemetry-collector-url>', // url is optional and can be omitted - default is https://api.multiplayer.app/v1/traces
apiKey: '<multiplayer-otlp-key>' // api key from multiplayer integration
}
const exporter = new SessionRecorderHttpTraceExporterBrowser(collectorOptions)
const provider = new WebTracerProvider({
spanProcessors: [
new BatchSpanProcessor(exporter, {
// The maximum queue size. After the size is reached spans are dropped.
maxQueueSize: 100,
// The maximum batch size of every export. It must be smaller or equal to maxQueueSize.
maxExportBatchSize: 10,
// The interval between two consecutive exports
scheduledDelayMillis: 500,
// How long the export can run before it is cancelled
exportTimeoutMillis: 30000
})
]
})
provider.register()
```
### Session Recorder id generator
```javascript
import { BatchSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { SessionRecorderIdGenerator, SessionRecorderHttpTraceExporterBrowser } from '@multiplayer-app/session-recorder-common'
const idGenerator = new SessionRecorderIdGenerator({ autoDocTracesRatio: 0.05 })
const collectorOptions = {
url: '<opentelemetry-collector-url>', // url is optional and can be omitted - default is https://api.multiplayer.app/v1/traces
apiKey: '<multiplayer-otlp-key>' // api key from multiplayer integration
}
const exporter = new SessionRecorderHttpTraceExporterBrowser(collectorOptions)
const provider = new WebTracerProvider({
spanProcessors: [
new BatchSpanProcessor(exporter, {
// The maximum queue size. After the size is reached spans are dropped.
maxQueueSize: 100,
// The maximum batch size of every export. It must be smaller or equal to maxQueueSize.
maxExportBatchSize: 10,
// The interval between two consecutive exports
scheduledDelayMillis: 500,
// How long the export can run before it is cancelled
exportTimeoutMillis: 30000
})
],
idGenerator
})
idGenerator.setSessionId('<multiplayer-debug-session-short-id>')
```
### Trace id ratio based sampler
Session Recorder sampler will always sample traces with appropriate prefixes, other traces will be sampled using ration provided to constructor.
```javascript
import { BatchSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { SessionRecorderTraceIdRatioBasedSampler, SessionRecorderHttpTraceExporterBrowser } from '@multiplayer-app/session-recorder-common'
const collectorOptions = {
url: '<opentelemetry-collector-url>', // url is optional and can be omitted - default is https://api.multiplayer.app/v1/traces
apiKey: '<multiplayer-otlp-key>' // api key from multiplayer integration
}
const exporter = new SessionRecorderHttpTraceExporterBrowser(collectorOptions)
const provider = new WebTracerProvider({
spanProcessors: [
new BatchSpanProcessor(exporter, {
// The maximum queue size. After the size is reached spans are dropped.
maxQueueSize: 100,
// The maximum batch size of every export. It must be smaller or equal to maxQueueSize.
maxExportBatchSize: 10,
// The interval between two consecutive exports
scheduledDelayMillis: 500,
// How long the export can run before it is cancelled
exportTimeoutMillis: 30000
})
],
sampler: new SessionRecorderTraceIdRatioBasedSampler(0.05)
})
```
### Helper for capturing exception in session recording
```javascript
import { SessionRecorderSdk } from '@multiplayer-app/session-recorder-common'
const error = new Error('Some text here')
SessionRecorderSdk.captureException(error)
```
### Helpers for adding content to session recording
```javascript
import { SessionRecorderSdk } from '@multiplayer-app/session-recorder-common'
SessionRecorderSdk.setAttribute('{{SOME_KEY}}', '{{SOME_VALUE}}')
// following helpers do masking of sensitive fields
SessionRecorderSdk.setHttpRequestBody('{{ANY_REQUEST_PAYLOAD_HERE}}')
SessionRecorderSdk.setHttpRequestHeaders({ Cookie: '...', Authorization: '...'})
SessionRecorderSdk.setHttpResponseBody({some_payload: '{{ANY_REQUEST_PAYLOAD_HERE}}'})
SessionRecorderSdk.setHttpResponseHeaders({ 'Set-Cookie': '...' })
SessionRecorderSdk.setMessageBody({some_payload: '{{ANY_REQUEST_PAYLOAD_HERE}}'})
SessionRecorderSdk.setRpcRequestMessage({some_payload: '{{ANY_REQUEST_PAYLOAD_HERE}}'})
SessionRecorderSdk.setRpcResponseMessage({some_payload: '{{ANY_REQUEST_PAYLOAD_HERE}}'})
SessionRecorderSdk.setGrpcRequestMessage({some_payload: '{{ANY_REQUEST_PAYLOAD_HERE}}'})
SessionRecorderSdk.setGrpcResponseMessage({some_payload: '{{ANY_REQUEST_PAYLOAD_HERE}}'})
```
## License
MIT - See [LICENSE](./LICENSE) for more information.