@dxos/observability 0.3.11-main.fc97a54 → 0.3.11-next.e28df4f

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 (82) hide show
  1. package/README.md +4 -9
  2. package/dist/lib/browser/{chunk-6ZTMPKEG.mjs → chunk-2J5YS65Q.mjs} +3 -3
  3. package/dist/lib/browser/{chunk-6ZTMPKEG.mjs.map → chunk-2J5YS65Q.mjs.map} +3 -3
  4. package/dist/lib/browser/{chunk-HPGC4HC7.mjs → chunk-ROSK6U3K.mjs} +3 -3
  5. package/dist/lib/browser/chunk-ROSK6U3K.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-JVT4FOCC.mjs → chunk-STWCJK52.mjs} +130 -238
  7. package/dist/lib/browser/chunk-STWCJK52.mjs.map +7 -0
  8. package/dist/lib/browser/datadog/index.mjs +1 -1
  9. package/dist/lib/browser/index.mjs +5 -9
  10. package/dist/lib/browser/meta.json +1 -1
  11. package/dist/lib/browser/observability-XIDFB6PJ.mjs +10 -0
  12. package/dist/lib/browser/segment/index.mjs +1 -1
  13. package/dist/lib/node/{chunk-BHF4PKAP.cjs → chunk-ARUBPK2W.cjs} +6 -6
  14. package/dist/lib/node/chunk-ARUBPK2W.cjs.map +7 -0
  15. package/dist/lib/node/{chunk-ED364ZBZ.cjs → chunk-DE7OVD7T.cjs} +120 -226
  16. package/dist/lib/node/chunk-DE7OVD7T.cjs.map +7 -0
  17. package/dist/lib/node/{chunk-ZJRKFREX.cjs → chunk-VDBBIYH6.cjs} +6 -6
  18. package/dist/lib/node/{chunk-ZJRKFREX.cjs.map → chunk-VDBBIYH6.cjs.map} +3 -3
  19. package/dist/lib/node/datadog/index.cjs +3 -3
  20. package/dist/lib/node/datadog/index.cjs.map +1 -1
  21. package/dist/lib/node/index.cjs +16 -20
  22. package/dist/lib/node/index.cjs.map +2 -2
  23. package/dist/lib/node/meta.json +1 -1
  24. package/dist/lib/node/{observability-MN7SJ7NA.cjs → observability-YMIQHLME.cjs} +8 -8
  25. package/dist/lib/node/observability-YMIQHLME.cjs.map +7 -0
  26. package/dist/lib/node/segment/index.cjs +2 -2
  27. package/dist/lib/node/segment/index.cjs.map +1 -1
  28. package/dist/types/src/datadog/metrics.d.ts +1 -3
  29. package/dist/types/src/datadog/metrics.d.ts.map +1 -1
  30. package/dist/types/src/datadog/metrics.js +1 -1
  31. package/dist/types/src/datadog/metrics.js.map +1 -1
  32. package/dist/types/src/helpers/{browser-observability.d.ts → app-observability.d.ts} +6 -4
  33. package/dist/types/src/helpers/app-observability.d.ts.map +1 -0
  34. package/dist/types/src/helpers/{browser-observability.js → app-observability.js} +51 -22
  35. package/dist/types/src/helpers/app-observability.js.map +1 -0
  36. package/dist/types/src/helpers/index.d.ts +1 -3
  37. package/dist/types/src/helpers/index.d.ts.map +1 -1
  38. package/dist/types/src/helpers/index.js +1 -3
  39. package/dist/types/src/helpers/index.js.map +1 -1
  40. package/dist/types/src/helpers/setup-telemetry-listeners.d.ts.map +1 -1
  41. package/dist/types/src/helpers/setup-telemetry-listeners.js +12 -7
  42. package/dist/types/src/helpers/setup-telemetry-listeners.js.map +1 -1
  43. package/dist/types/src/observability.d.ts +4 -9
  44. package/dist/types/src/observability.d.ts.map +1 -1
  45. package/dist/types/src/observability.js +17 -44
  46. package/dist/types/src/observability.js.map +1 -1
  47. package/dist/types/src/segment/browser.d.ts.map +1 -1
  48. package/dist/types/src/segment/browser.js +2 -2
  49. package/dist/types/src/segment/browser.js.map +1 -1
  50. package/dist/types/src/segment/node.d.ts.map +1 -1
  51. package/dist/types/src/segment/node.js +2 -2
  52. package/dist/types/src/segment/node.js.map +1 -1
  53. package/dist/types/src/segment/types.d.ts +1 -3
  54. package/dist/types/src/segment/types.d.ts.map +1 -1
  55. package/package.json +14 -17
  56. package/src/datadog/metrics.ts +5 -3
  57. package/src/helpers/{browser-observability.ts → app-observability.ts} +54 -26
  58. package/src/helpers/index.ts +1 -3
  59. package/src/helpers/setup-telemetry-listeners.ts +7 -2
  60. package/src/observability.ts +20 -57
  61. package/src/segment/browser.ts +3 -3
  62. package/src/segment/node.ts +3 -3
  63. package/src/segment/types.ts +1 -1
  64. package/dist/lib/browser/chunk-HPGC4HC7.mjs.map +0 -7
  65. package/dist/lib/browser/chunk-JVT4FOCC.mjs.map +0 -7
  66. package/dist/lib/browser/observability-3UVQW6ZL.mjs +0 -10
  67. package/dist/lib/node/chunk-BHF4PKAP.cjs.map +0 -7
  68. package/dist/lib/node/chunk-ED364ZBZ.cjs.map +0 -7
  69. package/dist/lib/node/observability-MN7SJ7NA.cjs.map +0 -7
  70. package/dist/types/src/helpers/browser-observability.d.ts.map +0 -1
  71. package/dist/types/src/helpers/browser-observability.js.map +0 -1
  72. package/dist/types/src/helpers/common.d.ts +0 -10
  73. package/dist/types/src/helpers/common.d.ts.map +0 -1
  74. package/dist/types/src/helpers/common.js +0 -23
  75. package/dist/types/src/helpers/common.js.map +0 -1
  76. package/dist/types/src/helpers/node-observability.d.ts +0 -34
  77. package/dist/types/src/helpers/node-observability.d.ts.map +0 -1
  78. package/dist/types/src/helpers/node-observability.js +0 -106
  79. package/dist/types/src/helpers/node-observability.js.map +0 -1
  80. package/src/helpers/common.ts +0 -25
  81. package/src/helpers/node-observability.ts +0 -151
  82. /package/dist/lib/browser/{observability-3UVQW6ZL.mjs.map → observability-XIDFB6PJ.mjs.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/observability",
3
- "version": "0.3.11-main.fc97a54",
3
+ "version": "0.3.11-next.e28df4f",
4
4
  "description": "Provides a common interface for app and platform observability",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -65,28 +65,25 @@
65
65
  "analytics-node": "^6.2.0",
66
66
  "datadog-metrics": "^0.11.1",
67
67
  "debug": "^4.3.4",
68
- "js-yaml": "^4.1.0",
69
68
  "localforage": "^1.10.0",
70
- "uuid": "^8.3.2",
71
- "@dxos/async": "0.3.11-main.fc97a54",
72
- "@dxos/client-services": "0.3.11-main.fc97a54",
73
- "@dxos/config": "0.3.11-main.fc97a54",
74
- "@dxos/context": "0.3.11-main.fc97a54",
75
- "@dxos/invariant": "0.3.11-main.fc97a54",
76
- "@dxos/client-protocol": "0.3.11-main.fc97a54",
77
- "@dxos/debug": "0.3.11-main.fc97a54",
78
- "@dxos/node-std": "0.3.11-main.fc97a54",
79
- "@dxos/log": "0.3.11-main.fc97a54",
80
- "@dxos/network-manager": "0.3.11-main.fc97a54",
81
- "@dxos/protocols": "0.3.11-main.fc97a54",
82
- "@dxos/react-client": "0.3.11-main.fc97a54",
83
- "@dxos/util": "0.3.11-main.fc97a54"
69
+ "@dxos/async": "0.3.11-next.e28df4f",
70
+ "@dxos/client-protocol": "0.3.11-next.e28df4f",
71
+ "@dxos/client-services": "0.3.11-next.e28df4f",
72
+ "@dxos/context": "0.3.11-next.e28df4f",
73
+ "@dxos/debug": "0.3.11-next.e28df4f",
74
+ "@dxos/invariant": "0.3.11-next.e28df4f",
75
+ "@dxos/config": "0.3.11-next.e28df4f",
76
+ "@dxos/log": "0.3.11-next.e28df4f",
77
+ "@dxos/node-std": "0.3.11-next.e28df4f",
78
+ "@dxos/network-manager": "0.3.11-next.e28df4f",
79
+ "@dxos/protocols": "0.3.11-next.e28df4f",
80
+ "@dxos/react-client": "0.3.11-next.e28df4f",
81
+ "@dxos/util": "0.3.11-next.e28df4f"
84
82
  },
85
83
  "devDependencies": {
86
84
  "@sentry/types": "^7.98.0",
87
85
  "@types/analytics-node": "^3.1.9",
88
86
  "@types/debug": "^4.1.10",
89
- "@types/js-yaml": "^4.0.5",
90
87
  "sentry-testkit": "^5.0.5"
91
88
  },
92
89
  "publishConfig": {
@@ -16,7 +16,7 @@ export type DatadogOptions = {
16
16
  apiKey: string;
17
17
  host?: string;
18
18
  site?: String;
19
- getTags: () => { [key: string]: string };
19
+ getTags: () => Map<string, string>;
20
20
  // needed to read CORS proxy
21
21
  config: Config;
22
22
  };
@@ -25,7 +25,7 @@ debug.enable('metrics');
25
25
 
26
26
  export class DatadogMetrics {
27
27
  private _datadogmetrics?: any;
28
- private _getTags: () => { [key: string]: string };
28
+ private _getTags: () => Map<string, string>;
29
29
 
30
30
  constructor(options: DatadogOptions) {
31
31
  this._getTags = options.getTags;
@@ -36,7 +36,9 @@ export class DatadogMetrics {
36
36
 
37
37
  gauge(name: string, value: number, tags?: any) {
38
38
  invariant(this._datadogmetrics, 'Datadog not initialized');
39
- const mergedTags = Object.entries({ ...this._getTags(), ...tags }).map(([key, value]) => `${key}:${value}`);
39
+ const mergedTags = Object.entries({ ...Object.fromEntries(this._getTags().entries()), ...tags }).map(
40
+ ([key, value]) => `${key}:${value}`,
41
+ );
40
42
  log('datadog gauge', { name, value, tags: mergedTags });
41
43
  this._datadogmetrics.gauge(name, value, mergedTags);
42
44
  }
@@ -6,16 +6,46 @@
6
6
  import * as localForage from 'localforage';
7
7
 
8
8
  // import { type Platform } from '@dxos/client-services';
9
- // import { type InitOptions as TelemetryInitOptions } from '@dxos/telemetry';
10
-
11
- import type { Config } from '@dxos/client';
9
+ import type { Client, Config } from '@dxos/client';
12
10
  import { log } from '@dxos/log';
11
+ // import { type InitOptions as TelemetryInitOptions } from '@dxos/telemetry';
13
12
 
14
- import type { IPData } from './common';
15
13
  import type { Mode, Observability } from '../observability';
16
14
 
17
- export const OBSERVABILITY_DISABLED_KEY = 'observability-disabled';
18
- export const OBSERVABILITY_GROUP_KEY = 'observability-group';
15
+ export const BASE_TELEMETRY_PROPERTIES: any = {};
16
+ // item name is 'telemetry' for backwards compatibility
17
+ export const OBSERVABILITY_DISABLED_KEY = 'telemetry-disabled';
18
+ export const OBSERVABILITY_GROUP_KEY = 'telemetry-group';
19
+
20
+ if (typeof navigator !== 'undefined' && navigator.storage?.estimate) {
21
+ setInterval(async () => {
22
+ try {
23
+ const storageEstimate = await navigator.storage.estimate();
24
+ BASE_TELEMETRY_PROPERTIES.storageUsage = storageEstimate.usage;
25
+ BASE_TELEMETRY_PROPERTIES.storageQuota = storageEstimate.quota;
26
+ } catch (error) {
27
+ log.warn('Failed to run estimate()', error);
28
+ }
29
+ }, 10e3);
30
+ }
31
+
32
+ // TODO(wittjosiah): Improve privacy of telemetry identifiers.
33
+ // - Identifier should be generated client-side with no attachment to identity.
34
+ // - Identifier can then be reset by user.
35
+ // - Identifier can be synced via HALO to allow for correlation of events bewteen devices.
36
+ // - Identifier should also be stored outside of HALO such that it is available immediately on startup.
37
+ export const getTelemetryIdentifier = (client: Client) => {
38
+ if (!client?.initialized) {
39
+ return undefined;
40
+ }
41
+
42
+ const identity = client.halo.identity.get();
43
+ if (identity) {
44
+ return identity.identityKey.truncate();
45
+ }
46
+
47
+ return undefined;
48
+ };
19
49
 
20
50
  export const isObservabilityDisabled = async (namespace: string): Promise<boolean> => {
21
51
  try {
@@ -59,7 +89,9 @@ export type AppObservabilityOptions = {
59
89
  // TODO(nf): options for providers?
60
90
  };
61
91
 
62
- // TODO(wittjosiah): Store preference for disabling observability.
92
+ type IPData = { city: string; region: string; country: string; latitude: number; longitude: number };
93
+
94
+ // TODO(wittjosiah): Store preference for disabling telemetry.
63
95
  // At minimum should be stored locally (i.e., localstorage), possibly in halo preference.
64
96
  // Needs to be hooked up to settings page for user visibility.
65
97
  export const initializeAppObservability = async ({
@@ -82,7 +114,9 @@ export const initializeAppObservability = async ({
82
114
  const group = (await getObservabilityGroup(namespace)) ?? undefined;
83
115
  const release = `${namespace}@${config.get('runtime.app.build.version')}`;
84
116
  const environment = config.get('runtime.app.env.DX_ENVIRONMENT');
85
-
117
+ BASE_TELEMETRY_PROPERTIES.group = group;
118
+ BASE_TELEMETRY_PROPERTIES.release = release;
119
+ BASE_TELEMETRY_PROPERTIES.environment = environment;
86
120
  const observabilityDisabled = await isObservabilityDisabled(namespace);
87
121
 
88
122
  const { Observability } = await import('../observability');
@@ -123,11 +157,12 @@ export const initializeAppObservability = async ({
123
157
  };
124
158
 
125
159
  // Check cache first.
126
- const cachedData: null | CachedIPData = await localForage.getItem('dxos:observability:ipdata');
160
+ const cachedData: null | CachedIPData = await localForage.getItem('dxos:telemetry:ipdata');
127
161
  if (cachedData && cachedData.timestamp > Date.now() - IP_DATA_CACHE_TIMEOUT) {
128
162
  return cachedData.data;
129
163
  }
130
164
 
165
+ // TODO(nf): move into observability
131
166
  // Fetch data if not cached.
132
167
  const IPDATA_API_KEY = config.get('runtime.app.env.DX_IPDATA_API_KEY');
133
168
  if (IPDATA_API_KEY) {
@@ -136,7 +171,7 @@ export const initializeAppObservability = async ({
136
171
  .then((data) => {
137
172
  // Cache data.
138
173
  localForage
139
- .setItem('dxos:observability:ipdata', {
174
+ .setItem('dxos:telemetry:ipdata', {
140
175
  data,
141
176
  timestamp: Date.now(),
142
177
  })
@@ -148,27 +183,20 @@ export const initializeAppObservability = async ({
148
183
  }
149
184
  };
150
185
 
186
+ const ipData = await getIPData(config);
187
+ if (ipData && ipData.city) {
188
+ BASE_TELEMETRY_PROPERTIES.city = ipData.city;
189
+ BASE_TELEMETRY_PROPERTIES.region = ipData.region;
190
+ BASE_TELEMETRY_PROPERTIES.country = ipData.country;
191
+ BASE_TELEMETRY_PROPERTIES.latitude = ipData.latitude;
192
+ BASE_TELEMETRY_PROPERTIES.longitude = ipData.longitude;
193
+ }
194
+
151
195
  // TODO(nf): plugin state?
152
196
 
153
197
  // TODO(nf): should provide capability to init Sentry earlier in booting process to capture errors during initialization.
154
198
 
155
199
  observability.initialize();
156
-
157
- const ipData = await getIPData(config);
158
-
159
- ipData && observability.addIPDataTelemetryTags(ipData);
160
-
161
- if (typeof navigator !== 'undefined' && navigator.storage?.estimate) {
162
- setInterval(async () => {
163
- try {
164
- const storageEstimate = await navigator.storage.estimate();
165
- storageEstimate.usage && observability.setTag('storageUsage', storageEstimate.usage.toString(), 'telemetry');
166
- storageEstimate.quota && observability.setTag('storageQuota', storageEstimate.quota.toString(), 'telemetry');
167
- } catch (error) {
168
- log.warn('Failed to run estimate()', error);
169
- }
170
- }, 10e3);
171
- }
172
200
  } catch (err: any) {
173
201
  log.error('Failed to initialize app observability', err);
174
202
  }
@@ -2,8 +2,6 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- export * from './browser-observability';
6
- export * from './common';
7
- export * from './node-observability';
5
+ export * from './app-observability';
8
6
  export * from './map-spaces';
9
7
  export * from './setup-telemetry-listeners';
@@ -4,7 +4,7 @@
4
4
 
5
5
  import type { Client } from '@dxos/client';
6
6
 
7
- import { getTelemetryIdentifier } from './common';
7
+ import { BASE_TELEMETRY_PROPERTIES, getTelemetryIdentifier } from './app-observability';
8
8
  import type { Observability } from '../observability';
9
9
 
10
10
  let lastFocusEvent = new Date();
@@ -12,7 +12,7 @@ let totalTime = 0;
12
12
 
13
13
  export const setupTelemetryListeners = (namespace: string, client: Client, observability: Observability) => {
14
14
  const clickCallback = (event: any) => {
15
- if (observability.group === 'dxos' && event.target && !event.target.id) {
15
+ if (BASE_TELEMETRY_PROPERTIES.group === 'dxos' && event.target && !event.target.id) {
16
16
  // TODO(wittjosiah): Use @dxos/log so these can be filtered.
17
17
  console.warn('Click event on element without id:', event.target);
18
18
  }
@@ -22,6 +22,7 @@ export const setupTelemetryListeners = (namespace: string, client: Client, obser
22
22
  identityId: getTelemetryIdentifier(client),
23
23
  name: `${namespace}.window.click`,
24
24
  properties: {
25
+ ...BASE_TELEMETRY_PROPERTIES,
25
26
  href: window.location.href,
26
27
  id: (event.target as HTMLElement)?.id,
27
28
  path: (event.path as HTMLElement[])
@@ -41,6 +42,7 @@ export const setupTelemetryListeners = (namespace: string, client: Client, obser
41
42
  identityId: getTelemetryIdentifier(client),
42
43
  name: `${namespace}.window.focus`,
43
44
  properties: {
45
+ ...BASE_TELEMETRY_PROPERTIES,
44
46
  href: window.location.href,
45
47
  timeAway: now.getTime() - lastFocusEvent.getTime(),
46
48
  },
@@ -57,6 +59,7 @@ export const setupTelemetryListeners = (namespace: string, client: Client, obser
57
59
  identityId: getTelemetryIdentifier(client),
58
60
  name: `${namespace}.window.blur`,
59
61
  properties: {
62
+ ...BASE_TELEMETRY_PROPERTIES,
60
63
  href: window.location.href,
61
64
  timeSpent,
62
65
  },
@@ -72,6 +75,7 @@ export const setupTelemetryListeners = (namespace: string, client: Client, obser
72
75
  identityId: getTelemetryIdentifier(client),
73
76
  name: `${namespace}.page.unload`,
74
77
  properties: {
78
+ ...BASE_TELEMETRY_PROPERTIES,
75
79
  href: window.location.href,
76
80
  timeSpent: totalTime,
77
81
  },
@@ -85,6 +89,7 @@ export const setupTelemetryListeners = (namespace: string, client: Client, obser
85
89
  identityId: getTelemetryIdentifier(client),
86
90
  name: `${namespace}.window.error`,
87
91
  properties: {
92
+ ...BASE_TELEMETRY_PROPERTIES,
88
93
  href: window.location.href,
89
94
  message: event.message,
90
95
  filename: event.filename,
@@ -14,7 +14,7 @@ import { isNode } from '@dxos/util';
14
14
 
15
15
  import buildSecrets from './cli-observability-secrets.json';
16
16
  import { DatadogMetrics } from './datadog';
17
- import { type IPData, getTelemetryIdentifier, mapSpaces } from './helpers';
17
+ import { BASE_TELEMETRY_PROPERTIES, getTelemetryIdentifier, mapSpaces } from './helpers';
18
18
  import { SegmentTelemetry, type EventOptions, type PageOptions } from './segment';
19
19
  import {
20
20
  captureException as sentryCaptureException,
@@ -29,6 +29,9 @@ const SPACE_METRICS_MIN_INTERVAL = 1000 * 60;
29
29
  // const DATADOG_IDLE_INTERVAL = 1000 * 60 * 5;
30
30
  const DATADOG_IDLE_INTERVAL = 1000 * 60 * 1;
31
31
 
32
+ // TODO(nf): add allowlist for telemetry tags?
33
+ const ERROR_TAGS = ['identityKey', 'username', 'deviceKey', 'group'];
34
+
32
35
  // Secrets? EnvironmentConfig?
33
36
 
34
37
  export type ObservabilitySecrets = {
@@ -42,7 +45,6 @@ export type ObservabilitySecrets = {
42
45
  };
43
46
 
44
47
  export type Mode = 'basic' | 'full' | 'disabled';
45
- export type TagScope = 'errors' | 'telemetry' | 'metrics' | 'all';
46
48
 
47
49
  export type ObservabilityOptions = {
48
50
  /// The webapp (e.g. 'composer.dxos.org'), 'cli', or 'agent'.
@@ -85,7 +87,7 @@ export class Observability {
85
87
  private _group?: string;
86
88
  // TODO(nf): accept upstream context?
87
89
  private _ctx = new Context();
88
- private _tags = new Map<string, { value: string; scope: TagScope }>();
90
+ private _tags = new Map<string, string>();
89
91
 
90
92
  // TODO(nf): make platform a required extension?
91
93
  constructor({ namespace, config, secrets, group, mode, telemetry, errorLog }: ObservabilityOptions) {
@@ -110,20 +112,7 @@ export class Observability {
110
112
 
111
113
  private _loadSecrets(config: Config | undefined, secrets?: Record<string, string>) {
112
114
  if (isNode()) {
113
- const mergedSecrets = {
114
- ...(buildSecrets as ObservabilitySecrets),
115
- ...secrets,
116
- };
117
-
118
- process.env.DX_ENVIRONMENT && (mergedSecrets.DX_ENVIRONMENT = process.env.DX_ENVIRONMENT);
119
- process.env.DX_RELEASE && (mergedSecrets.DX_RELEASE = process.env.DX_RELEASE);
120
- process.env.SENTRY_DESTINATION && (mergedSecrets.SENTRY_DESTINATION = process.env.SENTRY_DESTINATION);
121
- process.env.TELEMETRY_API_KEY && (mergedSecrets.TELEMETRY_API_KEY = process.env.TELEMETRY_API_KEY);
122
- process.env.IPDATA_API_KEY && (mergedSecrets.IPDATA_API_KEY = process.env.IPDATA_API_KEY);
123
- process.env.DATADOG_API_KEY && (mergedSecrets.DATADOG_API_KEY = process.env.DATADOG_API_KEY);
124
- process.env.DATADOG_APP_KEY && (mergedSecrets.DATADOG_APP_KEY = process.env.DATADOG_APP_KEY);
125
-
126
- return mergedSecrets;
115
+ return buildSecrets as ObservabilitySecrets;
127
116
  } else {
128
117
  invariant(config, 'runtime config is required');
129
118
  log('config', { rtc: this._secrets, config });
@@ -160,10 +149,6 @@ export class Observability {
160
149
  return this._mode;
161
150
  }
162
151
 
163
- get group() {
164
- return this._group;
165
- }
166
-
167
152
  get enabled() {
168
153
  return this._mode !== 'disabled';
169
154
  }
@@ -172,28 +157,17 @@ export class Observability {
172
157
  // Tags
173
158
  //
174
159
 
175
- setTag(key: string, value: string, scope?: TagScope) {
176
- if (this.enabled && (scope === undefined || scope === 'all' || scope === 'errors')) {
160
+ /**
161
+ * Set a tag for all observability services.
162
+ */
163
+ setTag(key: string, value: string) {
164
+ if (this.enabled && ERROR_TAGS.includes(key)) {
177
165
  sentrySetTag(key, value);
178
166
  }
179
- if (!scope) {
180
- scope = 'all';
181
- }
182
- this._tags.set(key, { value, scope });
183
- }
184
167
 
185
- getTag(key: string) {
186
- return this._tags.get(key);
168
+ this._tags.set(key, value);
187
169
  }
188
170
 
189
- addIPDataTelemetryTags = (ipData: IPData) => {
190
- this.setTag('city', ipData.city, 'telemetry');
191
- this.setTag('region', ipData.region, 'telemetry');
192
- this.setTag('country', ipData.country, 'telemetry');
193
- ipData.latitude && this.setTag('latitude', ipData.latitude.toString(), 'telemetry');
194
- ipData.longitude && this.setTag('longitude', ipData.longitude.toString(), 'telemetry');
195
- };
196
-
197
171
  // TODO(wittjosiah): Improve privacy of telemetry identifiers. See `getTelemetryIdentifier`.
198
172
  async setIdentityTags(client: Client) {
199
173
  client.services.services.IdentityService!.queryIdentity().subscribe((idqr) => {
@@ -232,14 +206,7 @@ export class Observability {
232
206
  if (this.enabled && this._secrets.DATADOG_API_KEY) {
233
207
  this._metrics = new DatadogMetrics({
234
208
  apiKey: this._secrets.DATADOG_API_KEY,
235
- getTags: () =>
236
- Object.fromEntries(
237
- Array.from(this._tags)
238
- .filter(([key, value]) => {
239
- return value.scope === 'all' || value.scope === 'metrics';
240
- })
241
- .map(([key, value]) => [key, value.value]),
242
- ),
209
+ getTags: () => this._tags,
243
210
  // TODO(nf): move/refactor from telementryContext, needed to read CORS proxy
244
211
  config: this._config!,
245
212
  });
@@ -328,7 +295,10 @@ export class Observability {
328
295
  this.event({
329
296
  identityId: getTelemetryIdentifier(client),
330
297
  name: `${namespace}.space.update`,
331
- properties: data,
298
+ properties: {
299
+ ...BASE_TELEMETRY_PROPERTIES,
300
+ ...data,
301
+ },
332
302
  });
333
303
  }
334
304
  });
@@ -402,14 +372,7 @@ export class Observability {
402
372
  this._telemetry = new SegmentTelemetry({
403
373
  apiKey: this._secrets.TELEMETRY_API_KEY,
404
374
  batchSize: this._telemetryBatchSize,
405
- getTags: () =>
406
- Object.fromEntries(
407
- Array.from(this._tags)
408
- .filter(([key, value]) => {
409
- return value.scope === 'all' || value.scope === 'telemetry';
410
- })
411
- .map(([key, value]) => [key, value.value]),
412
- ),
375
+ getTags: () => this._tags,
413
376
  });
414
377
  } else {
415
378
  log('segment disabled');
@@ -459,8 +422,8 @@ export class Observability {
459
422
  }
460
423
  // TODO(nf): is this different than passing as properties in options?
461
424
  this._tags.forEach((v, k) => {
462
- if (v.scope === 'all' || v.scope === 'errors') {
463
- sentrySetTag(k, v.value);
425
+ if (ERROR_TAGS.includes(k)) {
426
+ sentrySetTag(k, v);
464
427
  }
465
428
  });
466
429
  } else {
@@ -10,7 +10,7 @@ import type { EventOptions, SegmentTelemetryOptions, PageOptions } from './types
10
10
  import { captureException } from '../sentry';
11
11
 
12
12
  export class SegmentTelemetry {
13
- private _getTags: () => { [key: string]: string };
13
+ private _getTags: () => Map<string, string>;
14
14
 
15
15
  constructor({ apiKey, batchSize, getTags }: SegmentTelemetryOptions) {
16
16
  this._getTags = getTags;
@@ -31,7 +31,7 @@ export class SegmentTelemetry {
31
31
  page({ identityId: userId, ...options }: PageOptions = {}) {
32
32
  try {
33
33
  (window as any).analytics?.page({
34
- context: this._getTags(),
34
+ context: Object.fromEntries(this._getTags().entries()),
35
35
  ...options,
36
36
  userId,
37
37
  });
@@ -44,7 +44,7 @@ export class SegmentTelemetry {
44
44
  try {
45
45
  options.properties = {
46
46
  ...options.properties,
47
- ...this._getTags(),
47
+ ...Object.fromEntries(this._getTags().entries()),
48
48
  };
49
49
  (window as any).analytics?.track({
50
50
  ...options,
@@ -12,7 +12,7 @@ import { captureException } from '../sentry';
12
12
 
13
13
  export class SegmentTelemetry {
14
14
  private _analytics?: Analytics;
15
- private _getTags: () => { [key: string]: string };
15
+ private _getTags: () => Map<string, string>;
16
16
 
17
17
  constructor({ apiKey, batchSize, getTags }: SegmentTelemetryOptions) {
18
18
  this._getTags = getTags;
@@ -52,7 +52,7 @@ export class SegmentTelemetry {
52
52
  * Track an event.
53
53
  */
54
54
  event({ installationId: anonymousId, identityId: userId, name: event, ...options }: EventOptions) {
55
- log('sending event to telemetry', { event, options, tags: this._getTags() });
55
+ log('sending event to telemetry', { event, options, tags: Object.fromEntries(this._getTags().entries()) });
56
56
  if (!this._analytics) {
57
57
  log('Analytics not initialized', { action: 'event' });
58
58
  return;
@@ -61,7 +61,7 @@ export class SegmentTelemetry {
61
61
  try {
62
62
  this._analytics.track({
63
63
  ...options,
64
- context: this._getTags(),
64
+ context: Object.fromEntries(this._getTags().entries()),
65
65
  userId,
66
66
  anonymousId: anonymousId!,
67
67
  event,
@@ -6,7 +6,7 @@ export type SegmentTelemetryOptions = {
6
6
  apiKey?: string;
7
7
  batchSize?: number;
8
8
  enable?: boolean;
9
- getTags: () => { [key: string]: string };
9
+ getTags: () => Map<string, string>;
10
10
  };
11
11
 
12
12
  type CommonOptions = {
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/segment/browser.ts"],
4
- "sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nimport snippet from '@segment/snippet';\n\nimport { log } from '@dxos/log';\n\nimport type { EventOptions, SegmentTelemetryOptions, PageOptions } from './types';\nimport { captureException } from '../sentry';\n\nexport class SegmentTelemetry {\n private _getTags: () => { [key: string]: string };\n\n constructor({ apiKey, batchSize, getTags }: SegmentTelemetryOptions) {\n this._getTags = getTags;\n try {\n const contents = snippet.min({\n apiKey,\n page: false,\n });\n\n const script = document.createElement('script');\n script.innerHTML = contents;\n document.body.append(script);\n } catch (err) {\n log.catch('Failed to initialize telemetry', err);\n }\n }\n\n page({ identityId: userId, ...options }: PageOptions = {}) {\n try {\n (window as any).analytics?.page({\n context: this._getTags(),\n ...options,\n userId,\n });\n } catch (err) {\n log.catch('Failed to track page', err);\n }\n }\n\n event({ identityId: userId, name: event, ...options }: EventOptions) {\n try {\n options.properties = {\n ...options.properties,\n ...this._getTags(),\n };\n (window as any).analytics?.track({\n ...options,\n event,\n });\n } catch (err) {\n log.catch('Failed to track event', err);\n }\n }\n\n async flush() {\n try {\n await (window as any).analytics?.flush((err: any) => {\n captureException(err);\n });\n } catch (err) {\n log.catch('Failed to flush telemetry', err);\n }\n }\n}\n"],
5
- "mappings": ";;;;;AAIA,OAAOA,aAAa;AAEpB,SAASC,WAAW;;AAKb,IAAMC,mBAAN,MAAMA;EAGXC,YAAY,EAAEC,QAAQC,WAAWC,QAAO,GAA6B;AACnE,SAAKC,WAAWD;AAChB,QAAI;AACF,YAAME,WAAWC,QAAQC,IAAI;QAC3BN;QACAO,MAAM;MACR,CAAA;AAEA,YAAMC,SAASC,SAASC,cAAc,QAAA;AACtCF,aAAOG,YAAYP;AACnBK,eAASG,KAAKC,OAAOL,MAAAA;IACvB,SAASM,KAAK;AACZC,UAAIC,MAAM,kCAAkCF,KAAAA;;;;;;IAC9C;EACF;EAEAP,KAAK,EAAEU,YAAYC,QAAQ,GAAGC,QAAAA,IAAyB,CAAC,GAAG;AACzD,QAAI;AACDC,aAAeC,WAAWd,KAAK;QAC9Be,SAAS,KAAKnB,SAAQ;QACtB,GAAGgB;QACHD;MACF,CAAA;IACF,SAASJ,KAAK;AACZC,UAAIC,MAAM,wBAAwBF,KAAAA;;;;;;IACpC;EACF;EAEAS,MAAM,EAAEN,YAAYC,QAAQM,MAAMD,OAAO,GAAGJ,QAAAA,GAAyB;AACnE,QAAI;AACFA,cAAQM,aAAa;QACnB,GAAGN,QAAQM;QACX,GAAG,KAAKtB,SAAQ;MAClB;AACCiB,aAAeC,WAAWK,MAAM;QAC/B,GAAGP;QACHI;MACF,CAAA;IACF,SAAST,KAAK;AACZC,UAAIC,MAAM,yBAAyBF,KAAAA;;;;;;IACrC;EACF;EAEA,MAAMa,QAAQ;AACZ,QAAI;AACF,YAAOP,OAAeC,WAAWM,MAAM,CAACb,QAAAA;AACtCc,yBAAiBd,GAAAA;MACnB,CAAA;IACF,SAASA,KAAK;AACZC,UAAIC,MAAM,6BAA6BF,KAAAA;;;;;;IACzC;EACF;AACF;",
6
- "names": ["snippet", "log", "SegmentTelemetry", "constructor", "apiKey", "batchSize", "getTags", "_getTags", "contents", "snippet", "min", "page", "script", "document", "createElement", "innerHTML", "body", "append", "err", "log", "catch", "identityId", "userId", "options", "window", "analytics", "context", "event", "name", "properties", "track", "flush", "captureException"]
7
- }