@multiplayer-app/session-recorder-common 0.0.1

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 (285) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +230 -0
  3. package/dist/esm/SessionRecorderHttpInstrumentationHooksNode.d.ts +35 -0
  4. package/dist/esm/SessionRecorderHttpInstrumentationHooksNode.d.ts.map +1 -0
  5. package/dist/esm/SessionRecorderHttpInstrumentationHooksNode.js +355 -0
  6. package/dist/esm/SessionRecorderHttpInstrumentationHooksNode.js.map +1 -0
  7. package/dist/esm/SessionRecorderHttpTraceExporterBrowser.d.ts +26 -0
  8. package/dist/esm/SessionRecorderHttpTraceExporterBrowser.d.ts.map +1 -0
  9. package/dist/esm/SessionRecorderHttpTraceExporterBrowser.js +116 -0
  10. package/dist/esm/SessionRecorderHttpTraceExporterBrowser.js.map +1 -0
  11. package/dist/esm/SessionRecorderIdGenerator.d.ts +15 -0
  12. package/dist/esm/SessionRecorderIdGenerator.d.ts.map +1 -0
  13. package/dist/esm/SessionRecorderIdGenerator.js +63 -0
  14. package/dist/esm/SessionRecorderIdGenerator.js.map +1 -0
  15. package/dist/esm/SessionRecorderJsonTraceSerializer.d.ts +4 -0
  16. package/dist/esm/SessionRecorderJsonTraceSerializer.d.ts.map +1 -0
  17. package/dist/esm/SessionRecorderJsonTraceSerializer.js +26 -0
  18. package/dist/esm/SessionRecorderJsonTraceSerializer.js.map +1 -0
  19. package/dist/esm/SessionRecorderTraceIdRatioBasedSampler.d.ts +11 -0
  20. package/dist/esm/SessionRecorderTraceIdRatioBasedSampler.d.ts.map +1 -0
  21. package/dist/esm/SessionRecorderTraceIdRatioBasedSampler.js +45 -0
  22. package/dist/esm/SessionRecorderTraceIdRatioBasedSampler.js.map +1 -0
  23. package/dist/esm/constants.base.d.ts +32 -0
  24. package/dist/esm/constants.base.d.ts.map +1 -0
  25. package/dist/esm/constants.base.js +32 -0
  26. package/dist/esm/constants.base.js.map +1 -0
  27. package/dist/esm/constants.browser.d.ts +2 -0
  28. package/dist/esm/constants.browser.d.ts.map +1 -0
  29. package/dist/esm/constants.browser.js +2 -0
  30. package/dist/esm/constants.browser.js.map +1 -0
  31. package/dist/esm/constants.node.d.ts +3 -0
  32. package/dist/esm/constants.node.d.ts.map +1 -0
  33. package/dist/esm/constants.node.js +5 -0
  34. package/dist/esm/constants.node.js.map +1 -0
  35. package/dist/esm/index-browser.d.ts +8 -0
  36. package/dist/esm/index-browser.d.ts.map +1 -0
  37. package/dist/esm/index-browser.js +9 -0
  38. package/dist/esm/index-browser.js.map +1 -0
  39. package/dist/esm/index-node.d.ts +8 -0
  40. package/dist/esm/index-node.d.ts.map +1 -0
  41. package/dist/esm/index-node.js +9 -0
  42. package/dist/esm/index-node.js.map +1 -0
  43. package/dist/esm/index.d.ts +9 -0
  44. package/dist/esm/index.d.ts.map +1 -0
  45. package/dist/esm/index.js +10 -0
  46. package/dist/esm/index.js.map +1 -0
  47. package/dist/esm/sdk/capture-exception.d.ts +7 -0
  48. package/dist/esm/sdk/capture-exception.d.ts.map +1 -0
  49. package/dist/esm/sdk/capture-exception.js +19 -0
  50. package/dist/esm/sdk/capture-exception.js.map +1 -0
  51. package/dist/esm/sdk/id-generator.d.ts +2 -0
  52. package/dist/esm/sdk/id-generator.d.ts.map +1 -0
  53. package/dist/esm/sdk/id-generator.js +14 -0
  54. package/dist/esm/sdk/id-generator.js.map +1 -0
  55. package/dist/esm/sdk/index.d.ts +8 -0
  56. package/dist/esm/sdk/index.d.ts.map +1 -0
  57. package/dist/esm/sdk/index.js +8 -0
  58. package/dist/esm/sdk/index.js.map +1 -0
  59. package/dist/esm/sdk/is-gzip.d.ts +2 -0
  60. package/dist/esm/sdk/is-gzip.d.ts.map +1 -0
  61. package/dist/esm/sdk/is-gzip.js +7 -0
  62. package/dist/esm/sdk/is-gzip.js.map +1 -0
  63. package/dist/esm/sdk/mask.d.ts +6 -0
  64. package/dist/esm/sdk/mask.d.ts.map +1 -0
  65. package/dist/esm/sdk/mask.js +148 -0
  66. package/dist/esm/sdk/mask.js.map +1 -0
  67. package/dist/esm/sdk/save-continuous-deb-session.d.ts +7 -0
  68. package/dist/esm/sdk/save-continuous-deb-session.d.ts.map +1 -0
  69. package/dist/esm/sdk/save-continuous-deb-session.js +21 -0
  70. package/dist/esm/sdk/save-continuous-deb-session.js.map +1 -0
  71. package/dist/esm/sdk/schemify.d.ts +4 -0
  72. package/dist/esm/sdk/schemify.d.ts.map +1 -0
  73. package/dist/esm/sdk/schemify.js +51 -0
  74. package/dist/esm/sdk/schemify.js.map +1 -0
  75. package/dist/esm/sdk/set-attribute.d.ts +90 -0
  76. package/dist/esm/sdk/set-attribute.d.ts.map +1 -0
  77. package/dist/esm/sdk/set-attribute.js +160 -0
  78. package/dist/esm/sdk/set-attribute.js.map +1 -0
  79. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
  80. package/dist/esm/type/index.d.ts +2 -0
  81. package/dist/esm/type/index.d.ts.map +1 -0
  82. package/dist/esm/type/index.js +2 -0
  83. package/dist/esm/type/index.js.map +1 -0
  84. package/dist/esm/type/session-type.enum.d.ts +5 -0
  85. package/dist/esm/type/session-type.enum.d.ts.map +1 -0
  86. package/dist/esm/type/session-type.enum.js +6 -0
  87. package/dist/esm/type/session-type.enum.js.map +1 -0
  88. package/dist/esnext/SessionRecorderHttpInstrumentationHooksNode.d.ts +35 -0
  89. package/dist/esnext/SessionRecorderHttpInstrumentationHooksNode.d.ts.map +1 -0
  90. package/dist/esnext/SessionRecorderHttpInstrumentationHooksNode.js +221 -0
  91. package/dist/esnext/SessionRecorderHttpInstrumentationHooksNode.js.map +1 -0
  92. package/dist/esnext/SessionRecorderHttpTraceExporterBrowser.d.ts +26 -0
  93. package/dist/esnext/SessionRecorderHttpTraceExporterBrowser.d.ts.map +1 -0
  94. package/dist/esnext/SessionRecorderHttpTraceExporterBrowser.js +82 -0
  95. package/dist/esnext/SessionRecorderHttpTraceExporterBrowser.js.map +1 -0
  96. package/dist/esnext/SessionRecorderIdGenerator.d.ts +15 -0
  97. package/dist/esnext/SessionRecorderIdGenerator.d.ts.map +1 -0
  98. package/dist/esnext/SessionRecorderIdGenerator.js +42 -0
  99. package/dist/esnext/SessionRecorderIdGenerator.js.map +1 -0
  100. package/dist/esnext/SessionRecorderJsonTraceSerializer.d.ts +4 -0
  101. package/dist/esnext/SessionRecorderJsonTraceSerializer.d.ts.map +1 -0
  102. package/dist/esnext/SessionRecorderJsonTraceSerializer.js +26 -0
  103. package/dist/esnext/SessionRecorderJsonTraceSerializer.js.map +1 -0
  104. package/dist/esnext/SessionRecorderTraceIdRatioBasedSampler.d.ts +11 -0
  105. package/dist/esnext/SessionRecorderTraceIdRatioBasedSampler.d.ts.map +1 -0
  106. package/dist/esnext/SessionRecorderTraceIdRatioBasedSampler.js +42 -0
  107. package/dist/esnext/SessionRecorderTraceIdRatioBasedSampler.js.map +1 -0
  108. package/dist/esnext/constants.base.d.ts +32 -0
  109. package/dist/esnext/constants.base.d.ts.map +1 -0
  110. package/dist/esnext/constants.base.js +32 -0
  111. package/dist/esnext/constants.base.js.map +1 -0
  112. package/dist/esnext/constants.browser.d.ts +2 -0
  113. package/dist/esnext/constants.browser.d.ts.map +1 -0
  114. package/dist/esnext/constants.browser.js +2 -0
  115. package/dist/esnext/constants.browser.js.map +1 -0
  116. package/dist/esnext/constants.node.d.ts +3 -0
  117. package/dist/esnext/constants.node.d.ts.map +1 -0
  118. package/dist/esnext/constants.node.js +5 -0
  119. package/dist/esnext/constants.node.js.map +1 -0
  120. package/dist/esnext/index-browser.d.ts +8 -0
  121. package/dist/esnext/index-browser.d.ts.map +1 -0
  122. package/dist/esnext/index-browser.js +8 -0
  123. package/dist/esnext/index-browser.js.map +1 -0
  124. package/dist/esnext/index-node.d.ts +8 -0
  125. package/dist/esnext/index-node.d.ts.map +1 -0
  126. package/dist/esnext/index-node.js +8 -0
  127. package/dist/esnext/index-node.js.map +1 -0
  128. package/dist/esnext/index.d.ts +9 -0
  129. package/dist/esnext/index.d.ts.map +1 -0
  130. package/dist/esnext/index.js +9 -0
  131. package/dist/esnext/index.js.map +1 -0
  132. package/dist/esnext/sdk/capture-exception.d.ts +7 -0
  133. package/dist/esnext/sdk/capture-exception.d.ts.map +1 -0
  134. package/dist/esnext/sdk/capture-exception.js +19 -0
  135. package/dist/esnext/sdk/capture-exception.js.map +1 -0
  136. package/dist/esnext/sdk/id-generator.d.ts +2 -0
  137. package/dist/esnext/sdk/id-generator.d.ts.map +1 -0
  138. package/dist/esnext/sdk/id-generator.js +14 -0
  139. package/dist/esnext/sdk/id-generator.js.map +1 -0
  140. package/dist/esnext/sdk/index.d.ts +8 -0
  141. package/dist/esnext/sdk/index.d.ts.map +1 -0
  142. package/dist/esnext/sdk/index.js +8 -0
  143. package/dist/esnext/sdk/index.js.map +1 -0
  144. package/dist/esnext/sdk/is-gzip.d.ts +2 -0
  145. package/dist/esnext/sdk/is-gzip.d.ts.map +1 -0
  146. package/dist/esnext/sdk/is-gzip.js +7 -0
  147. package/dist/esnext/sdk/is-gzip.js.map +1 -0
  148. package/dist/esnext/sdk/mask.d.ts +6 -0
  149. package/dist/esnext/sdk/mask.d.ts.map +1 -0
  150. package/dist/esnext/sdk/mask.js +144 -0
  151. package/dist/esnext/sdk/mask.js.map +1 -0
  152. package/dist/esnext/sdk/save-continuous-deb-session.d.ts +7 -0
  153. package/dist/esnext/sdk/save-continuous-deb-session.d.ts.map +1 -0
  154. package/dist/esnext/sdk/save-continuous-deb-session.js +21 -0
  155. package/dist/esnext/sdk/save-continuous-deb-session.js.map +1 -0
  156. package/dist/esnext/sdk/schemify.d.ts +4 -0
  157. package/dist/esnext/sdk/schemify.d.ts.map +1 -0
  158. package/dist/esnext/sdk/schemify.js +49 -0
  159. package/dist/esnext/sdk/schemify.js.map +1 -0
  160. package/dist/esnext/sdk/set-attribute.d.ts +90 -0
  161. package/dist/esnext/sdk/set-attribute.d.ts.map +1 -0
  162. package/dist/esnext/sdk/set-attribute.js +151 -0
  163. package/dist/esnext/sdk/set-attribute.js.map +1 -0
  164. package/dist/esnext/tsconfig.esnext.tsbuildinfo +1 -0
  165. package/dist/esnext/type/index.d.ts +2 -0
  166. package/dist/esnext/type/index.d.ts.map +1 -0
  167. package/dist/esnext/type/index.js +2 -0
  168. package/dist/esnext/type/index.js.map +1 -0
  169. package/dist/esnext/type/session-type.enum.d.ts +5 -0
  170. package/dist/esnext/type/session-type.enum.d.ts.map +1 -0
  171. package/dist/esnext/type/session-type.enum.js +6 -0
  172. package/dist/esnext/type/session-type.enum.js.map +1 -0
  173. package/dist/src/SessionRecorderHttpInstrumentationHooksNode.d.ts +35 -0
  174. package/dist/src/SessionRecorderHttpInstrumentationHooksNode.d.ts.map +1 -0
  175. package/dist/src/SessionRecorderHttpInstrumentationHooksNode.js +224 -0
  176. package/dist/src/SessionRecorderHttpInstrumentationHooksNode.js.map +1 -0
  177. package/dist/src/SessionRecorderHttpTraceExporterBrowser.d.ts +26 -0
  178. package/dist/src/SessionRecorderHttpTraceExporterBrowser.d.ts.map +1 -0
  179. package/dist/src/SessionRecorderHttpTraceExporterBrowser.js +86 -0
  180. package/dist/src/SessionRecorderHttpTraceExporterBrowser.js.map +1 -0
  181. package/dist/src/SessionRecorderIdGenerator.d.ts +15 -0
  182. package/dist/src/SessionRecorderIdGenerator.d.ts.map +1 -0
  183. package/dist/src/SessionRecorderIdGenerator.js +46 -0
  184. package/dist/src/SessionRecorderIdGenerator.js.map +1 -0
  185. package/dist/src/SessionRecorderJsonTraceSerializer.d.ts +4 -0
  186. package/dist/src/SessionRecorderJsonTraceSerializer.d.ts.map +1 -0
  187. package/dist/src/SessionRecorderJsonTraceSerializer.js +29 -0
  188. package/dist/src/SessionRecorderJsonTraceSerializer.js.map +1 -0
  189. package/dist/src/SessionRecorderTraceIdRatioBasedSampler.d.ts +11 -0
  190. package/dist/src/SessionRecorderTraceIdRatioBasedSampler.d.ts.map +1 -0
  191. package/dist/src/SessionRecorderTraceIdRatioBasedSampler.js +46 -0
  192. package/dist/src/SessionRecorderTraceIdRatioBasedSampler.js.map +1 -0
  193. package/dist/src/constants.base.d.ts +32 -0
  194. package/dist/src/constants.base.d.ts.map +1 -0
  195. package/dist/src/constants.base.js +35 -0
  196. package/dist/src/constants.base.js.map +1 -0
  197. package/dist/src/constants.browser.d.ts +2 -0
  198. package/dist/src/constants.browser.d.ts.map +1 -0
  199. package/dist/src/constants.browser.js +18 -0
  200. package/dist/src/constants.browser.js.map +1 -0
  201. package/dist/src/constants.node.d.ts +3 -0
  202. package/dist/src/constants.node.d.ts.map +1 -0
  203. package/dist/src/constants.node.js +22 -0
  204. package/dist/src/constants.node.js.map +1 -0
  205. package/dist/src/index-browser.d.ts +8 -0
  206. package/dist/src/index-browser.d.ts.map +1 -0
  207. package/dist/src/index-browser.js +29 -0
  208. package/dist/src/index-browser.js.map +1 -0
  209. package/dist/src/index-node.d.ts +8 -0
  210. package/dist/src/index-node.d.ts.map +1 -0
  211. package/dist/src/index-node.js +29 -0
  212. package/dist/src/index-node.js.map +1 -0
  213. package/dist/src/index.d.ts +9 -0
  214. package/dist/src/index.d.ts.map +1 -0
  215. package/dist/src/index.js +31 -0
  216. package/dist/src/index.js.map +1 -0
  217. package/dist/src/sdk/capture-exception.d.ts +7 -0
  218. package/dist/src/sdk/capture-exception.d.ts.map +1 -0
  219. package/dist/src/sdk/capture-exception.js +23 -0
  220. package/dist/src/sdk/capture-exception.js.map +1 -0
  221. package/dist/src/sdk/id-generator.d.ts +2 -0
  222. package/dist/src/sdk/id-generator.d.ts.map +1 -0
  223. package/dist/src/sdk/id-generator.js +18 -0
  224. package/dist/src/sdk/id-generator.js.map +1 -0
  225. package/dist/src/sdk/index.d.ts +8 -0
  226. package/dist/src/sdk/index.d.ts.map +1 -0
  227. package/dist/src/sdk/index.js +29 -0
  228. package/dist/src/sdk/index.js.map +1 -0
  229. package/dist/src/sdk/is-gzip.d.ts +2 -0
  230. package/dist/src/sdk/is-gzip.d.ts.map +1 -0
  231. package/dist/src/sdk/is-gzip.js +11 -0
  232. package/dist/src/sdk/is-gzip.js.map +1 -0
  233. package/dist/src/sdk/mask.d.ts +6 -0
  234. package/dist/src/sdk/mask.d.ts.map +1 -0
  235. package/dist/src/sdk/mask.js +147 -0
  236. package/dist/src/sdk/mask.js.map +1 -0
  237. package/dist/src/sdk/save-continuous-deb-session.d.ts +7 -0
  238. package/dist/src/sdk/save-continuous-deb-session.d.ts.map +1 -0
  239. package/dist/src/sdk/save-continuous-deb-session.js +25 -0
  240. package/dist/src/sdk/save-continuous-deb-session.js.map +1 -0
  241. package/dist/src/sdk/schemify.d.ts +4 -0
  242. package/dist/src/sdk/schemify.d.ts.map +1 -0
  243. package/dist/src/sdk/schemify.js +51 -0
  244. package/dist/src/sdk/schemify.js.map +1 -0
  245. package/dist/src/sdk/set-attribute.d.ts +90 -0
  246. package/dist/src/sdk/set-attribute.d.ts.map +1 -0
  247. package/dist/src/sdk/set-attribute.js +164 -0
  248. package/dist/src/sdk/set-attribute.js.map +1 -0
  249. package/dist/src/type/index.d.ts +2 -0
  250. package/dist/src/type/index.d.ts.map +1 -0
  251. package/dist/src/type/index.js +18 -0
  252. package/dist/src/type/index.js.map +1 -0
  253. package/dist/src/type/session-type.enum.d.ts +5 -0
  254. package/dist/src/type/session-type.enum.d.ts.map +1 -0
  255. package/dist/src/type/session-type.enum.js +9 -0
  256. package/dist/src/type/session-type.enum.js.map +1 -0
  257. package/package.json +50 -0
  258. package/src/SessionRecorderHttpInstrumentationHooksNode.ts +362 -0
  259. package/src/SessionRecorderHttpTraceExporterBrowser.ts +123 -0
  260. package/src/SessionRecorderIdGenerator.ts +72 -0
  261. package/src/SessionRecorderJsonTraceSerializer.ts +43 -0
  262. package/src/SessionRecorderTraceIdRatioBasedSampler.ts +57 -0
  263. package/src/constants.base.ts +61 -0
  264. package/src/constants.browser.ts +1 -0
  265. package/src/constants.node.ts +5 -0
  266. package/src/index-browser.ts +7 -0
  267. package/src/index-node.ts +7 -0
  268. package/src/index.ts +8 -0
  269. package/src/sdk/capture-exception.ts +19 -0
  270. package/src/sdk/id-generator.ts +17 -0
  271. package/src/sdk/index.ts +7 -0
  272. package/src/sdk/is-gzip.ts +7 -0
  273. package/src/sdk/mask.ts +161 -0
  274. package/src/sdk/save-continuous-deb-session.ts +28 -0
  275. package/src/sdk/schemify.ts +58 -0
  276. package/src/sdk/set-attribute.ts +210 -0
  277. package/src/type/index.ts +1 -0
  278. package/src/type/session-type.enum.ts +4 -0
  279. package/tsconfig.base.es5.json +8 -0
  280. package/tsconfig.base.esm.json +7 -0
  281. package/tsconfig.base.esnext.json +10 -0
  282. package/tsconfig.base.json +35 -0
  283. package/tsconfig.esm.json +12 -0
  284. package/tsconfig.esnext.json +12 -0
  285. package/tsconfig.json +25 -0
@@ -0,0 +1,362 @@
1
+ import type {
2
+ IncomingMessage,
3
+ ServerResponse,
4
+ ClientRequest,
5
+ } from 'http'
6
+ import * as zlib from 'zlib'
7
+ import type { Span } from '@opentelemetry/api'
8
+ import {
9
+ ATTR_MULTIPLAYER_HTTP_REQUEST_BODY,
10
+ ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS,
11
+ ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY,
12
+ ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS,
13
+ MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE,
14
+ ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY_ENCODING,
15
+ MULTIPLAYER_TRACE_DEBUG_PREFIX,
16
+ } from './constants.node'
17
+ import {
18
+ mask,
19
+ schemify,
20
+ isGzip,
21
+ } from './sdk'
22
+ import {
23
+ sensitiveFields,
24
+ sensitiveHeaders
25
+ } from './sdk/mask'
26
+
27
+ interface HttpResponseHookOptions {
28
+ maxPayloadSizeBytes?: number
29
+ schemifyDocSpanPayload?: boolean
30
+ uncompressPayload?: boolean
31
+
32
+ captureHeaders?: boolean
33
+ captureBody?: boolean
34
+
35
+ isMaskingEnabled?: boolean
36
+
37
+ maskBody?: (arg: any, span: Span) => any
38
+ maskHeaders?: (arg: any, span: Span) => any
39
+
40
+ maskBodyFieldsList?: string[]
41
+ maskHeadersList?: string[]
42
+
43
+ headersToInclude?: string[]
44
+ headersToExclude?: string[]
45
+ }
46
+
47
+ interface HttpRequestHookOptions {
48
+ maxPayloadSizeBytes?: number
49
+ schemifyDocSpanPayload?: boolean
50
+
51
+ captureHeaders?: boolean
52
+ captureBody?: boolean
53
+
54
+ isMaskingEnabled?: boolean
55
+
56
+ maskBody?: (arg: any, span: Span) => any
57
+ maskHeaders?: (arg: any, span: Span) => any
58
+
59
+ maskBodyFieldsList?: string[]
60
+ maskHeadersList?: string[]
61
+
62
+ headersToInclude?: string[]
63
+ headersToExclude?: string[]
64
+ }
65
+
66
+ const setDefaultOptions = (
67
+ options: HttpResponseHookOptions | HttpResponseHookOptions
68
+ ): Omit<HttpResponseHookOptions & HttpResponseHookOptions, 'maskBody' | 'maskHeaders'>
69
+ & {
70
+ maskBody: (arg: any, span: Span) => any
71
+ maskHeaders: (arg: any, span: Span) => any
72
+ captureHeaders: boolean,
73
+ captureBody: boolean,
74
+ isMaskingEnabled: boolean,
75
+ schemifyDocSpanPayload: boolean,
76
+ uncompressPayload: boolean,
77
+ maxPayloadSizeBytes: number
78
+ } => {
79
+ options.captureHeaders = 'captureHeaders' in options
80
+ ? options.captureHeaders
81
+ : true
82
+ options.captureBody = 'captureBody' in options
83
+ ? options.captureBody
84
+ : true
85
+ options.isMaskingEnabled = 'isMaskingEnabled' in options
86
+ ? options.isMaskingEnabled
87
+ : true
88
+ options.schemifyDocSpanPayload = 'schemifyDocSpanPayload' in options
89
+ ? options.schemifyDocSpanPayload
90
+ : false
91
+ options.uncompressPayload = 'uncompressPayload' in options
92
+ ? options.uncompressPayload
93
+ : true
94
+ options.maskBody = options.maskBody || mask([
95
+ ...(
96
+ Array.isArray(options.maskBodyFieldsList)
97
+ ? options.maskBodyFieldsList
98
+ : sensitiveFields
99
+ ),
100
+ ...(
101
+ Array.isArray(options.maskHeadersList)
102
+ ? options.maskHeadersList
103
+ : sensitiveHeaders
104
+ ),
105
+ ])
106
+ options.maskHeaders = options.maskHeaders || mask([
107
+ ...(
108
+ Array.isArray(options.maskBodyFieldsList)
109
+ ? options.maskBodyFieldsList
110
+ : sensitiveFields
111
+ ),
112
+ ...(
113
+ Array.isArray(options.maskHeadersList)
114
+ ? options.maskHeadersList
115
+ : sensitiveHeaders
116
+ ),
117
+ ])
118
+ options.maxPayloadSizeBytes = options.maxPayloadSizeBytes || MULTIPLAYER_MAX_HTTP_REQUEST_RESPONSE_SIZE
119
+
120
+ return options as Omit<HttpResponseHookOptions & HttpResponseHookOptions, 'maskBody' | 'maskHeaders'>
121
+ & {
122
+ maskBody: (arg: any, span: Span) => any
123
+ maskHeaders: (arg: any, span: Span) => any
124
+ captureHeaders: boolean,
125
+ captureBody: boolean,
126
+ isMaskingEnabled: boolean,
127
+ schemifyDocSpanPayload: boolean,
128
+ uncompressPayload: boolean,
129
+ maxPayloadSizeBytes: number
130
+ }
131
+ }
132
+
133
+ export const SessionRecorderHttpInstrumentationHooksNode = {
134
+ responseHook: (options: HttpResponseHookOptions = {}) =>
135
+ (span: Span, response: IncomingMessage | ServerResponse) => {
136
+ try {
137
+ const _options = setDefaultOptions(options)
138
+
139
+ if (!_options.captureBody && !_options.captureHeaders) {
140
+ return
141
+ }
142
+
143
+ const _response = response as ServerResponse
144
+ const traceId = span.spanContext().traceId
145
+
146
+ if (_response.setHeader) {
147
+ _response.setHeader('X-Trace-Id', traceId)
148
+ }
149
+
150
+ const [oldWrite, oldEnd] = [_response.write, _response.end]
151
+
152
+ const chunks: Buffer[] = [];
153
+
154
+ if (_options.captureBody) {
155
+ (_response.write as unknown) = function (...restArgs: any[]) {
156
+ chunks.push(Buffer.from(restArgs[0]))
157
+ // eslint-disable-next-line
158
+ // @ts-ignore
159
+ oldWrite.apply(_response, restArgs)
160
+ }
161
+ }
162
+
163
+ // eslint-disable-next-line
164
+ // @ts-ignore
165
+ _response.end = async function (...restArgs) {
166
+ if (_options.captureBody && restArgs[0]) {
167
+ chunks.push(Buffer.from(restArgs[0]))
168
+ }
169
+
170
+ const responseBuffer = Buffer.concat(chunks)
171
+
172
+ if (
173
+ _options.captureBody
174
+ && responseBuffer.byteLength > 0
175
+ && responseBuffer.byteLength < _options.maxPayloadSizeBytes
176
+ ) {
177
+ let responseBody: string
178
+ let skipResponseBodyModification = false
179
+
180
+ if (isGzip(responseBuffer)) {
181
+ if (_options.uncompressPayload) {
182
+ const dezippedBuffer = await new Promise((resolve) => zlib
183
+ .gunzip(responseBuffer, function (err, dezipped) {
184
+ if (err) {
185
+ return resolve(Buffer.from(''))
186
+ } else {
187
+ return resolve(dezipped)
188
+ }
189
+ })) as Buffer
190
+ responseBody = dezippedBuffer.toString('utf-8')
191
+ } else {
192
+ span.setAttribute(
193
+ ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY_ENCODING,
194
+ 'gzip',
195
+ )
196
+
197
+ skipResponseBodyModification = true
198
+ responseBody = responseBuffer.toString('hex')
199
+ }
200
+ } else {
201
+ responseBody = responseBuffer.toString('utf-8')
202
+ }
203
+
204
+ if (!skipResponseBodyModification) {
205
+ if (
206
+ traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX)
207
+ && _options.isMaskingEnabled
208
+ ) {
209
+ responseBody = _options.maskBody(responseBody, span)
210
+ } else if (_options.schemifyDocSpanPayload) {
211
+ responseBody = schemify(responseBody)
212
+ } else if (typeof responseBody !== 'string') {
213
+ responseBody = JSON.stringify(responseBody)
214
+ }
215
+ }
216
+
217
+ if (responseBody.length) {
218
+ span.setAttribute(
219
+ ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY,
220
+ responseBody,
221
+ )
222
+ }
223
+ }
224
+
225
+ if (_options.captureHeaders) {
226
+ const headers = _options.maskHeaders(_response.getHeaders(), span)
227
+
228
+ let _headers: any = {}
229
+
230
+ if (
231
+ !_options.headersToInclude?.length
232
+ && !_options.headersToExclude?.length
233
+ ) {
234
+ _headers = JSON.parse(JSON.stringify(headers))
235
+ } else {
236
+ if (_options.headersToInclude) {
237
+ for (const headerName of _options.headersToInclude) {
238
+ _headers[headerName] = headers[headerName]
239
+ }
240
+ }
241
+
242
+ if (_options.headersToExclude?.length) {
243
+ for (const headerName of _options.headersToExclude) {
244
+ delete _headers[headerName]
245
+ }
246
+ }
247
+ }
248
+
249
+ const stringifiedHeaders = JSON.stringify(_headers)
250
+
251
+ if (stringifiedHeaders?.length) {
252
+ span.setAttribute(
253
+ ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS,
254
+ stringifiedHeaders,
255
+ )
256
+ }
257
+ }
258
+
259
+ // eslint-disable-next-line
260
+ // @ts-ignore
261
+ return oldEnd.apply(_response, restArgs)
262
+ }
263
+ } catch (error) {
264
+ // eslint-disable-next-line
265
+ console.error('An error occured in multiplayer otlp http responseHook', error)
266
+ }
267
+ },
268
+ requestHook: (options: HttpRequestHookOptions = {}) =>
269
+ (span: Span, request: ClientRequest | IncomingMessage) => {
270
+ try {
271
+ const _options = setDefaultOptions(options)
272
+
273
+ if (!_options.captureBody && !_options.captureHeaders) {
274
+ return
275
+ }
276
+
277
+ const traceId = span.spanContext().traceId
278
+ const _request = request as IncomingMessage
279
+
280
+ if (_options.captureHeaders) {
281
+ let _headers: any = {}
282
+
283
+ if (
284
+ !_options.headersToInclude?.length
285
+ && !_options.headersToExclude?.length
286
+ ) {
287
+ _headers = JSON.parse(JSON.stringify(_request.headers))
288
+ } else {
289
+ if (_options.headersToInclude) {
290
+ for (const headerName of _options.headersToInclude) {
291
+ _headers[headerName] = _request.headers
292
+ }
293
+ }
294
+
295
+ if (_options.headersToExclude?.length) {
296
+ for (const headerName of _options.headersToExclude) {
297
+ delete _headers[headerName]
298
+ }
299
+ }
300
+ }
301
+
302
+ const headers = _options.maskHeaders(_headers, span)
303
+
304
+ span.setAttribute(
305
+ ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS,
306
+ JSON.stringify(headers),
307
+ )
308
+ }
309
+
310
+ const contentType = _request?.headers?.['content-type']
311
+ if (
312
+ _options.captureBody
313
+ && contentType?.includes('application/json')
314
+ ) {
315
+ let body = ''
316
+ _request.on('data', (chunk) => {
317
+ body += chunk
318
+ })
319
+ _request.on('end', () => {
320
+ try {
321
+ const requestBodySizeBytes = Buffer.byteLength(body, 'utf8')
322
+
323
+ if (
324
+ requestBodySizeBytes === 0
325
+ || requestBodySizeBytes > _options.maxPayloadSizeBytes
326
+ ) {
327
+ return
328
+ }
329
+
330
+ let requestBody = body
331
+ if (!requestBody) return
332
+
333
+ if (
334
+ traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX)
335
+ && _options.isMaskingEnabled
336
+ ) {
337
+ requestBody = _options.maskBody(requestBody, span)
338
+ } else if (_options.schemifyDocSpanPayload) {
339
+ requestBody = schemify(requestBody)
340
+ } else if (typeof requestBody !== 'string') {
341
+ requestBody = JSON.stringify(requestBody)
342
+ }
343
+
344
+ if (requestBody?.length) {
345
+ span.setAttribute(
346
+ ATTR_MULTIPLAYER_HTTP_REQUEST_BODY,
347
+ requestBody,
348
+ )
349
+ }
350
+ } catch (err) {
351
+ // eslint-disable-next-line
352
+ console.error('[MULTIPLAYER-HTTP-REQ-HOOK] An error occured in multiplayer otlp http requestHook', err)
353
+ }
354
+ })
355
+ }
356
+
357
+ } catch (error) {
358
+ // eslint-disable-next-line
359
+ console.error('An error occured in multiplayer otlp http requestHook', error)
360
+ }
361
+ },
362
+ }
@@ -0,0 +1,123 @@
1
+ import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'
2
+ import {
3
+ OTLPExporterConfigBase,
4
+ OTLPExporterBase,
5
+ } from '@opentelemetry/otlp-exporter-base'
6
+ import { createLegacyOtlpBrowserExportDelegate } from '@opentelemetry/otlp-exporter-base/browser-http'
7
+ import { SessionRecorderJsonTraceSerializer } from './SessionRecorderJsonTraceSerializer'
8
+ import { MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_URL } from './constants.base'
9
+
10
+ interface SessionRecorderExporterBrowserConfig
11
+ extends OTLPExporterConfigBase {
12
+ apiKey?: string
13
+ usePostMessageFallback?: boolean
14
+ postMessageType?: string
15
+ postMessageTargetOrigin?: string
16
+ }
17
+
18
+ /**
19
+ * Trace Exporters for Web with postMessage fallback
20
+ */
21
+ export class SessionRecorderHttpTraceExporterBrowser
22
+ extends OTLPExporterBase<ReadableSpan[]>
23
+ implements SpanExporter {
24
+
25
+ private usePostMessage: boolean = false
26
+ private readonly postMessageType: string
27
+ private readonly postMessageTargetOrigin: string
28
+ private readonly config: SessionRecorderExporterBrowserConfig
29
+
30
+ constructor(config: SessionRecorderExporterBrowserConfig = {}) {
31
+ const _config = {
32
+ ...config,
33
+ url: config.url || MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_URL,
34
+ headers: {
35
+ ...(config.headers || {}),
36
+ ...config.apiKey
37
+ ? { Authorization: config.apiKey }
38
+ : {},
39
+ },
40
+ }
41
+
42
+ super(
43
+ createLegacyOtlpBrowserExportDelegate(
44
+ _config,
45
+ SessionRecorderJsonTraceSerializer,
46
+ 'v1/traces',
47
+ { 'Content-Type': 'application/json' },
48
+ ),
49
+ )
50
+
51
+ this.config = config
52
+ this.postMessageType = config.postMessageType || 'MULTIPLAYER_SESSION_DEBUGGER_LIB'
53
+ this.postMessageTargetOrigin = config.postMessageTargetOrigin || '*'
54
+ }
55
+
56
+ override export(spans: ReadableSpan[], resultCallback: (result: { code: number }) => void): void {
57
+ if (this.usePostMessage) {
58
+ this.exportViaPostMessage(spans, resultCallback)
59
+ return
60
+ }
61
+
62
+ super.export(spans, (result) => {
63
+ if (result.code === 0) {
64
+ resultCallback(result)
65
+ } else if (this.config.usePostMessageFallback) {
66
+ this.usePostMessage = true
67
+ this.exportViaPostMessage(spans, resultCallback)
68
+ } else {
69
+ resultCallback(result)
70
+ }
71
+ })
72
+ }
73
+
74
+ private exportViaPostMessage(spans: ReadableSpan[], resultCallback: (result: { code: number }) => void): void {
75
+ if (typeof window === 'undefined') {
76
+ resultCallback({ code: 1 })
77
+ return
78
+ }
79
+
80
+ try {
81
+ window.postMessage(
82
+ {
83
+ action: 'traces',
84
+ type: this.postMessageType,
85
+ payload: spans.map(span => this._serializeSpan(span)),
86
+ },
87
+ this.postMessageTargetOrigin,
88
+ )
89
+ resultCallback({ code: 0 })
90
+ } catch (e) {
91
+ resultCallback({ code: 1 })
92
+ }
93
+ }
94
+
95
+ private _serializeSpan(span: ReadableSpan): any {
96
+ return {
97
+ _spanContext: span.spanContext(),
98
+ name: span.name,
99
+ kind: span.kind,
100
+ links: span.links,
101
+ ended: span.ended,
102
+ events: span.events,
103
+ status: span.status,
104
+ endTime: span.endTime,
105
+ startTime: span.startTime,
106
+ duration: span.duration,
107
+ attributes: span.attributes,
108
+ parentSpanId: span.parentSpanId,
109
+ instrumentationLibrary: span.instrumentationLibrary,
110
+ droppedAttributesCount: span.droppedAttributesCount,
111
+ droppedEventsCount: span.droppedEventsCount,
112
+ droppedLinksCount: span.droppedLinksCount,
113
+ resource: {
114
+ attributes: span.resource.attributes,
115
+ asyncAttributesPending: span.resource.asyncAttributesPending,
116
+ },
117
+ }
118
+ }
119
+
120
+ getDefaultUrl(config: OTLPExporterConfigBase): string {
121
+ return config.url || MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_URL
122
+ }
123
+ }
@@ -0,0 +1,72 @@
1
+ import {
2
+ RandomIdGenerator,
3
+ SamplingDecision,
4
+ } from '@opentelemetry/sdk-trace-base'
5
+ import { SessionType } from './type'
6
+ import {
7
+ SessionRecorderTraceIdRatioBasedSampler
8
+ } from './SessionRecorderTraceIdRatioBasedSampler'
9
+ import {
10
+ MULTIPLAYER_TRACE_DEBUG_PREFIX,
11
+ MULTIPLAYER_TRACE_DOC_PREFIX,
12
+ MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
13
+ } from './constants.base'
14
+ import { getIdGenerator } from './sdk'
15
+
16
+ export class SessionRecorderIdGenerator extends RandomIdGenerator {
17
+ sessionShortId: string
18
+ sessionType: SessionType
19
+ docSpanSampler: SessionRecorderTraceIdRatioBasedSampler
20
+
21
+ generateLongId: () => string
22
+
23
+ constructor({ autoDocTracesRatio = 0 } = {}) {
24
+ super()
25
+
26
+ this.docSpanSampler = new SessionRecorderTraceIdRatioBasedSampler(autoDocTracesRatio)
27
+
28
+ this.generateLongId = getIdGenerator(16)
29
+ this.sessionShortId = ''
30
+ this.sessionType = SessionType.PLAIN
31
+
32
+ this.generateTraceId = () => {
33
+ const traceId = this.generateLongId()
34
+
35
+ if (this.sessionShortId) {
36
+ let sessionTypePrefix: string = ''
37
+ switch (this.sessionType) {
38
+ case SessionType.CONTINUOUS:
39
+ sessionTypePrefix = MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX
40
+ break
41
+ default:
42
+ sessionTypePrefix = MULTIPLAYER_TRACE_DEBUG_PREFIX
43
+ }
44
+
45
+ const prefix = `${sessionTypePrefix}${this.sessionShortId}`
46
+
47
+ const sessionTraceId = `${prefix}${traceId.substring(prefix.length, traceId.length)}`
48
+
49
+ return sessionTraceId
50
+ } else if (this._isDocTrace(traceId)) {
51
+ return `${MULTIPLAYER_TRACE_DOC_PREFIX}${traceId.slice(MULTIPLAYER_TRACE_DOC_PREFIX.length, traceId.length)}`
52
+ }
53
+
54
+ return traceId
55
+ }
56
+ }
57
+
58
+ setSessionId(
59
+ sessionShortId: string,
60
+ sessionType: SessionType = SessionType.PLAIN,
61
+ ) {
62
+ this.sessionShortId = sessionShortId
63
+ this.sessionType = sessionType
64
+ }
65
+
66
+ _isDocTrace(traceId: string) {
67
+ return this.docSpanSampler.shouldSample(
68
+ undefined,
69
+ traceId,
70
+ ).decision === SamplingDecision.RECORD_AND_SAMPLED
71
+ }
72
+ }
@@ -0,0 +1,43 @@
1
+ import { ReadableSpan } from '@opentelemetry/sdk-trace-base'
2
+ import {
3
+ IExportTraceServiceResponse,
4
+ createExportTraceServiceRequest,
5
+ ISerializer,
6
+ } from '@opentelemetry/otlp-transformer'
7
+ import {
8
+ MULTIPLAYER_TRACE_DEBUG_PREFIX,
9
+ MULTIPLAYER_TRACE_DOC_PREFIX,
10
+ MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
11
+ } from './constants.base'
12
+
13
+ export const SessionRecorderJsonTraceSerializer: ISerializer<
14
+ ReadableSpan[],
15
+ IExportTraceServiceResponse
16
+ > = {
17
+ serializeRequest: (arg: ReadableSpan[]) => {
18
+ const filteredArg = arg.filter(span => {
19
+ const traceId = span.spanContext().traceId
20
+
21
+ if (
22
+ traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX)
23
+ || traceId.startsWith(MULTIPLAYER_TRACE_DOC_PREFIX)
24
+ || traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
25
+ ) {
26
+ return true
27
+ }
28
+
29
+ return false
30
+ })
31
+
32
+ const request = createExportTraceServiceRequest(filteredArg, {
33
+ useHex: true,
34
+ useLongBits: false,
35
+ })
36
+ const encoder = new TextEncoder()
37
+ return encoder.encode(JSON.stringify(request))
38
+ },
39
+ deserializeResponse: (arg: Uint8Array) => {
40
+ const decoder = new TextDecoder()
41
+ return JSON.parse(decoder.decode(arg)) as IExportTraceServiceResponse
42
+ },
43
+ }
@@ -0,0 +1,57 @@
1
+ import { isValidTraceId } from '@opentelemetry/api'
2
+ import {
3
+ Sampler,
4
+ SamplingDecision,
5
+ SamplingResult,
6
+ } from '@opentelemetry/sdk-trace-base'
7
+ import { MULTIPLAYER_TRACE_DEBUG_PREFIX } from './constants.base'
8
+
9
+ export class SessionRecorderTraceIdRatioBasedSampler implements Sampler {
10
+ private _upperBound: number
11
+
12
+ constructor(private readonly _ratio: number = 0) {
13
+ this._ratio = this._normalize(_ratio)
14
+ this._upperBound = Math.floor(this._ratio * 0xffffffff)
15
+ }
16
+
17
+ shouldSample(context: unknown, traceId: string): SamplingResult {
18
+ if (
19
+ this._ratio > 0
20
+ && traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX)
21
+ ) {
22
+ return {
23
+ decision: SamplingDecision.RECORD_AND_SAMPLED,
24
+ }
25
+ }
26
+
27
+ let decision: SamplingDecision = SamplingDecision.NOT_RECORD
28
+
29
+ if (
30
+ isValidTraceId(traceId)
31
+ && this._accumulate(traceId) < this._upperBound
32
+ ) {
33
+ decision = SamplingDecision.RECORD_AND_SAMPLED
34
+ }
35
+
36
+ return { decision }
37
+ }
38
+
39
+ toString(): string {
40
+ return `MultiplayerTraceIdRatioBasedSampler{${this._ratio}}`
41
+ }
42
+
43
+ private _normalize(ratio: number): number {
44
+ if (typeof ratio !== 'number' || isNaN(ratio)) return 0
45
+ return ratio >= 1 ? 1 : ratio <= 0 ? 0 : ratio
46
+ }
47
+
48
+ private _accumulate(traceId: string): number {
49
+ let accumulation = 0
50
+ for (let i = 0; i < traceId.length / 8; i++) {
51
+ const pos = i * 8
52
+ const part = parseInt(traceId.slice(pos, pos + 8), 16)
53
+ accumulation = (accumulation ^ part) >>> 0
54
+ }
55
+ return accumulation
56
+ }
57
+ }