@azure/monitor-opentelemetry-exporter 1.0.0-beta.32 → 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 (193) hide show
  1. package/LICENSE +21 -0
  2. package/dist/commonjs/Declarations/Constants.d.ts +10 -0
  3. package/dist/commonjs/Declarations/Constants.d.ts.map +1 -1
  4. package/dist/commonjs/Declarations/Constants.js +11 -1
  5. package/dist/commonjs/Declarations/Constants.js.map +1 -1
  6. package/dist/commonjs/export/base.js +25 -14
  7. package/dist/commonjs/export/base.js.map +1 -1
  8. package/dist/commonjs/export/log.js +5 -4
  9. package/dist/commonjs/export/log.js.map +1 -1
  10. package/dist/commonjs/export/metric.js +5 -4
  11. package/dist/commonjs/export/metric.js.map +1 -1
  12. package/dist/commonjs/export/statsbeat/customerSDKStats.d.ts +133 -0
  13. package/dist/commonjs/export/statsbeat/customerSDKStats.d.ts.map +1 -0
  14. package/dist/commonjs/export/statsbeat/customerSDKStats.js +528 -0
  15. package/dist/commonjs/export/statsbeat/customerSDKStats.js.map +1 -0
  16. package/dist/commonjs/export/statsbeat/longIntervalStatsbeatMetrics.js +35 -11
  17. package/dist/commonjs/export/statsbeat/longIntervalStatsbeatMetrics.js.map +1 -1
  18. package/dist/commonjs/export/statsbeat/networkStatsbeatMetrics.js +52 -21
  19. package/dist/commonjs/export/statsbeat/networkStatsbeatMetrics.js.map +1 -1
  20. package/dist/commonjs/export/statsbeat/statsbeatExporter.d.ts +7 -0
  21. package/dist/commonjs/export/statsbeat/statsbeatExporter.d.ts.map +1 -1
  22. package/dist/commonjs/export/statsbeat/statsbeatExporter.js +25 -5
  23. package/dist/commonjs/export/statsbeat/statsbeatExporter.js.map +1 -1
  24. package/dist/commonjs/export/statsbeat/statsbeatMetrics.js +6 -8
  25. package/dist/commonjs/export/statsbeat/statsbeatMetrics.js.map +1 -1
  26. package/dist/commonjs/export/statsbeat/types.d.ts +77 -0
  27. package/dist/commonjs/export/statsbeat/types.d.ts.map +1 -1
  28. package/dist/commonjs/export/statsbeat/types.js +105 -1
  29. package/dist/commonjs/export/statsbeat/types.js.map +1 -1
  30. package/dist/commonjs/export/trace.js +6 -5
  31. package/dist/commonjs/export/trace.js.map +1 -1
  32. package/dist/commonjs/generated/applicationInsightsClient.js +9 -4
  33. package/dist/commonjs/generated/applicationInsightsClient.js.map +1 -1
  34. package/dist/commonjs/generated/models/mappers.js +145 -68
  35. package/dist/commonjs/generated/models/mappers.js.map +1 -1
  36. package/dist/commonjs/index.d.ts +2 -1
  37. package/dist/commonjs/index.d.ts.map +1 -1
  38. package/dist/commonjs/index.js +5 -3
  39. package/dist/commonjs/index.js.map +1 -1
  40. package/dist/commonjs/platform/nodejs/baseSender.d.ts +1 -0
  41. package/dist/commonjs/platform/nodejs/baseSender.d.ts.map +1 -1
  42. package/dist/commonjs/platform/nodejs/baseSender.js +92 -31
  43. package/dist/commonjs/platform/nodejs/baseSender.js.map +1 -1
  44. package/dist/commonjs/platform/nodejs/context/context.d.ts +0 -1
  45. package/dist/commonjs/platform/nodejs/context/context.d.ts.map +1 -1
  46. package/dist/commonjs/platform/nodejs/context/context.js +4 -8
  47. package/dist/commonjs/platform/nodejs/context/context.js.map +1 -1
  48. package/dist/commonjs/platform/nodejs/httpSender.js +11 -4
  49. package/dist/commonjs/platform/nodejs/httpSender.js.map +1 -1
  50. package/dist/commonjs/platform/nodejs/index.d.ts +1 -0
  51. package/dist/commonjs/platform/nodejs/index.d.ts.map +1 -1
  52. package/dist/commonjs/platform/nodejs/index.js +1 -0
  53. package/dist/commonjs/platform/nodejs/index.js.map +1 -1
  54. package/dist/commonjs/platform/nodejs/persist/fileAccessControl.js +7 -7
  55. package/dist/commonjs/platform/nodejs/persist/fileAccessControl.js.map +1 -1
  56. package/dist/commonjs/platform/nodejs/persist/fileSystemPersist.d.ts +9 -1
  57. package/dist/commonjs/platform/nodejs/persist/fileSystemPersist.d.ts.map +1 -1
  58. package/dist/commonjs/platform/nodejs/persist/fileSystemPersist.js +37 -16
  59. package/dist/commonjs/platform/nodejs/persist/fileSystemPersist.js.map +1 -1
  60. package/dist/commonjs/{sampling.d.ts → sampling/percentageSampler.d.ts} +2 -3
  61. package/dist/commonjs/sampling/percentageSampler.d.ts.map +1 -0
  62. package/dist/commonjs/{sampling.js → sampling/percentageSampler.js} +6 -39
  63. package/dist/commonjs/sampling/percentageSampler.js.map +1 -0
  64. package/dist/commonjs/sampling/rateLimitedSampler.d.ts +58 -0
  65. package/dist/commonjs/sampling/rateLimitedSampler.d.ts.map +1 -0
  66. package/dist/commonjs/sampling/rateLimitedSampler.js +118 -0
  67. package/dist/commonjs/sampling/rateLimitedSampler.js.map +1 -0
  68. package/dist/commonjs/sampling/samplingUtils.d.ts +17 -0
  69. package/dist/commonjs/sampling/samplingUtils.d.ts.map +1 -0
  70. package/dist/commonjs/sampling/samplingUtils.js +94 -0
  71. package/dist/commonjs/sampling/samplingUtils.js.map +1 -0
  72. package/dist/commonjs/tsdoc-metadata.json +11 -11
  73. package/dist/commonjs/types.d.ts +3 -1
  74. package/dist/commonjs/types.d.ts.map +1 -1
  75. package/dist/commonjs/types.js +4 -0
  76. package/dist/commonjs/types.js.map +1 -1
  77. package/dist/commonjs/utils/common.js +2 -3
  78. package/dist/commonjs/utils/common.js.map +1 -1
  79. package/dist/commonjs/utils/connectionStringParser.js +3 -3
  80. package/dist/commonjs/utils/connectionStringParser.js.map +1 -1
  81. package/dist/commonjs/utils/constants/applicationinsights.d.ts +2 -1
  82. package/dist/commonjs/utils/constants/applicationinsights.d.ts.map +1 -1
  83. package/dist/commonjs/utils/constants/applicationinsights.js +3 -2
  84. package/dist/commonjs/utils/constants/applicationinsights.js.map +1 -1
  85. package/dist/commonjs/utils/eventhub.js +5 -2
  86. package/dist/commonjs/utils/eventhub.js.map +1 -1
  87. package/dist/commonjs/utils/logUtils.d.ts.map +1 -1
  88. package/dist/commonjs/utils/logUtils.js +34 -15
  89. package/dist/commonjs/utils/logUtils.js.map +1 -1
  90. package/dist/commonjs/utils/metricUtils.d.ts.map +1 -1
  91. package/dist/commonjs/utils/metricUtils.js +6 -6
  92. package/dist/commonjs/utils/metricUtils.js.map +1 -1
  93. package/dist/commonjs/utils/spanUtils.d.ts.map +1 -1
  94. package/dist/commonjs/utils/spanUtils.js +29 -14
  95. package/dist/commonjs/utils/spanUtils.js.map +1 -1
  96. package/dist/esm/Declarations/Constants.d.ts +10 -0
  97. package/dist/esm/Declarations/Constants.d.ts.map +1 -1
  98. package/dist/esm/Declarations/Constants.js +10 -0
  99. package/dist/esm/Declarations/Constants.js.map +1 -1
  100. package/dist/esm/export/base.js +25 -14
  101. package/dist/esm/export/base.js.map +1 -1
  102. package/dist/esm/export/log.js +5 -4
  103. package/dist/esm/export/log.js.map +1 -1
  104. package/dist/esm/export/metric.js +5 -4
  105. package/dist/esm/export/metric.js.map +1 -1
  106. package/dist/esm/export/statsbeat/customerSDKStats.d.ts +133 -0
  107. package/dist/esm/export/statsbeat/customerSDKStats.d.ts.map +1 -0
  108. package/dist/esm/export/statsbeat/customerSDKStats.js +523 -0
  109. package/dist/esm/export/statsbeat/customerSDKStats.js.map +1 -0
  110. package/dist/esm/export/statsbeat/longIntervalStatsbeatMetrics.js +35 -11
  111. package/dist/esm/export/statsbeat/longIntervalStatsbeatMetrics.js.map +1 -1
  112. package/dist/esm/export/statsbeat/networkStatsbeatMetrics.js +52 -21
  113. package/dist/esm/export/statsbeat/networkStatsbeatMetrics.js.map +1 -1
  114. package/dist/esm/export/statsbeat/statsbeatExporter.d.ts +7 -0
  115. package/dist/esm/export/statsbeat/statsbeatExporter.d.ts.map +1 -1
  116. package/dist/esm/export/statsbeat/statsbeatExporter.js +25 -5
  117. package/dist/esm/export/statsbeat/statsbeatExporter.js.map +1 -1
  118. package/dist/esm/export/statsbeat/statsbeatMetrics.js +6 -8
  119. package/dist/esm/export/statsbeat/statsbeatMetrics.js.map +1 -1
  120. package/dist/esm/export/statsbeat/types.d.ts +77 -0
  121. package/dist/esm/export/statsbeat/types.d.ts.map +1 -1
  122. package/dist/esm/export/statsbeat/types.js +103 -0
  123. package/dist/esm/export/statsbeat/types.js.map +1 -1
  124. package/dist/esm/export/trace.js +6 -5
  125. package/dist/esm/export/trace.js.map +1 -1
  126. package/dist/esm/generated/applicationInsightsClient.js +9 -4
  127. package/dist/esm/generated/applicationInsightsClient.js.map +1 -1
  128. package/dist/esm/generated/models/mappers.js +145 -68
  129. package/dist/esm/generated/models/mappers.js.map +1 -1
  130. package/dist/esm/index.d.ts +2 -1
  131. package/dist/esm/index.d.ts.map +1 -1
  132. package/dist/esm/index.js +2 -1
  133. package/dist/esm/index.js.map +1 -1
  134. package/dist/esm/platform/nodejs/baseSender.d.ts +1 -0
  135. package/dist/esm/platform/nodejs/baseSender.d.ts.map +1 -1
  136. package/dist/esm/platform/nodejs/baseSender.js +91 -30
  137. package/dist/esm/platform/nodejs/baseSender.js.map +1 -1
  138. package/dist/esm/platform/nodejs/context/context.d.ts +0 -1
  139. package/dist/esm/platform/nodejs/context/context.d.ts.map +1 -1
  140. package/dist/esm/platform/nodejs/context/context.js +4 -8
  141. package/dist/esm/platform/nodejs/context/context.js.map +1 -1
  142. package/dist/esm/platform/nodejs/httpSender.js +11 -4
  143. package/dist/esm/platform/nodejs/httpSender.js.map +1 -1
  144. package/dist/esm/platform/nodejs/index.d.ts +1 -0
  145. package/dist/esm/platform/nodejs/index.d.ts.map +1 -1
  146. package/dist/esm/platform/nodejs/index.js +1 -0
  147. package/dist/esm/platform/nodejs/index.js.map +1 -1
  148. package/dist/esm/platform/nodejs/persist/fileAccessControl.js +7 -7
  149. package/dist/esm/platform/nodejs/persist/fileAccessControl.js.map +1 -1
  150. package/dist/esm/platform/nodejs/persist/fileSystemPersist.d.ts +9 -1
  151. package/dist/esm/platform/nodejs/persist/fileSystemPersist.d.ts.map +1 -1
  152. package/dist/esm/platform/nodejs/persist/fileSystemPersist.js +37 -16
  153. package/dist/esm/platform/nodejs/persist/fileSystemPersist.js.map +1 -1
  154. package/dist/esm/{sampling.d.ts → sampling/percentageSampler.d.ts} +2 -3
  155. package/dist/esm/sampling/percentageSampler.d.ts.map +1 -0
  156. package/dist/esm/{sampling.js → sampling/percentageSampler.js} +6 -39
  157. package/dist/esm/sampling/percentageSampler.js.map +1 -0
  158. package/dist/esm/sampling/rateLimitedSampler.d.ts +58 -0
  159. package/dist/esm/sampling/rateLimitedSampler.d.ts.map +1 -0
  160. package/dist/esm/sampling/rateLimitedSampler.js +114 -0
  161. package/dist/esm/sampling/rateLimitedSampler.js.map +1 -0
  162. package/dist/esm/sampling/samplingUtils.d.ts +17 -0
  163. package/dist/esm/sampling/samplingUtils.d.ts.map +1 -0
  164. package/dist/esm/sampling/samplingUtils.js +89 -0
  165. package/dist/esm/sampling/samplingUtils.js.map +1 -0
  166. package/dist/esm/types.d.ts +3 -1
  167. package/dist/esm/types.d.ts.map +1 -1
  168. package/dist/esm/types.js +4 -0
  169. package/dist/esm/types.js.map +1 -1
  170. package/dist/esm/utils/common.js +2 -3
  171. package/dist/esm/utils/common.js.map +1 -1
  172. package/dist/esm/utils/connectionStringParser.js +3 -3
  173. package/dist/esm/utils/connectionStringParser.js.map +1 -1
  174. package/dist/esm/utils/constants/applicationinsights.d.ts +2 -1
  175. package/dist/esm/utils/constants/applicationinsights.d.ts.map +1 -1
  176. package/dist/esm/utils/constants/applicationinsights.js +2 -1
  177. package/dist/esm/utils/constants/applicationinsights.js.map +1 -1
  178. package/dist/esm/utils/eventhub.js +5 -2
  179. package/dist/esm/utils/eventhub.js.map +1 -1
  180. package/dist/esm/utils/logUtils.d.ts.map +1 -1
  181. package/dist/esm/utils/logUtils.js +31 -12
  182. package/dist/esm/utils/logUtils.js.map +1 -1
  183. package/dist/esm/utils/metricUtils.d.ts.map +1 -1
  184. package/dist/esm/utils/metricUtils.js +6 -6
  185. package/dist/esm/utils/metricUtils.js.map +1 -1
  186. package/dist/esm/utils/spanUtils.d.ts.map +1 -1
  187. package/dist/esm/utils/spanUtils.js +32 -17
  188. package/dist/esm/utils/spanUtils.js.map +1 -1
  189. package/package.json +34 -35
  190. package/dist/commonjs/sampling.d.ts.map +0 -1
  191. package/dist/commonjs/sampling.js.map +0 -1
  192. package/dist/esm/sampling.d.ts.map +0 -1
  193. package/dist/esm/sampling.js.map +0 -1
@@ -0,0 +1,133 @@
1
+ import { StatsbeatMetrics } from "./statsbeatMetrics.js";
2
+ import type { StatsbeatOptions } from "./types.js";
3
+ import { DropCode, RetryCode, ExceptionType } from "./types.js";
4
+ import { TelemetryType } from "./types.js";
5
+ import type { TelemetryItem as Envelope } from "../../generated/index.js";
6
+ /**
7
+ * Class that handles customer-facing SDK Stats metrics
8
+ * These metrics are sent to the customer's breeze endpoint
9
+ *
10
+ * Implements a singleton pattern to ensure only one set of customer SDK Stats metrics
11
+ * is exported every 15 minutes, regardless of the number of exporters or senders.
12
+ */
13
+ export declare class CustomerSDKStatsMetrics extends StatsbeatMetrics {
14
+ private static _instance;
15
+ private statsCollectionInterval;
16
+ private customerSDKStatsMeter;
17
+ private customerSDKStatsMeterProvider;
18
+ private customerSDKStatsExporter;
19
+ private customerSDKStatsCounter;
20
+ private customerSDKStatsMetricReader;
21
+ private isInitialized;
22
+ private language;
23
+ private version;
24
+ private attach;
25
+ private itemSuccessCountGauge;
26
+ private itemDropCountGauge;
27
+ private itemRetryCountGauge;
28
+ private customerProperties;
29
+ private constructor();
30
+ /**
31
+ * Get singleton instance of CustomerSDKStatsMetrics
32
+ * @param options - Configuration options for customer SDK Stats metrics
33
+ * @returns The singleton instance
34
+ */
35
+ static getInstance(options: StatsbeatOptions): CustomerSDKStatsMetrics;
36
+ /**
37
+ * Shutdown the singleton instance
38
+ * Used for cleanup and complete shutdown
39
+ */
40
+ static shutdown(): Promise<void> | undefined;
41
+ /**
42
+ * Shuts down the customer SDK Stats metrics provider
43
+ * @returns Promise<void>
44
+ */
45
+ shutdown(): Promise<void>;
46
+ /**
47
+ * Initializes the customer SDK Stats metrics
48
+ * Sets up the resource provider and adds observable callbacks for each metric
49
+ * @returns Promise<void>
50
+ */
51
+ private initialize;
52
+ private itemSuccessCallback;
53
+ private itemDropCallback;
54
+ private itemRetryCallback;
55
+ /**
56
+ * Tracks succcessful items
57
+ * @param envelopes - Number of successful envelopes
58
+ * @param telemetry_type - The type of telemetry being tracked
59
+ */
60
+ countSuccessfulItems(envelopes: Envelope[]): void;
61
+ /**
62
+ * Tracks dropped items
63
+ * @param envelopes - Array of envelopes dropped
64
+ * @param dropCode - The drop code indicating the reason for drop
65
+ * @param exceptionMessage - Optional exception message when dropCode is CLIENT_EXCEPTION
66
+ * @param exceptionType - Optional explicit exception type override when dropCode is CLIENT_EXCEPTION
67
+ */
68
+ countDroppedItems(envelopes: Envelope[], dropCode: DropCode | number, exceptionMessage?: string, exceptionType?: ExceptionType): void;
69
+ /**
70
+ * Generates a low-cardinality, informative description for drop reasons
71
+ * @param dropCode - The drop code (enum value or status code number)
72
+ * @param exceptionMessage - Optional exception message for CLIENT_EXCEPTION
73
+ * @param exceptionType - Optional explicit exception type override for CLIENT_EXCEPTION
74
+ * @returns A descriptive reason string with low cardinality
75
+ */
76
+ private getDropReason;
77
+ /**
78
+ * Categorizes exception messages into well-known exception categories
79
+ * @param exceptionMessage - The exception message to categorize
80
+ * @returns A well-known exception category string
81
+ */
82
+ private categorizeExceptionMessage;
83
+ /**
84
+ * Categorizes HTTP status codes into informative descriptions
85
+ * @param statusCode - The HTTP status code
86
+ * @returns A descriptive category string
87
+ */
88
+ private categorizeStatusCode;
89
+ /**
90
+ * Tracks retried envelopes
91
+ * @param envelopes - Number of envelopes retried
92
+ * @param retryCode - The retry code indicating the reason for retry
93
+ * @param exceptionMessage - Optional exception message when retryCode is CLIENT_EXCEPTION
94
+ * @param exceptionType - Optional explicit exception type override when retryCode is CLIENT_EXCEPTION
95
+ */
96
+ countRetryItems(envelopes: Envelope[], retryCode: RetryCode | number, exceptionMessage?: string, exceptionType?: ExceptionType): void;
97
+ /**
98
+ * Generates a low-cardinality, informative description for retry reasons
99
+ * @param retryCode - The retry code (enum value or status code number)
100
+ * @param exceptionMessage - Optional exception message for CLIENT_EXCEPTION
101
+ * @param exceptionType - Optional explicit exception type override for CLIENT_EXCEPTION
102
+ * @returns A descriptive reason string with low cardinality
103
+ */
104
+ private getRetryReason;
105
+ /**
106
+ * Check if a metric name corresponds to a performance counter
107
+ * @param metricName - The name of the metric to check
108
+ * @returns true if the metric name is a performance counter, false otherwise
109
+ */
110
+ private isPerformanceCounterMetric;
111
+ /**
112
+ * Extract telemetry type from an envelope based on its baseType
113
+ * @param envelope - The envelope to extract telemetry type from
114
+ * @returns The corresponding telemetry type
115
+ */
116
+ getTelemetryTypeFromEnvelope(envelope: Envelope): TelemetryType;
117
+ /**
118
+ * Extract telemetry success value from an envelope for REQUEST and DEPENDENCY telemetry types
119
+ * @param envelope - The envelope to extract success value from
120
+ * @returns The success value if available, undefined otherwise
121
+ */
122
+ getTelemetrySuccessFromEnvelope(envelope: Envelope): boolean | undefined;
123
+ /**
124
+ * Checks if the given error is a timeout-related error
125
+ * @param error - The error to check
126
+ * @returns true if the error is timeout-related, false otherwise
127
+ */
128
+ isTimeoutError(error: {
129
+ code?: string;
130
+ message?: string;
131
+ }): boolean;
132
+ }
133
+ //# sourceMappingURL=customerSDKStats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customerSDKStats.d.ts","sourceRoot":"","sources":["../../../../src/export/statsbeat/customerSDKStats.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAA8B,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAEL,QAAQ,EACR,SAAS,EACT,aAAa,EAGd,MAAM,YAAY,CAAC;AACpB,OAAO,EAA6C,aAAa,EAAE,MAAM,YAAY,CAAC;AAKtF,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAE1E;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,gBAAgB;IAC3D,OAAO,CAAC,MAAM,CAAC,SAAS,CAAsC;IAE9D,OAAO,CAAC,uBAAuB,CAAkB;IACjD,OAAO,CAAC,qBAAqB,CAAQ;IACrC,OAAO,CAAC,6BAA6B,CAAgB;IACrD,OAAO,CAAC,wBAAwB,CAAgC;IAChE,OAAO,CAAC,uBAAuB,CAAmB;IAClD,OAAO,CAAC,4BAA4B,CAAgC;IACpE,OAAO,CAAC,aAAa,CAAkB;IAGvC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAA2B;IAGzC,OAAO,CAAC,qBAAqB,CAAkB;IAC/C,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,mBAAmB,CAAkB;IAG7C,OAAO,CAAC,kBAAkB,CAA6B;IAEvD,OAAO;IAmDP;;;;OAIG;WACW,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,uBAAuB;IAO7E;;;OAGG;WACW,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS;IASnD;;;OAGG;IACI,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;OAIG;YACW,UAAU;IAkBxB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,gBAAgB;IAiDxB,OAAO,CAAC,iBAAiB;IAuCzB;;;;OAIG;IACI,oBAAoB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI;IAYxD;;;;;;OAMG;IACI,iBAAiB,CACtB,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAC3B,gBAAgB,CAAC,EAAE,MAAM,EACzB,aAAa,CAAC,EAAE,aAAa,GAC5B,IAAI;IA4CP;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAoCrB;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IA2BlC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAuC5B;;;;;;OAMG;IACI,eAAe,CACpB,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,EAAE,SAAS,GAAG,MAAM,EAC7B,gBAAgB,CAAC,EAAE,MAAM,EACzB,aAAa,CAAC,EAAE,aAAa,GAC5B,IAAI;IA6BP;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAgCtB;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAMlC;;;;OAIG;IACI,4BAA4B,CAAC,QAAQ,EAAE,QAAQ,GAAG,aAAa;IAqCtE;;;;OAIG;IACI,+BAA+B,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS;IAiB/E;;;;OAIG;IACI,cAAc,CAAC,KAAK,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO;CAsB3E"}
@@ -0,0 +1,523 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { diag } from "@opentelemetry/api";
4
+ import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
5
+ import * as ai from "../../utils/constants/applicationinsights.js";
6
+ import { StatsbeatMetrics } from "./statsbeatMetrics.js";
7
+ import { CustomerSDKStats, DropCode, RetryCode, ExceptionType, DropReason, RetryReason, } from "./types.js";
8
+ import { CustomSDKStatsCounter, STATSBEAT_LANGUAGE, TelemetryType } from "./types.js";
9
+ import { getAttachType } from "../../utils/metricUtils.js";
10
+ import { AzureMonitorStatsbeatExporter } from "./statsbeatExporter.js";
11
+ import { BreezePerformanceCounterNames } from "../../types.js";
12
+ /**
13
+ * Class that handles customer-facing SDK Stats metrics
14
+ * These metrics are sent to the customer's breeze endpoint
15
+ *
16
+ * Implements a singleton pattern to ensure only one set of customer SDK Stats metrics
17
+ * is exported every 15 minutes, regardless of the number of exporters or senders.
18
+ */
19
+ export class CustomerSDKStatsMetrics extends StatsbeatMetrics {
20
+ static _instance;
21
+ statsCollectionInterval = 900000; // 15 minutes
22
+ customerSDKStatsMeter;
23
+ customerSDKStatsMeterProvider;
24
+ customerSDKStatsExporter;
25
+ customerSDKStatsCounter;
26
+ customerSDKStatsMetricReader;
27
+ isInitialized = false;
28
+ // Custom dimensions
29
+ language;
30
+ version;
31
+ attach = getAttachType();
32
+ // Observable Gauges
33
+ itemSuccessCountGauge;
34
+ itemDropCountGauge;
35
+ itemRetryCountGauge;
36
+ // Customer SDK Stats properties
37
+ customerProperties;
38
+ constructor(options) {
39
+ super();
40
+ const exporterConfig = {
41
+ connectionString: `InstrumentationKey=${options.instrumentationKey};IngestionEndpoint=${options.endpointUrl}`,
42
+ };
43
+ this.customerSDKStatsExporter = new AzureMonitorStatsbeatExporter(exporterConfig);
44
+ // Exports Customer SDK Stats every 15 minutes
45
+ const customerMetricReaderOptions = {
46
+ exporter: this.customerSDKStatsExporter,
47
+ exportIntervalMillis: options.networkCollectionInterval || this.statsCollectionInterval,
48
+ };
49
+ this.customerSDKStatsMetricReader = new PeriodicExportingMetricReader(customerMetricReaderOptions);
50
+ this.customerSDKStatsMeterProvider = new MeterProvider({
51
+ readers: [this.customerSDKStatsMetricReader],
52
+ });
53
+ this.customerSDKStatsMeter = this.customerSDKStatsMeterProvider.getMeter("Azure Monitor Customer SDK Stats");
54
+ this.language = STATSBEAT_LANGUAGE;
55
+ this.version = ai.packageVersion;
56
+ this.itemSuccessCountGauge = this.customerSDKStatsMeter.createObservableGauge(CustomSDKStatsCounter.ITEM_SUCCESS_COUNT);
57
+ this.itemDropCountGauge = this.customerSDKStatsMeter.createObservableGauge(CustomSDKStatsCounter.ITEM_DROP_COUNT);
58
+ this.itemRetryCountGauge = this.customerSDKStatsMeter.createObservableGauge(CustomSDKStatsCounter.ITEM_RETRY_COUNT);
59
+ if (!this.isInitialized) {
60
+ this.initialize();
61
+ }
62
+ this.isInitialized = true;
63
+ // Initialize the single customer SDK Stats counter
64
+ this.customerSDKStatsCounter = new CustomerSDKStats();
65
+ this.customerProperties = {
66
+ language: this.language,
67
+ version: this.version,
68
+ computeType: this.attach,
69
+ };
70
+ }
71
+ /**
72
+ * Get singleton instance of CustomerSDKStatsMetrics
73
+ * @param options - Configuration options for customer SDK Stats metrics
74
+ * @returns The singleton instance
75
+ */
76
+ static getInstance(options) {
77
+ if (!CustomerSDKStatsMetrics._instance) {
78
+ CustomerSDKStatsMetrics._instance = new CustomerSDKStatsMetrics(options);
79
+ }
80
+ return CustomerSDKStatsMetrics._instance;
81
+ }
82
+ /**
83
+ * Shutdown the singleton instance
84
+ * Used for cleanup and complete shutdown
85
+ */
86
+ static shutdown() {
87
+ if (CustomerSDKStatsMetrics._instance) {
88
+ const shutdownPromise = CustomerSDKStatsMetrics._instance.shutdown();
89
+ CustomerSDKStatsMetrics._instance = undefined;
90
+ return shutdownPromise;
91
+ }
92
+ return undefined;
93
+ }
94
+ /**
95
+ * Shuts down the customer SDK Stats metrics provider
96
+ * @returns Promise<void>
97
+ */
98
+ shutdown() {
99
+ return this.customerSDKStatsMeterProvider.shutdown();
100
+ }
101
+ /**
102
+ * Initializes the customer SDK Stats metrics
103
+ * Sets up the resource provider and adds observable callbacks for each metric
104
+ * @returns Promise<void>
105
+ */
106
+ async initialize() {
107
+ try {
108
+ await super.getResourceProvider();
109
+ this.customerSDKStatsMeter.addBatchObservableCallback(this.itemSuccessCallback.bind(this), [
110
+ this.itemSuccessCountGauge,
111
+ ]);
112
+ this.customerSDKStatsMeter.addBatchObservableCallback(this.itemDropCallback.bind(this), [
113
+ this.itemDropCountGauge,
114
+ ]);
115
+ this.customerSDKStatsMeter.addBatchObservableCallback(this.itemRetryCallback.bind(this), [
116
+ this.itemRetryCountGauge,
117
+ ]);
118
+ }
119
+ catch (error) {
120
+ diag.debug("Call to get the resource provider failed for customer SDK Stats metrics.");
121
+ }
122
+ }
123
+ // Observable gauge callbacks
124
+ itemSuccessCallback(observableResult) {
125
+ const counter = this.customerSDKStatsCounter;
126
+ const attributes = { ...this.customerProperties, telemetry_type: TelemetryType.UNKNOWN };
127
+ // For each { telemetry_type -> count } mapping, call observe, passing the count and attributes that include the telemetry_type
128
+ for (const [telemetry_type, count] of counter.totalItemSuccessCount.entries()) {
129
+ // Only send metrics if count is greater than zero
130
+ if (count > 0) {
131
+ attributes.telemetry_type = telemetry_type;
132
+ observableResult.observe(this.itemSuccessCountGauge, count, {
133
+ ...attributes,
134
+ });
135
+ counter.totalItemSuccessCount.set(telemetry_type, 0);
136
+ }
137
+ }
138
+ }
139
+ itemDropCallback(observableResult) {
140
+ const counter = this.customerSDKStatsCounter;
141
+ const baseAttributes = {
142
+ ...this.customerProperties,
143
+ "drop.code": DropCode.UNKNOWN,
144
+ telemetry_type: TelemetryType.UNKNOWN,
145
+ };
146
+ // Iterate through the nested Map structure: telemetry_type -> drop.code -> reason -> telemetry_success -> count
147
+ for (const [telemetryType, dropCodeMap] of counter.totalItemDropCount.entries()) {
148
+ for (const [dropCode, reasonMap] of dropCodeMap.entries()) {
149
+ for (const [reason, successMap] of reasonMap.entries()) {
150
+ for (const [success, count] of successMap.entries()) {
151
+ const attributes = { ...baseAttributes };
152
+ attributes.telemetry_type = telemetryType;
153
+ attributes["drop.code"] = dropCode;
154
+ // Include drop.reason for all cases
155
+ if (reason) {
156
+ attributes["drop.reason"] = reason;
157
+ }
158
+ // Include telemetry_success only for request/dependency telemetry when success is not null
159
+ if ((telemetryType === TelemetryType.REQUEST ||
160
+ telemetryType === TelemetryType.DEPENDENCY) &&
161
+ success !== null) {
162
+ attributes["telemetry_success"] = success;
163
+ }
164
+ // Only send metrics if count is greater than zero
165
+ if (count > 0) {
166
+ observableResult.observe(this.itemDropCountGauge, count, {
167
+ ...attributes,
168
+ });
169
+ }
170
+ // Reset the count to 0
171
+ successMap.set(success, 0);
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+ itemRetryCallback(observableResult) {
178
+ const counter = this.customerSDKStatsCounter;
179
+ const baseAttributes = {
180
+ ...this.customerProperties,
181
+ "retry.code": RetryCode.UNKNOWN,
182
+ telemetry_type: TelemetryType.UNKNOWN,
183
+ };
184
+ // Iterate through the nested Map structure: telemetry_type -> retry.code -> reason -> count
185
+ for (const [telemetryType, retryCodeMap] of counter.totalItemRetryCount.entries()) {
186
+ for (const [retryCode, reasonMap] of retryCodeMap.entries()) {
187
+ for (const [reason, count] of reasonMap.entries()) {
188
+ const attributes = { ...baseAttributes };
189
+ attributes.telemetry_type = telemetryType;
190
+ attributes["retry.code"] = retryCode;
191
+ // Include retry.reason for all cases
192
+ if (reason) {
193
+ attributes["retry.reason"] = reason;
194
+ }
195
+ // Only send metrics if count is greater than zero
196
+ if (count > 0) {
197
+ observableResult.observe(this.itemRetryCountGauge, count, {
198
+ ...attributes,
199
+ });
200
+ }
201
+ // Reset the count to 0
202
+ reasonMap.set(reason, 0);
203
+ }
204
+ }
205
+ }
206
+ }
207
+ // Public methods to track metrics
208
+ /**
209
+ * Tracks succcessful items
210
+ * @param envelopes - Number of successful envelopes
211
+ * @param telemetry_type - The type of telemetry being tracked
212
+ */
213
+ countSuccessfulItems(envelopes) {
214
+ const counter = this.customerSDKStatsCounter;
215
+ let telemetry_type;
216
+ // Get the current count for this telemetry type, or 0 if it doesn't exist
217
+ for (const envelope of envelopes) {
218
+ telemetry_type = this.getTelemetryTypeFromEnvelope(envelope);
219
+ const currentCount = counter.totalItemSuccessCount.get(telemetry_type) || 0;
220
+ counter.totalItemSuccessCount.set(telemetry_type, currentCount + 1);
221
+ }
222
+ }
223
+ /**
224
+ * Tracks dropped items
225
+ * @param envelopes - Array of envelopes dropped
226
+ * @param dropCode - The drop code indicating the reason for drop
227
+ * @param exceptionMessage - Optional exception message when dropCode is CLIENT_EXCEPTION
228
+ * @param exceptionType - Optional explicit exception type override when dropCode is CLIENT_EXCEPTION
229
+ */
230
+ countDroppedItems(envelopes, dropCode, exceptionMessage, exceptionType) {
231
+ const counter = this.customerSDKStatsCounter;
232
+ let telemetry_type;
233
+ for (const envelope of envelopes) {
234
+ telemetry_type = this.getTelemetryTypeFromEnvelope(envelope);
235
+ let dropCodeMap = counter.totalItemDropCount.get(telemetry_type);
236
+ if (!dropCodeMap) {
237
+ dropCodeMap = new Map();
238
+ counter.totalItemDropCount.set(telemetry_type, dropCodeMap);
239
+ }
240
+ // Get or create the reason map for this dropCode
241
+ let reasonMap = dropCodeMap.get(dropCode);
242
+ if (!reasonMap) {
243
+ reasonMap = new Map();
244
+ dropCodeMap.set(dropCode, reasonMap);
245
+ }
246
+ // Generate a low-cardinality, informative reason description
247
+ const reason = this.getDropReason(dropCode, exceptionMessage, exceptionType);
248
+ // Get or create the success map for this reason
249
+ let successMap = reasonMap.get(reason);
250
+ if (!successMap) {
251
+ successMap = new Map();
252
+ reasonMap.set(reason, successMap);
253
+ }
254
+ // For non-request/dependency telemetry or when success is not provided, use null as the success key
255
+ const individualTelemetrySuccess = this.getTelemetrySuccessFromEnvelope(envelope);
256
+ const successKey = (telemetry_type === TelemetryType.REQUEST || telemetry_type === TelemetryType.DEPENDENCY) &&
257
+ individualTelemetrySuccess !== undefined
258
+ ? individualTelemetrySuccess
259
+ : null;
260
+ // Update the count for this reason and success combination
261
+ const currentCount = successMap.get(successKey) || 0;
262
+ successMap.set(successKey, currentCount + 1);
263
+ }
264
+ }
265
+ /**
266
+ * Generates a low-cardinality, informative description for drop reasons
267
+ * @param dropCode - The drop code (enum value or status code number)
268
+ * @param exceptionMessage - Optional exception message for CLIENT_EXCEPTION
269
+ * @param exceptionType - Optional explicit exception type override for CLIENT_EXCEPTION
270
+ * @returns A descriptive reason string with low cardinality
271
+ */
272
+ getDropReason(dropCode, exceptionMessage, exceptionType) {
273
+ if (dropCode === DropCode.CLIENT_EXCEPTION) {
274
+ // If an explicit exception type is provided, use it
275
+ if (exceptionType) {
276
+ return exceptionType;
277
+ }
278
+ // For client exceptions, derive a well-known exception category from the exception message
279
+ if (exceptionMessage) {
280
+ return this.categorizeExceptionMessage(exceptionMessage);
281
+ }
282
+ return ExceptionType.CLIENT_EXCEPTION; // Default to "Client exception" if no message provided
283
+ }
284
+ // Handle status code drop codes (numeric values)
285
+ if (typeof dropCode === "number") {
286
+ return this.categorizeStatusCode(dropCode);
287
+ }
288
+ // Handle other enum drop codes
289
+ switch (dropCode) {
290
+ case DropCode.CLIENT_READONLY:
291
+ return DropReason.CLIENT_READONLY;
292
+ case DropCode.CLIENT_PERSISTENCE_CAPACITY:
293
+ return DropReason.CLIENT_PERSISTENCE_CAPACITY;
294
+ case DropCode.CLIENT_STORAGE_DISABLED:
295
+ return DropReason.CLIENT_STORAGE_DISABLED;
296
+ case DropCode.UNKNOWN:
297
+ default:
298
+ return DropReason.UNKNOWN;
299
+ }
300
+ }
301
+ /**
302
+ * Categorizes exception messages into well-known exception categories
303
+ * @param exceptionMessage - The exception message to categorize
304
+ * @returns A well-known exception category string
305
+ */
306
+ categorizeExceptionMessage(exceptionMessage) {
307
+ const message = exceptionMessage.toLowerCase();
308
+ if (message.includes("timeout") || message.includes("timed out")) {
309
+ return ExceptionType.TIMEOUT_EXCEPTION;
310
+ }
311
+ if (message.includes("network") ||
312
+ message.includes("connection") ||
313
+ message.includes("dns") ||
314
+ message.includes("socket")) {
315
+ return ExceptionType.NETWORK_EXCEPTION;
316
+ }
317
+ if (message.includes("disk") ||
318
+ message.includes("storage") ||
319
+ message.includes("file") ||
320
+ message.includes("persist")) {
321
+ return ExceptionType.STORAGE_EXCEPTION;
322
+ }
323
+ // Default to Client exception for any other cases
324
+ return ExceptionType.CLIENT_EXCEPTION;
325
+ }
326
+ /**
327
+ * Categorizes HTTP status codes into informative descriptions
328
+ * @param statusCode - The HTTP status code
329
+ * @returns A descriptive category string
330
+ */
331
+ categorizeStatusCode(statusCode) {
332
+ if (statusCode >= 400 && statusCode < 500) {
333
+ switch (statusCode) {
334
+ case 400:
335
+ return "Bad request";
336
+ case 401:
337
+ return "Unauthorized";
338
+ case 403:
339
+ return "Forbidden";
340
+ case 404:
341
+ return "Not found";
342
+ case 408:
343
+ return "Request timeout";
344
+ case 413:
345
+ return "Payload too large";
346
+ case 429:
347
+ return "Too many requests";
348
+ default:
349
+ return "Client error 4xx";
350
+ }
351
+ }
352
+ if (statusCode >= 500 && statusCode < 600) {
353
+ switch (statusCode) {
354
+ case 500:
355
+ return "Internal server error";
356
+ case 502:
357
+ return "Bad gateway";
358
+ case 503:
359
+ return "Service unavailable";
360
+ case 504:
361
+ return "Gateway timeout";
362
+ default:
363
+ return "Server error 5xx";
364
+ }
365
+ }
366
+ return `status_${statusCode}`;
367
+ }
368
+ /**
369
+ * Tracks retried envelopes
370
+ * @param envelopes - Number of envelopes retried
371
+ * @param retryCode - The retry code indicating the reason for retry
372
+ * @param exceptionMessage - Optional exception message when retryCode is CLIENT_EXCEPTION
373
+ * @param exceptionType - Optional explicit exception type override when retryCode is CLIENT_EXCEPTION
374
+ */
375
+ countRetryItems(envelopes, retryCode, exceptionMessage, exceptionType) {
376
+ const counter = this.customerSDKStatsCounter;
377
+ let telemetry_type;
378
+ for (const envelope of envelopes) {
379
+ telemetry_type = this.getTelemetryTypeFromEnvelope(envelope);
380
+ // Get or create the retryCode map for this telemetry_type
381
+ let retryCodeMap = counter.totalItemRetryCount.get(telemetry_type);
382
+ if (!retryCodeMap) {
383
+ retryCodeMap = new Map();
384
+ counter.totalItemRetryCount.set(telemetry_type, retryCodeMap);
385
+ }
386
+ // Get or create the reason map for this retryCode
387
+ let reasonMap = retryCodeMap.get(retryCode);
388
+ if (!reasonMap) {
389
+ reasonMap = new Map();
390
+ retryCodeMap.set(retryCode, reasonMap);
391
+ }
392
+ // Generate a low-cardinality, informative reason description
393
+ const reason = this.getRetryReason(retryCode, exceptionMessage, exceptionType);
394
+ // Update the count for this reason
395
+ const currentCount = reasonMap.get(reason) || 0;
396
+ reasonMap.set(reason, currentCount + 1);
397
+ }
398
+ }
399
+ /**
400
+ * Generates a low-cardinality, informative description for retry reasons
401
+ * @param retryCode - The retry code (enum value or status code number)
402
+ * @param exceptionMessage - Optional exception message for CLIENT_EXCEPTION
403
+ * @param exceptionType - Optional explicit exception type override for CLIENT_EXCEPTION
404
+ * @returns A descriptive reason string with low cardinality
405
+ */
406
+ getRetryReason(retryCode, exceptionMessage, exceptionType) {
407
+ if (retryCode === RetryCode.CLIENT_EXCEPTION) {
408
+ // If an explicit exception type is provided, use it
409
+ if (exceptionType) {
410
+ return exceptionType;
411
+ }
412
+ // For client exceptions, derive a low-cardinality reason from the exception message
413
+ if (exceptionMessage) {
414
+ return this.categorizeExceptionMessage(exceptionMessage);
415
+ }
416
+ return ExceptionType.CLIENT_EXCEPTION;
417
+ }
418
+ // Handle status code retry codes (numeric values)
419
+ if (typeof retryCode === "number") {
420
+ return this.categorizeStatusCode(retryCode);
421
+ }
422
+ // Handle other enum retry codes
423
+ switch (retryCode) {
424
+ case RetryCode.CLIENT_TIMEOUT:
425
+ return RetryReason.CLIENT_TIMEOUT;
426
+ case RetryCode.UNKNOWN:
427
+ default:
428
+ return RetryReason.UNKNOWN;
429
+ }
430
+ }
431
+ /**
432
+ * Check if a metric name corresponds to a performance counter
433
+ * @param metricName - The name of the metric to check
434
+ * @returns true if the metric name is a performance counter, false otherwise
435
+ */
436
+ isPerformanceCounterMetric(metricName) {
437
+ return Object.values(BreezePerformanceCounterNames).includes(metricName);
438
+ }
439
+ /**
440
+ * Extract telemetry type from an envelope based on its baseType
441
+ * @param envelope - The envelope to extract telemetry type from
442
+ * @returns The corresponding telemetry type
443
+ */
444
+ getTelemetryTypeFromEnvelope(envelope) {
445
+ if (envelope.data && envelope.data.baseType) {
446
+ switch (envelope.data.baseType) {
447
+ case "MessageData":
448
+ return TelemetryType.TRACE;
449
+ case "AvailabilityData":
450
+ return TelemetryType.AVAILABILITY;
451
+ case "TelemetryEventData":
452
+ return TelemetryType.CUSTOM_EVENT;
453
+ case "TelemetryExceptionData":
454
+ return TelemetryType.EXCEPTION;
455
+ case "PageViewData":
456
+ return TelemetryType.PAGE_VIEW;
457
+ case "RemoteDependencyData":
458
+ return TelemetryType.DEPENDENCY;
459
+ case "RequestData":
460
+ return TelemetryType.REQUEST;
461
+ case "MetricData": {
462
+ const metricsData = envelope.data.baseData;
463
+ if (metricsData && metricsData.metrics && metricsData.metrics.length > 0) {
464
+ // Check if any of the metrics are performance counters
465
+ const hasPerformanceCounter = metricsData.metrics.some((metric) => this.isPerformanceCounterMetric(metric.name));
466
+ return hasPerformanceCounter
467
+ ? TelemetryType.PERFORMANCE_COUNTER
468
+ : TelemetryType.CUSTOM_METRIC;
469
+ }
470
+ return TelemetryType.CUSTOM_METRIC;
471
+ }
472
+ default:
473
+ return TelemetryType.UNKNOWN;
474
+ }
475
+ }
476
+ return TelemetryType.UNKNOWN;
477
+ }
478
+ /**
479
+ * Extract telemetry success value from an envelope for REQUEST and DEPENDENCY telemetry types
480
+ * @param envelope - The envelope to extract success value from
481
+ * @returns The success value if available, undefined otherwise
482
+ */
483
+ getTelemetrySuccessFromEnvelope(envelope) {
484
+ if (!envelope.data || !envelope.data.baseData) {
485
+ return undefined;
486
+ }
487
+ const baseType = envelope.data.baseType;
488
+ if (baseType === "RequestData") {
489
+ const requestData = envelope.data.baseData;
490
+ return requestData.success;
491
+ }
492
+ else if (baseType === "RemoteDependencyData") {
493
+ const dependencyData = envelope.data.baseData;
494
+ return dependencyData.success;
495
+ }
496
+ return undefined;
497
+ }
498
+ /**
499
+ * Checks if the given error is a timeout-related error
500
+ * @param error - The error to check
501
+ * @returns true if the error is timeout-related, false otherwise
502
+ */
503
+ isTimeoutError(error) {
504
+ // Check for various timeout error codes that indicate client timeouts
505
+ const timeoutErrorCodes = [
506
+ "ETIMEDOUT", // Connection timed out
507
+ "ESOCKETTIMEDOUT", // Socket timeout
508
+ "ECONNRESET", // Connection reset (often due to timeout)
509
+ "ENOTFOUND", // DNS lookup failed/timeout
510
+ ];
511
+ if (error && error.code && timeoutErrorCodes.includes(error.code)) {
512
+ return true;
513
+ }
514
+ // Also check if the error message contains timeout-related keywords
515
+ if (error && error.message) {
516
+ const timeoutKeywords = ["timeout", "timed out", "connection reset"];
517
+ const errorMessage = error.message.toLowerCase();
518
+ return timeoutKeywords.some((keyword) => errorMessage.includes(keyword));
519
+ }
520
+ return false;
521
+ }
522
+ }
523
+ //# sourceMappingURL=customerSDKStats.js.map