@azure/monitor-opentelemetry-exporter 1.0.0-beta.33 → 1.0.0-beta.34

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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/dist/commonjs/Declarations/Constants.d.ts +7 -2
  3. package/dist/commonjs/Declarations/Constants.d.ts.map +1 -1
  4. package/dist/commonjs/Declarations/Constants.js +8 -3
  5. package/dist/commonjs/Declarations/Constants.js.map +1 -1
  6. package/dist/commonjs/export/statsbeat/{customerStatsbeat.d.ts → customerSDKStats.d.ts} +30 -22
  7. package/dist/commonjs/export/statsbeat/customerSDKStats.d.ts.map +1 -0
  8. package/dist/commonjs/export/statsbeat/{customerStatsbeat.js → customerSDKStats.js} +175 -127
  9. package/dist/commonjs/export/statsbeat/customerSDKStats.js.map +1 -0
  10. package/dist/commonjs/export/statsbeat/types.d.ts +34 -9
  11. package/dist/commonjs/export/statsbeat/types.d.ts.map +1 -1
  12. package/dist/commonjs/export/statsbeat/types.js +45 -15
  13. package/dist/commonjs/export/statsbeat/types.js.map +1 -1
  14. package/dist/commonjs/generated/applicationInsightsClient.js +1 -1
  15. package/dist/commonjs/generated/applicationInsightsClient.js.map +1 -1
  16. package/dist/commonjs/platform/nodejs/baseSender.d.ts +1 -1
  17. package/dist/commonjs/platform/nodejs/baseSender.d.ts.map +1 -1
  18. package/dist/commonjs/platform/nodejs/baseSender.js +41 -26
  19. package/dist/commonjs/platform/nodejs/baseSender.js.map +1 -1
  20. package/dist/commonjs/platform/nodejs/persist/fileSystemPersist.d.ts +3 -3
  21. package/dist/commonjs/platform/nodejs/persist/fileSystemPersist.d.ts.map +1 -1
  22. package/dist/commonjs/platform/nodejs/persist/fileSystemPersist.js +8 -8
  23. package/dist/commonjs/platform/nodejs/persist/fileSystemPersist.js.map +1 -1
  24. package/dist/commonjs/tsdoc-metadata.json +1 -1
  25. package/dist/commonjs/types.d.ts +3 -1
  26. package/dist/commonjs/types.d.ts.map +1 -1
  27. package/dist/commonjs/types.js +4 -0
  28. package/dist/commonjs/types.js.map +1 -1
  29. package/dist/commonjs/utils/constants/applicationinsights.d.ts +2 -1
  30. package/dist/commonjs/utils/constants/applicationinsights.d.ts.map +1 -1
  31. package/dist/commonjs/utils/constants/applicationinsights.js +3 -2
  32. package/dist/commonjs/utils/constants/applicationinsights.js.map +1 -1
  33. package/dist/commonjs/utils/logUtils.d.ts.map +1 -1
  34. package/dist/commonjs/utils/logUtils.js +24 -6
  35. package/dist/commonjs/utils/logUtils.js.map +1 -1
  36. package/dist/commonjs/utils/spanUtils.d.ts.map +1 -1
  37. package/dist/commonjs/utils/spanUtils.js +16 -3
  38. package/dist/commonjs/utils/spanUtils.js.map +1 -1
  39. package/dist/esm/Declarations/Constants.d.ts +7 -2
  40. package/dist/esm/Declarations/Constants.d.ts.map +1 -1
  41. package/dist/esm/Declarations/Constants.js +7 -2
  42. package/dist/esm/Declarations/Constants.js.map +1 -1
  43. package/dist/esm/export/statsbeat/{customerStatsbeat.d.ts → customerSDKStats.d.ts} +30 -22
  44. package/dist/esm/export/statsbeat/customerSDKStats.d.ts.map +1 -0
  45. package/dist/esm/export/statsbeat/{customerStatsbeat.js → customerSDKStats.js} +175 -127
  46. package/dist/esm/export/statsbeat/customerSDKStats.js.map +1 -0
  47. package/dist/esm/export/statsbeat/types.d.ts +34 -9
  48. package/dist/esm/export/statsbeat/types.d.ts.map +1 -1
  49. package/dist/esm/export/statsbeat/types.js +43 -13
  50. package/dist/esm/export/statsbeat/types.js.map +1 -1
  51. package/dist/esm/generated/applicationInsightsClient.js +1 -1
  52. package/dist/esm/generated/applicationInsightsClient.js.map +1 -1
  53. package/dist/esm/platform/nodejs/baseSender.d.ts +1 -1
  54. package/dist/esm/platform/nodejs/baseSender.d.ts.map +1 -1
  55. package/dist/esm/platform/nodejs/baseSender.js +39 -24
  56. package/dist/esm/platform/nodejs/baseSender.js.map +1 -1
  57. package/dist/esm/platform/nodejs/persist/fileSystemPersist.d.ts +3 -3
  58. package/dist/esm/platform/nodejs/persist/fileSystemPersist.d.ts.map +1 -1
  59. package/dist/esm/platform/nodejs/persist/fileSystemPersist.js +9 -9
  60. package/dist/esm/platform/nodejs/persist/fileSystemPersist.js.map +1 -1
  61. package/dist/esm/types.d.ts +3 -1
  62. package/dist/esm/types.d.ts.map +1 -1
  63. package/dist/esm/types.js +4 -0
  64. package/dist/esm/types.js.map +1 -1
  65. package/dist/esm/utils/constants/applicationinsights.d.ts +2 -1
  66. package/dist/esm/utils/constants/applicationinsights.d.ts.map +1 -1
  67. package/dist/esm/utils/constants/applicationinsights.js +2 -1
  68. package/dist/esm/utils/constants/applicationinsights.js.map +1 -1
  69. package/dist/esm/utils/logUtils.d.ts.map +1 -1
  70. package/dist/esm/utils/logUtils.js +21 -3
  71. package/dist/esm/utils/logUtils.js.map +1 -1
  72. package/dist/esm/utils/spanUtils.d.ts.map +1 -1
  73. package/dist/esm/utils/spanUtils.js +19 -6
  74. package/dist/esm/utils/spanUtils.js.map +1 -1
  75. package/package.json +32 -33
  76. package/dist/commonjs/export/statsbeat/customerStatsbeat.d.ts.map +0 -1
  77. package/dist/commonjs/export/statsbeat/customerStatsbeat.js.map +0 -1
  78. package/dist/esm/export/statsbeat/customerStatsbeat.d.ts.map +0 -1
  79. package/dist/esm/export/statsbeat/customerStatsbeat.js.map +0 -1
@@ -2,7 +2,7 @@
2
2
  // Copyright (c) Microsoft Corporation.
3
3
  // Licensed under the MIT License.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.CustomerStatsbeatMetrics = void 0;
5
+ exports.CustomerSDKStatsMetrics = void 0;
6
6
  const tslib_1 = require("tslib");
7
7
  const api_1 = require("@opentelemetry/api");
8
8
  const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
@@ -14,20 +14,20 @@ const metricUtils_js_1 = require("../../utils/metricUtils.js");
14
14
  const statsbeatExporter_js_1 = require("./statsbeatExporter.js");
15
15
  const types_js_3 = require("../../types.js");
16
16
  /**
17
- * Class that handles customer-facing statsbeat metrics
17
+ * Class that handles customer-facing SDK Stats metrics
18
18
  * These metrics are sent to the customer's breeze endpoint
19
19
  *
20
- * Implements a singleton pattern to ensure only one set of customer statsbeat metrics
20
+ * Implements a singleton pattern to ensure only one set of customer SDK Stats metrics
21
21
  * is exported every 15 minutes, regardless of the number of exporters or senders.
22
22
  */
23
- class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
23
+ class CustomerSDKStatsMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
24
24
  static _instance;
25
25
  statsCollectionInterval = 900000; // 15 minutes
26
- customerStatsbeatMeter;
27
- customerStatsbeatMeterProvider;
28
- customerStatsbeatExporter;
29
- customerStatsbeatCounter;
30
- customerStatsbeatMetricReader;
26
+ customerSDKStatsMeter;
27
+ customerSDKStatsMeterProvider;
28
+ customerSDKStatsExporter;
29
+ customerSDKStatsCounter;
30
+ customerSDKStatsMetricReader;
31
31
  isInitialized = false;
32
32
  // Custom dimensions
33
33
  language;
@@ -37,35 +37,35 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
37
37
  itemSuccessCountGauge;
38
38
  itemDropCountGauge;
39
39
  itemRetryCountGauge;
40
- // Customer statsbeat properties
40
+ // Customer SDK Stats properties
41
41
  customerProperties;
42
42
  constructor(options) {
43
43
  super();
44
44
  const exporterConfig = {
45
45
  connectionString: `InstrumentationKey=${options.instrumentationKey};IngestionEndpoint=${options.endpointUrl}`,
46
46
  };
47
- this.customerStatsbeatExporter = new statsbeatExporter_js_1.AzureMonitorStatsbeatExporter(exporterConfig);
48
- // Exports Customer Statsbeat every 15 minutes
47
+ this.customerSDKStatsExporter = new statsbeatExporter_js_1.AzureMonitorStatsbeatExporter(exporterConfig);
48
+ // Exports Customer SDK Stats every 15 minutes
49
49
  const customerMetricReaderOptions = {
50
- exporter: this.customerStatsbeatExporter,
50
+ exporter: this.customerSDKStatsExporter,
51
51
  exportIntervalMillis: options.networkCollectionInterval || this.statsCollectionInterval,
52
52
  };
53
- this.customerStatsbeatMetricReader = new sdk_metrics_1.PeriodicExportingMetricReader(customerMetricReaderOptions);
54
- this.customerStatsbeatMeterProvider = new sdk_metrics_1.MeterProvider({
55
- readers: [this.customerStatsbeatMetricReader],
53
+ this.customerSDKStatsMetricReader = new sdk_metrics_1.PeriodicExportingMetricReader(customerMetricReaderOptions);
54
+ this.customerSDKStatsMeterProvider = new sdk_metrics_1.MeterProvider({
55
+ readers: [this.customerSDKStatsMetricReader],
56
56
  });
57
- this.customerStatsbeatMeter = this.customerStatsbeatMeterProvider.getMeter("Azure Monitor Customer Statsbeat");
57
+ this.customerSDKStatsMeter = this.customerSDKStatsMeterProvider.getMeter("Azure Monitor Customer SDK Stats");
58
58
  this.language = types_js_2.STATSBEAT_LANGUAGE;
59
59
  this.version = ai.packageVersion;
60
- this.itemSuccessCountGauge = this.customerStatsbeatMeter.createObservableGauge(types_js_2.CustomStatsbeatCounter.ITEM_SUCCESS_COUNT);
61
- this.itemDropCountGauge = this.customerStatsbeatMeter.createObservableGauge(types_js_2.CustomStatsbeatCounter.ITEM_DROP_COUNT);
62
- this.itemRetryCountGauge = this.customerStatsbeatMeter.createObservableGauge(types_js_2.CustomStatsbeatCounter.ITEM_RETRY_COUNT);
60
+ this.itemSuccessCountGauge = this.customerSDKStatsMeter.createObservableGauge(types_js_2.CustomSDKStatsCounter.ITEM_SUCCESS_COUNT);
61
+ this.itemDropCountGauge = this.customerSDKStatsMeter.createObservableGauge(types_js_2.CustomSDKStatsCounter.ITEM_DROP_COUNT);
62
+ this.itemRetryCountGauge = this.customerSDKStatsMeter.createObservableGauge(types_js_2.CustomSDKStatsCounter.ITEM_RETRY_COUNT);
63
63
  if (!this.isInitialized) {
64
64
  this.initialize();
65
65
  }
66
66
  this.isInitialized = true;
67
- // Initialize the single customer statsbeat counter
68
- this.customerStatsbeatCounter = new types_js_1.CustomerStatsbeat();
67
+ // Initialize the single customer SDK Stats counter
68
+ this.customerSDKStatsCounter = new types_js_1.CustomerSDKStats();
69
69
  this.customerProperties = {
70
70
  language: this.language,
71
71
  version: this.version,
@@ -73,99 +73,113 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
73
73
  };
74
74
  }
75
75
  /**
76
- * Get singleton instance of CustomerStatsbeatMetrics
77
- * @param options - Configuration options for customer statsbeat metrics
76
+ * Get singleton instance of CustomerSDKStatsMetrics
77
+ * @param options - Configuration options for customer SDK Stats metrics
78
78
  * @returns The singleton instance
79
79
  */
80
80
  static getInstance(options) {
81
- if (!CustomerStatsbeatMetrics._instance) {
82
- CustomerStatsbeatMetrics._instance = new CustomerStatsbeatMetrics(options);
81
+ if (!CustomerSDKStatsMetrics._instance) {
82
+ CustomerSDKStatsMetrics._instance = new CustomerSDKStatsMetrics(options);
83
83
  }
84
- return CustomerStatsbeatMetrics._instance;
84
+ return CustomerSDKStatsMetrics._instance;
85
85
  }
86
86
  /**
87
87
  * Shutdown the singleton instance
88
88
  * Used for cleanup and complete shutdown
89
89
  */
90
90
  static shutdown() {
91
- if (CustomerStatsbeatMetrics._instance) {
92
- const shutdownPromise = CustomerStatsbeatMetrics._instance.shutdown();
93
- CustomerStatsbeatMetrics._instance = undefined;
91
+ if (CustomerSDKStatsMetrics._instance) {
92
+ const shutdownPromise = CustomerSDKStatsMetrics._instance.shutdown();
93
+ CustomerSDKStatsMetrics._instance = undefined;
94
94
  return shutdownPromise;
95
95
  }
96
96
  return undefined;
97
97
  }
98
98
  /**
99
- * Shuts down the customer statsbeat metrics provider
99
+ * Shuts down the customer SDK Stats metrics provider
100
100
  * @returns Promise<void>
101
101
  */
102
102
  shutdown() {
103
- return this.customerStatsbeatMeterProvider.shutdown();
103
+ return this.customerSDKStatsMeterProvider.shutdown();
104
104
  }
105
105
  /**
106
- * Initializes the customer statsbeat metrics
106
+ * Initializes the customer SDK Stats metrics
107
107
  * Sets up the resource provider and adds observable callbacks for each metric
108
108
  * @returns Promise<void>
109
109
  */
110
110
  async initialize() {
111
111
  try {
112
112
  await super.getResourceProvider();
113
- this.customerStatsbeatMeter.addBatchObservableCallback(this.itemSuccessCallback.bind(this), [
113
+ this.customerSDKStatsMeter.addBatchObservableCallback(this.itemSuccessCallback.bind(this), [
114
114
  this.itemSuccessCountGauge,
115
115
  ]);
116
- this.customerStatsbeatMeter.addBatchObservableCallback(this.itemDropCallback.bind(this), [
116
+ this.customerSDKStatsMeter.addBatchObservableCallback(this.itemDropCallback.bind(this), [
117
117
  this.itemDropCountGauge,
118
118
  ]);
119
- this.customerStatsbeatMeter.addBatchObservableCallback(this.itemRetryCallback.bind(this), [
119
+ this.customerSDKStatsMeter.addBatchObservableCallback(this.itemRetryCallback.bind(this), [
120
120
  this.itemRetryCountGauge,
121
121
  ]);
122
122
  }
123
123
  catch (error) {
124
- api_1.diag.debug("Call to get the resource provider failed for customer statsbeat metrics.");
124
+ api_1.diag.debug("Call to get the resource provider failed for customer SDK Stats metrics.");
125
125
  }
126
126
  }
127
127
  // Observable gauge callbacks
128
128
  itemSuccessCallback(observableResult) {
129
- const counter = this.customerStatsbeatCounter;
129
+ const counter = this.customerSDKStatsCounter;
130
130
  const attributes = { ...this.customerProperties, telemetry_type: types_js_2.TelemetryType.UNKNOWN };
131
131
  // For each { telemetry_type -> count } mapping, call observe, passing the count and attributes that include the telemetry_type
132
132
  for (const [telemetry_type, count] of counter.totalItemSuccessCount.entries()) {
133
- attributes.telemetry_type = telemetry_type;
134
- observableResult.observe(this.itemSuccessCountGauge, count, {
135
- ...attributes,
136
- });
137
- counter.totalItemSuccessCount.set(telemetry_type, 0);
133
+ // Only send metrics if count is greater than zero
134
+ if (count > 0) {
135
+ attributes.telemetry_type = telemetry_type;
136
+ observableResult.observe(this.itemSuccessCountGauge, count, {
137
+ ...attributes,
138
+ });
139
+ counter.totalItemSuccessCount.set(telemetry_type, 0);
140
+ }
138
141
  }
139
142
  }
140
143
  itemDropCallback(observableResult) {
141
- const counter = this.customerStatsbeatCounter;
144
+ const counter = this.customerSDKStatsCounter;
142
145
  const baseAttributes = {
143
146
  ...this.customerProperties,
144
147
  "drop.code": types_js_1.DropCode.UNKNOWN,
145
148
  telemetry_type: types_js_2.TelemetryType.UNKNOWN,
146
149
  };
147
- // Iterate through the nested Map structure: telemetry_type -> drop.code -> reason -> count
150
+ // Iterate through the nested Map structure: telemetry_type -> drop.code -> reason -> telemetry_success -> count
148
151
  for (const [telemetryType, dropCodeMap] of counter.totalItemDropCount.entries()) {
149
152
  for (const [dropCode, reasonMap] of dropCodeMap.entries()) {
150
- for (const [reason, count] of reasonMap.entries()) {
151
- const attributes = { ...baseAttributes };
152
- attributes.telemetry_type = telemetryType;
153
- attributes["drop.code"] = dropCode;
154
- // Include drop.reason for all case
155
- if (reason) {
156
- attributes["drop.reason"] = reason;
153
+ for (const [reason, successMap] of reasonMap.entries()) {
154
+ for (const [success, count] of successMap.entries()) {
155
+ const attributes = { ...baseAttributes };
156
+ attributes.telemetry_type = telemetryType;
157
+ attributes["drop.code"] = dropCode;
158
+ // Include drop.reason for all cases
159
+ if (reason) {
160
+ attributes["drop.reason"] = reason;
161
+ }
162
+ // Include telemetry_success only for request/dependency telemetry when success is not null
163
+ if ((telemetryType === types_js_2.TelemetryType.REQUEST ||
164
+ telemetryType === types_js_2.TelemetryType.DEPENDENCY) &&
165
+ success !== null) {
166
+ attributes["telemetry_success"] = success;
167
+ }
168
+ // Only send metrics if count is greater than zero
169
+ if (count > 0) {
170
+ observableResult.observe(this.itemDropCountGauge, count, {
171
+ ...attributes,
172
+ });
173
+ }
174
+ // Reset the count to 0
175
+ successMap.set(success, 0);
157
176
  }
158
- observableResult.observe(this.itemDropCountGauge, count, {
159
- ...attributes,
160
- });
161
- // Reset the count to 0
162
- reasonMap.set(reason, 0);
163
177
  }
164
178
  }
165
179
  }
166
180
  }
167
181
  itemRetryCallback(observableResult) {
168
- const counter = this.customerStatsbeatCounter;
182
+ const counter = this.customerSDKStatsCounter;
169
183
  const baseAttributes = {
170
184
  ...this.customerProperties,
171
185
  "retry.code": types_js_1.RetryCode.UNKNOWN,
@@ -182,9 +196,12 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
182
196
  if (reason) {
183
197
  attributes["retry.reason"] = reason;
184
198
  }
185
- observableResult.observe(this.itemRetryCountGauge, count, {
186
- ...attributes,
187
- });
199
+ // Only send metrics if count is greater than zero
200
+ if (count > 0) {
201
+ observableResult.observe(this.itemRetryCountGauge, count, {
202
+ ...attributes,
203
+ });
204
+ }
188
205
  // Reset the count to 0
189
206
  reasonMap.set(reason, 0);
190
207
  }
@@ -198,7 +215,7 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
198
215
  * @param telemetry_type - The type of telemetry being tracked
199
216
  */
200
217
  countSuccessfulItems(envelopes) {
201
- const counter = this.customerStatsbeatCounter;
218
+ const counter = this.customerSDKStatsCounter;
202
219
  let telemetry_type;
203
220
  // Get the current count for this telemetry type, or 0 if it doesn't exist
204
221
  for (const envelope of envelopes) {
@@ -209,17 +226,16 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
209
226
  }
210
227
  /**
211
228
  * Tracks dropped items
212
- * @param envelopes - Number of envelopes dropped
229
+ * @param envelopes - Array of envelopes dropped
213
230
  * @param dropCode - The drop code indicating the reason for drop
214
- * @param telemetry_type - The type of telemetry being tracked
215
231
  * @param exceptionMessage - Optional exception message when dropCode is CLIENT_EXCEPTION
232
+ * @param exceptionType - Optional explicit exception type override when dropCode is CLIENT_EXCEPTION
216
233
  */
217
- countDroppedItems(envelopes, dropCode, exceptionMessage) {
218
- const counter = this.customerStatsbeatCounter;
234
+ countDroppedItems(envelopes, dropCode, exceptionMessage, exceptionType) {
235
+ const counter = this.customerSDKStatsCounter;
219
236
  let telemetry_type;
220
237
  for (const envelope of envelopes) {
221
238
  telemetry_type = this.getTelemetryTypeFromEnvelope(envelope);
222
- // Get or create the dropCode map for this telemetry_type
223
239
  let dropCodeMap = counter.totalItemDropCount.get(telemetry_type);
224
240
  if (!dropCodeMap) {
225
241
  dropCodeMap = new Map();
@@ -232,25 +248,42 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
232
248
  dropCodeMap.set(dropCode, reasonMap);
233
249
  }
234
250
  // Generate a low-cardinality, informative reason description
235
- const reason = this.getDropReason(dropCode, exceptionMessage);
236
- // Update the count for this reason
237
- const currentCount = reasonMap.get(reason) || 0;
238
- reasonMap.set(reason, currentCount + 1);
251
+ const reason = this.getDropReason(dropCode, exceptionMessage, exceptionType);
252
+ // Get or create the success map for this reason
253
+ let successMap = reasonMap.get(reason);
254
+ if (!successMap) {
255
+ successMap = new Map();
256
+ reasonMap.set(reason, successMap);
257
+ }
258
+ // For non-request/dependency telemetry or when success is not provided, use null as the success key
259
+ const individualTelemetrySuccess = this.getTelemetrySuccessFromEnvelope(envelope);
260
+ const successKey = (telemetry_type === types_js_2.TelemetryType.REQUEST || telemetry_type === types_js_2.TelemetryType.DEPENDENCY) &&
261
+ individualTelemetrySuccess !== undefined
262
+ ? individualTelemetrySuccess
263
+ : null;
264
+ // Update the count for this reason and success combination
265
+ const currentCount = successMap.get(successKey) || 0;
266
+ successMap.set(successKey, currentCount + 1);
239
267
  }
240
268
  }
241
269
  /**
242
270
  * Generates a low-cardinality, informative description for drop reasons
243
271
  * @param dropCode - The drop code (enum value or status code number)
244
272
  * @param exceptionMessage - Optional exception message for CLIENT_EXCEPTION
273
+ * @param exceptionType - Optional explicit exception type override for CLIENT_EXCEPTION
245
274
  * @returns A descriptive reason string with low cardinality
246
275
  */
247
- getDropReason(dropCode, exceptionMessage) {
276
+ getDropReason(dropCode, exceptionMessage, exceptionType) {
248
277
  if (dropCode === types_js_1.DropCode.CLIENT_EXCEPTION) {
249
- // For client exceptions, derive a low-cardinality reason from the exception message
278
+ // If an explicit exception type is provided, use it
279
+ if (exceptionType) {
280
+ return exceptionType;
281
+ }
282
+ // For client exceptions, derive a well-known exception category from the exception message
250
283
  if (exceptionMessage) {
251
284
  return this.categorizeExceptionMessage(exceptionMessage);
252
285
  }
253
- return "unknown_exception";
286
+ return types_js_1.ExceptionType.CLIENT_EXCEPTION; // Default to "Client exception" if no message provided
254
287
  }
255
288
  // Handle status code drop codes (numeric values)
256
289
  if (typeof dropCode === "number") {
@@ -258,49 +291,41 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
258
291
  }
259
292
  // Handle other enum drop codes
260
293
  switch (dropCode) {
261
- case types_js_1.DropCode.CLIENT_EXPIRED_DATA:
262
- return "expired_data";
263
294
  case types_js_1.DropCode.CLIENT_READONLY:
264
- return "readonly_mode";
265
- case types_js_1.DropCode.CLIENT_STALE_DATA:
266
- return "stale_data";
295
+ return types_js_1.DropReason.CLIENT_READONLY;
267
296
  case types_js_1.DropCode.CLIENT_PERSISTENCE_CAPACITY:
268
- return "persistence_full";
269
- case types_js_1.DropCode.NON_RETRYABLE_STATUS_CODE:
270
- return "non_retryable_status";
297
+ return types_js_1.DropReason.CLIENT_PERSISTENCE_CAPACITY;
298
+ case types_js_1.DropCode.CLIENT_STORAGE_DISABLED:
299
+ return types_js_1.DropReason.CLIENT_STORAGE_DISABLED;
271
300
  case types_js_1.DropCode.UNKNOWN:
272
301
  default:
273
- return "unknown_reason";
302
+ return types_js_1.DropReason.UNKNOWN;
274
303
  }
275
304
  }
276
305
  /**
277
- * Categorizes exception messages into low-cardinality groups
306
+ * Categorizes exception messages into well-known exception categories
278
307
  * @param exceptionMessage - The exception message to categorize
279
- * @returns A low-cardinality category string
308
+ * @returns A well-known exception category string
280
309
  */
281
310
  categorizeExceptionMessage(exceptionMessage) {
282
311
  const message = exceptionMessage.toLowerCase();
283
312
  if (message.includes("timeout") || message.includes("timed out")) {
284
- return "timeout_exception";
285
- }
286
- if (message.includes("network") || message.includes("connection")) {
287
- return "network_exception";
288
- }
289
- if (message.includes("auth") ||
290
- message.includes("unauthorized") ||
291
- message.includes("forbidden")) {
292
- return "auth_exception";
293
- }
294
- if (message.includes("parsing") || message.includes("parse") || message.includes("invalid")) {
295
- return "parsing_exception";
313
+ return types_js_1.ExceptionType.TIMEOUT_EXCEPTION;
296
314
  }
297
- if (message.includes("disk") || message.includes("storage") || message.includes("file")) {
298
- return "storage_exception";
315
+ if (message.includes("network") ||
316
+ message.includes("connection") ||
317
+ message.includes("dns") ||
318
+ message.includes("socket")) {
319
+ return types_js_1.ExceptionType.NETWORK_EXCEPTION;
299
320
  }
300
- if (message.includes("memory") || message.includes("out of memory")) {
301
- return "memory_exception";
321
+ if (message.includes("disk") ||
322
+ message.includes("storage") ||
323
+ message.includes("file") ||
324
+ message.includes("persist")) {
325
+ return types_js_1.ExceptionType.STORAGE_EXCEPTION;
302
326
  }
303
- return "other_exception";
327
+ // Default to Client exception for any other cases
328
+ return types_js_1.ExceptionType.CLIENT_EXCEPTION;
304
329
  }
305
330
  /**
306
331
  * Categorizes HTTP status codes into informative descriptions
@@ -311,35 +336,35 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
311
336
  if (statusCode >= 400 && statusCode < 500) {
312
337
  switch (statusCode) {
313
338
  case 400:
314
- return "bad_request";
339
+ return "Bad request";
315
340
  case 401:
316
- return "unauthorized";
341
+ return "Unauthorized";
317
342
  case 403:
318
- return "forbidden";
343
+ return "Forbidden";
319
344
  case 404:
320
- return "not_found";
345
+ return "Not found";
321
346
  case 408:
322
- return "request_timeout";
347
+ return "Request timeout";
323
348
  case 413:
324
- return "payload_too_large";
349
+ return "Payload too large";
325
350
  case 429:
326
- return "too_many_requests";
351
+ return "Too many requests";
327
352
  default:
328
- return "client_error_4xx";
353
+ return "Client error 4xx";
329
354
  }
330
355
  }
331
356
  if (statusCode >= 500 && statusCode < 600) {
332
357
  switch (statusCode) {
333
358
  case 500:
334
- return "internal_server_error";
359
+ return "Internal server error";
335
360
  case 502:
336
- return "bad_gateway";
361
+ return "Bad gateway";
337
362
  case 503:
338
- return "service_unavailable";
363
+ return "Service unavailable";
339
364
  case 504:
340
- return "gateway_timeout";
365
+ return "Gateway timeout";
341
366
  default:
342
- return "server_error_5xx";
367
+ return "Server error 5xx";
343
368
  }
344
369
  }
345
370
  return `status_${statusCode}`;
@@ -348,11 +373,11 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
348
373
  * Tracks retried envelopes
349
374
  * @param envelopes - Number of envelopes retried
350
375
  * @param retryCode - The retry code indicating the reason for retry
351
- * @param telemetry_type - The type of telemetry being tracked
352
376
  * @param exceptionMessage - Optional exception message when retryCode is CLIENT_EXCEPTION
377
+ * @param exceptionType - Optional explicit exception type override when retryCode is CLIENT_EXCEPTION
353
378
  */
354
- countRetryItems(envelopes, retryCode, exceptionMessage) {
355
- const counter = this.customerStatsbeatCounter;
379
+ countRetryItems(envelopes, retryCode, exceptionMessage, exceptionType) {
380
+ const counter = this.customerSDKStatsCounter;
356
381
  let telemetry_type;
357
382
  for (const envelope of envelopes) {
358
383
  telemetry_type = this.getTelemetryTypeFromEnvelope(envelope);
@@ -369,7 +394,7 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
369
394
  retryCodeMap.set(retryCode, reasonMap);
370
395
  }
371
396
  // Generate a low-cardinality, informative reason description
372
- const reason = this.getRetryReason(retryCode, exceptionMessage);
397
+ const reason = this.getRetryReason(retryCode, exceptionMessage, exceptionType);
373
398
  // Update the count for this reason
374
399
  const currentCount = reasonMap.get(reason) || 0;
375
400
  reasonMap.set(reason, currentCount + 1);
@@ -379,15 +404,20 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
379
404
  * Generates a low-cardinality, informative description for retry reasons
380
405
  * @param retryCode - The retry code (enum value or status code number)
381
406
  * @param exceptionMessage - Optional exception message for CLIENT_EXCEPTION
407
+ * @param exceptionType - Optional explicit exception type override for CLIENT_EXCEPTION
382
408
  * @returns A descriptive reason string with low cardinality
383
409
  */
384
- getRetryReason(retryCode, exceptionMessage) {
410
+ getRetryReason(retryCode, exceptionMessage, exceptionType) {
385
411
  if (retryCode === types_js_1.RetryCode.CLIENT_EXCEPTION) {
412
+ // If an explicit exception type is provided, use it
413
+ if (exceptionType) {
414
+ return exceptionType;
415
+ }
386
416
  // For client exceptions, derive a low-cardinality reason from the exception message
387
417
  if (exceptionMessage) {
388
418
  return this.categorizeExceptionMessage(exceptionMessage);
389
419
  }
390
- return "unknown_exception";
420
+ return types_js_1.ExceptionType.CLIENT_EXCEPTION;
391
421
  }
392
422
  // Handle status code retry codes (numeric values)
393
423
  if (typeof retryCode === "number") {
@@ -396,12 +426,10 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
396
426
  // Handle other enum retry codes
397
427
  switch (retryCode) {
398
428
  case types_js_1.RetryCode.CLIENT_TIMEOUT:
399
- return "client_timeout";
400
- case types_js_1.RetryCode.RETRYABLE_STATUS_CODE:
401
- return "retryable_status";
429
+ return types_js_1.RetryReason.CLIENT_TIMEOUT;
402
430
  case types_js_1.RetryCode.UNKNOWN:
403
431
  default:
404
- return "unknown_reason";
432
+ return types_js_1.RetryReason.UNKNOWN;
405
433
  }
406
434
  }
407
435
  /**
@@ -451,6 +479,26 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
451
479
  }
452
480
  return types_js_2.TelemetryType.UNKNOWN;
453
481
  }
482
+ /**
483
+ * Extract telemetry success value from an envelope for REQUEST and DEPENDENCY telemetry types
484
+ * @param envelope - The envelope to extract success value from
485
+ * @returns The success value if available, undefined otherwise
486
+ */
487
+ getTelemetrySuccessFromEnvelope(envelope) {
488
+ if (!envelope.data || !envelope.data.baseData) {
489
+ return undefined;
490
+ }
491
+ const baseType = envelope.data.baseType;
492
+ if (baseType === "RequestData") {
493
+ const requestData = envelope.data.baseData;
494
+ return requestData.success;
495
+ }
496
+ else if (baseType === "RemoteDependencyData") {
497
+ const dependencyData = envelope.data.baseData;
498
+ return dependencyData.success;
499
+ }
500
+ return undefined;
501
+ }
454
502
  /**
455
503
  * Checks if the given error is a timeout-related error
456
504
  * @param error - The error to check
@@ -476,5 +524,5 @@ class CustomerStatsbeatMetrics extends statsbeatMetrics_js_1.StatsbeatMetrics {
476
524
  return false;
477
525
  }
478
526
  }
479
- exports.CustomerStatsbeatMetrics = CustomerStatsbeatMetrics;
480
- //# sourceMappingURL=customerStatsbeat.js.map
527
+ exports.CustomerSDKStatsMetrics = CustomerSDKStatsMetrics;
528
+ //# sourceMappingURL=customerSDKStats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customerSDKStats.js","sourceRoot":"","sources":["../../../../src/export/statsbeat/customerSDKStats.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { BatchObservableResult, Meter, ObservableGauge } from \"@opentelemetry/api\";\nimport { diag } from \"@opentelemetry/api\";\nimport type { PeriodicExportingMetricReaderOptions } from \"@opentelemetry/sdk-metrics\";\nimport { MeterProvider, PeriodicExportingMetricReader } from \"@opentelemetry/sdk-metrics\";\nimport type { AzureMonitorExporterOptions } from \"../../index.js\";\nimport * as ai from \"../../utils/constants/applicationinsights.js\";\nimport { StatsbeatMetrics } from \"./statsbeatMetrics.js\";\nimport type { CustomerSDKStatsProperties, StatsbeatOptions } from \"./types.js\";\nimport {\n CustomerSDKStats,\n DropCode,\n RetryCode,\n ExceptionType,\n DropReason,\n RetryReason,\n} from \"./types.js\";\nimport { CustomSDKStatsCounter, STATSBEAT_LANGUAGE, TelemetryType } from \"./types.js\";\nimport { getAttachType } from \"../../utils/metricUtils.js\";\nimport { AzureMonitorStatsbeatExporter } from \"./statsbeatExporter.js\";\nimport { BreezePerformanceCounterNames } from \"../../types.js\";\nimport type { MetricsData, RemoteDependencyData, RequestData } from \"../../generated/index.js\";\nimport type { TelemetryItem as Envelope } from \"../../generated/index.js\";\n\n/**\n * Class that handles customer-facing SDK Stats metrics\n * These metrics are sent to the customer's breeze endpoint\n *\n * Implements a singleton pattern to ensure only one set of customer SDK Stats metrics\n * is exported every 15 minutes, regardless of the number of exporters or senders.\n */\nexport class CustomerSDKStatsMetrics extends StatsbeatMetrics {\n private static _instance: CustomerSDKStatsMetrics | undefined;\n\n private statsCollectionInterval: number = 900000; // 15 minutes\n private customerSDKStatsMeter: Meter;\n private customerSDKStatsMeterProvider: MeterProvider;\n private customerSDKStatsExporter: AzureMonitorStatsbeatExporter;\n private customerSDKStatsCounter: CustomerSDKStats;\n private customerSDKStatsMetricReader: PeriodicExportingMetricReader;\n private isInitialized: boolean = false;\n\n // Custom dimensions\n private language: string;\n private version: string;\n private attach: string = getAttachType();\n\n // Observable Gauges\n private itemSuccessCountGauge: ObservableGauge;\n private itemDropCountGauge: ObservableGauge;\n private itemRetryCountGauge: ObservableGauge;\n\n // Customer SDK Stats properties\n private customerProperties: CustomerSDKStatsProperties;\n\n private constructor(options: StatsbeatOptions) {\n super();\n const exporterConfig: AzureMonitorExporterOptions = {\n connectionString: `InstrumentationKey=${options.instrumentationKey};IngestionEndpoint=${options.endpointUrl}`,\n };\n\n this.customerSDKStatsExporter = new AzureMonitorStatsbeatExporter(exporterConfig);\n // Exports Customer SDK Stats every 15 minutes\n const customerMetricReaderOptions: PeriodicExportingMetricReaderOptions = {\n exporter: this.customerSDKStatsExporter,\n exportIntervalMillis: options.networkCollectionInterval || this.statsCollectionInterval,\n };\n this.customerSDKStatsMetricReader = new PeriodicExportingMetricReader(\n customerMetricReaderOptions,\n );\n this.customerSDKStatsMeterProvider = new MeterProvider({\n readers: [this.customerSDKStatsMetricReader],\n });\n\n this.customerSDKStatsMeter = this.customerSDKStatsMeterProvider.getMeter(\n \"Azure Monitor Customer SDK Stats\",\n );\n\n this.language = STATSBEAT_LANGUAGE;\n this.version = ai.packageVersion;\n\n this.itemSuccessCountGauge = this.customerSDKStatsMeter.createObservableGauge(\n CustomSDKStatsCounter.ITEM_SUCCESS_COUNT,\n );\n this.itemDropCountGauge = this.customerSDKStatsMeter.createObservableGauge(\n CustomSDKStatsCounter.ITEM_DROP_COUNT,\n );\n this.itemRetryCountGauge = this.customerSDKStatsMeter.createObservableGauge(\n CustomSDKStatsCounter.ITEM_RETRY_COUNT,\n );\n\n if (!this.isInitialized) {\n this.initialize();\n }\n this.isInitialized = true;\n\n // Initialize the single customer SDK Stats counter\n this.customerSDKStatsCounter = new CustomerSDKStats();\n\n this.customerProperties = {\n language: this.language,\n version: this.version,\n computeType: this.attach,\n };\n }\n\n /**\n * Get singleton instance of CustomerSDKStatsMetrics\n * @param options - Configuration options for customer SDK Stats metrics\n * @returns The singleton instance\n */\n public static getInstance(options: StatsbeatOptions): CustomerSDKStatsMetrics {\n if (!CustomerSDKStatsMetrics._instance) {\n CustomerSDKStatsMetrics._instance = new CustomerSDKStatsMetrics(options);\n }\n return CustomerSDKStatsMetrics._instance;\n }\n\n /**\n * Shutdown the singleton instance\n * Used for cleanup and complete shutdown\n */\n public static shutdown(): Promise<void> | undefined {\n if (CustomerSDKStatsMetrics._instance) {\n const shutdownPromise = CustomerSDKStatsMetrics._instance.shutdown();\n CustomerSDKStatsMetrics._instance = undefined;\n return shutdownPromise;\n }\n return undefined;\n }\n\n /**\n * Shuts down the customer SDK Stats metrics provider\n * @returns Promise<void>\n */\n public shutdown(): Promise<void> {\n return this.customerSDKStatsMeterProvider.shutdown();\n }\n\n /**\n * Initializes the customer SDK Stats metrics\n * Sets up the resource provider and adds observable callbacks for each metric\n * @returns Promise<void>\n */\n private async initialize(): Promise<void> {\n try {\n await super.getResourceProvider();\n this.customerSDKStatsMeter.addBatchObservableCallback(this.itemSuccessCallback.bind(this), [\n this.itemSuccessCountGauge,\n ]);\n this.customerSDKStatsMeter.addBatchObservableCallback(this.itemDropCallback.bind(this), [\n this.itemDropCountGauge,\n ]);\n this.customerSDKStatsMeter.addBatchObservableCallback(this.itemRetryCallback.bind(this), [\n this.itemRetryCountGauge,\n ]);\n } catch (error) {\n diag.debug(\"Call to get the resource provider failed for customer SDK Stats metrics.\");\n }\n }\n\n // Observable gauge callbacks\n private itemSuccessCallback(observableResult: BatchObservableResult): void {\n const counter: CustomerSDKStats = this.customerSDKStatsCounter;\n const attributes = { ...this.customerProperties, telemetry_type: TelemetryType.UNKNOWN };\n\n // For each { telemetry_type -> count } mapping, call observe, passing the count and attributes that include the telemetry_type\n for (const [telemetry_type, count] of counter.totalItemSuccessCount.entries()) {\n // Only send metrics if count is greater than zero\n if (count > 0) {\n attributes.telemetry_type = telemetry_type;\n observableResult.observe(this.itemSuccessCountGauge, count, {\n ...attributes,\n });\n counter.totalItemSuccessCount.set(telemetry_type, 0);\n }\n }\n }\n\n private itemDropCallback(observableResult: BatchObservableResult): void {\n const counter: CustomerSDKStats = this.customerSDKStatsCounter;\n const baseAttributes: CustomerSDKStatsProperties & {\n \"drop.code\": DropCode | number;\n telemetry_type: TelemetryType;\n } = {\n ...this.customerProperties,\n \"drop.code\": DropCode.UNKNOWN,\n telemetry_type: TelemetryType.UNKNOWN,\n };\n\n // Iterate through the nested Map structure: telemetry_type -> drop.code -> reason -> telemetry_success -> count\n for (const [telemetryType, dropCodeMap] of counter.totalItemDropCount.entries()) {\n for (const [dropCode, reasonMap] of dropCodeMap.entries()) {\n for (const [reason, successMap] of reasonMap.entries()) {\n for (const [success, count] of successMap.entries()) {\n const attributes = { ...baseAttributes };\n attributes.telemetry_type = telemetryType;\n attributes[\"drop.code\"] = dropCode;\n\n // Include drop.reason for all cases\n if (reason) {\n (attributes as any)[\"drop.reason\"] = reason;\n }\n\n // Include telemetry_success only for request/dependency telemetry when success is not null\n if (\n (telemetryType === TelemetryType.REQUEST ||\n telemetryType === TelemetryType.DEPENDENCY) &&\n success !== null\n ) {\n (attributes as any)[\"telemetry_success\"] = success;\n }\n\n // Only send metrics if count is greater than zero\n if (count > 0) {\n observableResult.observe(this.itemDropCountGauge, count, {\n ...attributes,\n });\n }\n\n // Reset the count to 0\n successMap.set(success, 0);\n }\n }\n }\n }\n }\n\n private itemRetryCallback(observableResult: BatchObservableResult): void {\n const counter: CustomerSDKStats = this.customerSDKStatsCounter;\n const baseAttributes: CustomerSDKStatsProperties & {\n \"retry.code\": RetryCode | number;\n telemetry_type: TelemetryType;\n } = {\n ...this.customerProperties,\n \"retry.code\": RetryCode.UNKNOWN,\n telemetry_type: TelemetryType.UNKNOWN,\n };\n\n // Iterate through the nested Map structure: telemetry_type -> retry.code -> reason -> count\n for (const [telemetryType, retryCodeMap] of counter.totalItemRetryCount.entries()) {\n for (const [retryCode, reasonMap] of retryCodeMap.entries()) {\n for (const [reason, count] of reasonMap.entries()) {\n const attributes = { ...baseAttributes };\n attributes.telemetry_type = telemetryType;\n attributes[\"retry.code\"] = retryCode;\n\n // Include retry.reason for all cases\n if (reason) {\n (attributes as any)[\"retry.reason\"] = reason;\n }\n\n // Only send metrics if count is greater than zero\n if (count > 0) {\n observableResult.observe(this.itemRetryCountGauge, count, {\n ...attributes,\n });\n }\n\n // Reset the count to 0\n reasonMap.set(reason, 0);\n }\n }\n }\n }\n\n // Public methods to track metrics\n /**\n * Tracks succcessful items\n * @param envelopes - Number of successful envelopes\n * @param telemetry_type - The type of telemetry being tracked\n */\n public countSuccessfulItems(envelopes: Envelope[]): void {\n const counter: CustomerSDKStats = this.customerSDKStatsCounter;\n let telemetry_type: TelemetryType;\n\n // Get the current count for this telemetry type, or 0 if it doesn't exist\n for (const envelope of envelopes) {\n telemetry_type = this.getTelemetryTypeFromEnvelope(envelope);\n const currentCount = counter.totalItemSuccessCount.get(telemetry_type) || 0;\n counter.totalItemSuccessCount.set(telemetry_type, currentCount + 1);\n }\n }\n\n /**\n * Tracks dropped items\n * @param envelopes - Array of envelopes dropped\n * @param dropCode - The drop code indicating the reason for drop\n * @param exceptionMessage - Optional exception message when dropCode is CLIENT_EXCEPTION\n * @param exceptionType - Optional explicit exception type override when dropCode is CLIENT_EXCEPTION\n */\n public countDroppedItems(\n envelopes: Envelope[],\n dropCode: DropCode | number,\n exceptionMessage?: string,\n exceptionType?: ExceptionType,\n ): void {\n const counter: CustomerSDKStats = this.customerSDKStatsCounter;\n let telemetry_type: TelemetryType;\n\n for (const envelope of envelopes) {\n telemetry_type = this.getTelemetryTypeFromEnvelope(envelope);\n\n let dropCodeMap = counter.totalItemDropCount.get(telemetry_type);\n if (!dropCodeMap) {\n dropCodeMap = new Map<DropCode | number, Map<string, Map<boolean | null, number>>>();\n counter.totalItemDropCount.set(telemetry_type, dropCodeMap);\n }\n\n // Get or create the reason map for this dropCode\n let reasonMap = dropCodeMap.get(dropCode);\n if (!reasonMap) {\n reasonMap = new Map<string, Map<boolean | null, number>>();\n dropCodeMap.set(dropCode, reasonMap);\n }\n\n // Generate a low-cardinality, informative reason description\n const reason = this.getDropReason(dropCode, exceptionMessage, exceptionType);\n\n // Get or create the success map for this reason\n let successMap = reasonMap.get(reason);\n if (!successMap) {\n successMap = new Map<boolean | null, number>();\n reasonMap.set(reason, successMap);\n }\n\n // For non-request/dependency telemetry or when success is not provided, use null as the success key\n const individualTelemetrySuccess = this.getTelemetrySuccessFromEnvelope(envelope);\n const successKey =\n (telemetry_type === TelemetryType.REQUEST || telemetry_type === TelemetryType.DEPENDENCY) &&\n individualTelemetrySuccess !== undefined\n ? individualTelemetrySuccess\n : null;\n\n // Update the count for this reason and success combination\n const currentCount = successMap.get(successKey) || 0;\n successMap.set(successKey, currentCount + 1);\n }\n }\n\n /**\n * Generates a low-cardinality, informative description for drop reasons\n * @param dropCode - The drop code (enum value or status code number)\n * @param exceptionMessage - Optional exception message for CLIENT_EXCEPTION\n * @param exceptionType - Optional explicit exception type override for CLIENT_EXCEPTION\n * @returns A descriptive reason string with low cardinality\n */\n private getDropReason(\n dropCode: DropCode | number,\n exceptionMessage?: string,\n exceptionType?: ExceptionType,\n ): string {\n if (dropCode === DropCode.CLIENT_EXCEPTION) {\n // If an explicit exception type is provided, use it\n if (exceptionType) {\n return exceptionType;\n }\n // For client exceptions, derive a well-known exception category from the exception message\n if (exceptionMessage) {\n return this.categorizeExceptionMessage(exceptionMessage);\n }\n return ExceptionType.CLIENT_EXCEPTION; // Default to \"Client exception\" if no message provided\n }\n\n // Handle status code drop codes (numeric values)\n if (typeof dropCode === \"number\") {\n return this.categorizeStatusCode(dropCode);\n }\n\n // Handle other enum drop codes\n switch (dropCode) {\n case DropCode.CLIENT_READONLY:\n return DropReason.CLIENT_READONLY;\n case DropCode.CLIENT_PERSISTENCE_CAPACITY:\n return DropReason.CLIENT_PERSISTENCE_CAPACITY;\n case DropCode.CLIENT_STORAGE_DISABLED:\n return DropReason.CLIENT_STORAGE_DISABLED;\n case DropCode.UNKNOWN:\n default:\n return DropReason.UNKNOWN;\n }\n }\n\n /**\n * Categorizes exception messages into well-known exception categories\n * @param exceptionMessage - The exception message to categorize\n * @returns A well-known exception category string\n */\n private categorizeExceptionMessage(exceptionMessage: string): ExceptionType {\n const message = exceptionMessage.toLowerCase();\n\n if (message.includes(\"timeout\") || message.includes(\"timed out\")) {\n return ExceptionType.TIMEOUT_EXCEPTION;\n }\n if (\n message.includes(\"network\") ||\n message.includes(\"connection\") ||\n message.includes(\"dns\") ||\n message.includes(\"socket\")\n ) {\n return ExceptionType.NETWORK_EXCEPTION;\n }\n if (\n message.includes(\"disk\") ||\n message.includes(\"storage\") ||\n message.includes(\"file\") ||\n message.includes(\"persist\")\n ) {\n return ExceptionType.STORAGE_EXCEPTION;\n }\n\n // Default to Client exception for any other cases\n return ExceptionType.CLIENT_EXCEPTION;\n }\n\n /**\n * Categorizes HTTP status codes into informative descriptions\n * @param statusCode - The HTTP status code\n * @returns A descriptive category string\n */\n private categorizeStatusCode(statusCode: number): string {\n if (statusCode >= 400 && statusCode < 500) {\n switch (statusCode) {\n case 400:\n return \"Bad request\";\n case 401:\n return \"Unauthorized\";\n case 403:\n return \"Forbidden\";\n case 404:\n return \"Not found\";\n case 408:\n return \"Request timeout\";\n case 413:\n return \"Payload too large\";\n case 429:\n return \"Too many requests\";\n default:\n return \"Client error 4xx\";\n }\n }\n\n if (statusCode >= 500 && statusCode < 600) {\n switch (statusCode) {\n case 500:\n return \"Internal server error\";\n case 502:\n return \"Bad gateway\";\n case 503:\n return \"Service unavailable\";\n case 504:\n return \"Gateway timeout\";\n default:\n return \"Server error 5xx\";\n }\n }\n\n return `status_${statusCode}`;\n }\n /**\n * Tracks retried envelopes\n * @param envelopes - Number of envelopes retried\n * @param retryCode - The retry code indicating the reason for retry\n * @param exceptionMessage - Optional exception message when retryCode is CLIENT_EXCEPTION\n * @param exceptionType - Optional explicit exception type override when retryCode is CLIENT_EXCEPTION\n */\n public countRetryItems(\n envelopes: Envelope[],\n retryCode: RetryCode | number,\n exceptionMessage?: string,\n exceptionType?: ExceptionType,\n ): void {\n const counter: CustomerSDKStats = this.customerSDKStatsCounter;\n let telemetry_type: TelemetryType;\n\n for (const envelope of envelopes) {\n telemetry_type = this.getTelemetryTypeFromEnvelope(envelope);\n // Get or create the retryCode map for this telemetry_type\n let retryCodeMap = counter.totalItemRetryCount.get(telemetry_type);\n if (!retryCodeMap) {\n retryCodeMap = new Map<RetryCode | number, Map<string, number>>();\n counter.totalItemRetryCount.set(telemetry_type, retryCodeMap);\n }\n\n // Get or create the reason map for this retryCode\n let reasonMap = retryCodeMap.get(retryCode);\n if (!reasonMap) {\n reasonMap = new Map<string, number>();\n retryCodeMap.set(retryCode, reasonMap);\n }\n\n // Generate a low-cardinality, informative reason description\n const reason = this.getRetryReason(retryCode, exceptionMessage, exceptionType);\n\n // Update the count for this reason\n const currentCount = reasonMap.get(reason) || 0;\n reasonMap.set(reason, currentCount + 1);\n }\n }\n\n /**\n * Generates a low-cardinality, informative description for retry reasons\n * @param retryCode - The retry code (enum value or status code number)\n * @param exceptionMessage - Optional exception message for CLIENT_EXCEPTION\n * @param exceptionType - Optional explicit exception type override for CLIENT_EXCEPTION\n * @returns A descriptive reason string with low cardinality\n */\n private getRetryReason(\n retryCode: RetryCode | number,\n exceptionMessage?: string,\n exceptionType?: ExceptionType,\n ): string {\n if (retryCode === RetryCode.CLIENT_EXCEPTION) {\n // If an explicit exception type is provided, use it\n if (exceptionType) {\n return exceptionType;\n }\n // For client exceptions, derive a low-cardinality reason from the exception message\n if (exceptionMessage) {\n return this.categorizeExceptionMessage(exceptionMessage);\n }\n return ExceptionType.CLIENT_EXCEPTION;\n }\n\n // Handle status code retry codes (numeric values)\n if (typeof retryCode === \"number\") {\n return this.categorizeStatusCode(retryCode);\n }\n\n // Handle other enum retry codes\n switch (retryCode) {\n case RetryCode.CLIENT_TIMEOUT:\n return RetryReason.CLIENT_TIMEOUT;\n case RetryCode.UNKNOWN:\n default:\n return RetryReason.UNKNOWN;\n }\n }\n\n /**\n * Check if a metric name corresponds to a performance counter\n * @param metricName - The name of the metric to check\n * @returns true if the metric name is a performance counter, false otherwise\n */\n private isPerformanceCounterMetric(metricName: string): boolean {\n return Object.values(BreezePerformanceCounterNames).includes(\n metricName as BreezePerformanceCounterNames,\n );\n }\n\n /**\n * Extract telemetry type from an envelope based on its baseType\n * @param envelope - The envelope to extract telemetry type from\n * @returns The corresponding telemetry type\n */\n public getTelemetryTypeFromEnvelope(envelope: Envelope): TelemetryType {\n if (envelope.data && envelope.data.baseType) {\n switch (envelope.data.baseType) {\n case \"MessageData\":\n return TelemetryType.TRACE;\n case \"AvailabilityData\":\n return TelemetryType.AVAILABILITY;\n case \"TelemetryEventData\":\n return TelemetryType.CUSTOM_EVENT;\n case \"TelemetryExceptionData\":\n return TelemetryType.EXCEPTION;\n case \"PageViewData\":\n return TelemetryType.PAGE_VIEW;\n case \"RemoteDependencyData\":\n return TelemetryType.DEPENDENCY;\n case \"RequestData\":\n return TelemetryType.REQUEST;\n case \"MetricData\": {\n const metricsData = envelope.data.baseData as MetricsData;\n if (metricsData && metricsData.metrics && metricsData.metrics.length > 0) {\n // Check if any of the metrics are performance counters\n const hasPerformanceCounter = metricsData.metrics.some((metric) =>\n this.isPerformanceCounterMetric(metric.name),\n );\n return hasPerformanceCounter\n ? TelemetryType.PERFORMANCE_COUNTER\n : TelemetryType.CUSTOM_METRIC;\n }\n return TelemetryType.CUSTOM_METRIC;\n }\n default:\n return TelemetryType.UNKNOWN;\n }\n }\n return TelemetryType.UNKNOWN;\n }\n\n /**\n * Extract telemetry success value from an envelope for REQUEST and DEPENDENCY telemetry types\n * @param envelope - The envelope to extract success value from\n * @returns The success value if available, undefined otherwise\n */\n public getTelemetrySuccessFromEnvelope(envelope: Envelope): boolean | undefined {\n if (!envelope.data || !envelope.data.baseData) {\n return undefined;\n }\n\n const baseType = envelope.data.baseType;\n if (baseType === \"RequestData\") {\n const requestData = envelope.data.baseData as RequestData;\n return requestData.success;\n } else if (baseType === \"RemoteDependencyData\") {\n const dependencyData = envelope.data.baseData as RemoteDependencyData;\n return dependencyData.success;\n }\n\n return undefined;\n }\n\n /**\n * Checks if the given error is a timeout-related error\n * @param error - The error to check\n * @returns true if the error is timeout-related, false otherwise\n */\n public isTimeoutError(error: { code?: string; message?: string }): boolean {\n // Check for various timeout error codes that indicate client timeouts\n const timeoutErrorCodes = [\n \"ETIMEDOUT\", // Connection timed out\n \"ESOCKETTIMEDOUT\", // Socket timeout\n \"ECONNRESET\", // Connection reset (often due to timeout)\n \"ENOTFOUND\", // DNS lookup failed/timeout\n ];\n\n if (error && error.code && timeoutErrorCodes.includes(error.code)) {\n return true;\n }\n\n // Also check if the error message contains timeout-related keywords\n if (error && error.message) {\n const timeoutKeywords = [\"timeout\", \"timed out\", \"connection reset\"];\n const errorMessage = error.message.toLowerCase();\n return timeoutKeywords.some((keyword) => errorMessage.includes(keyword));\n }\n\n return false;\n }\n}\n"]}