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

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