@mhubcloud/tms_core 3.8.0-beta.0 → 3.8.0-beta.10

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 (2) hide show
  1. package/dist/index.js +193 -91
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -32,6 +32,8 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  DefaultPublisher: () => defaultPublisher,
34
34
  broker: () => broker_exports,
35
+ createAppInsightsClient: () => createAppInsightsClient,
36
+ createRedisClient: () => createRedisClient,
35
37
  publisher: () => publisher,
36
38
  testUtils: () => testUtils_exports,
37
39
  utils: () => utils_exports
@@ -52,8 +54,8 @@ var import_service_bus = require("@azure/service-bus");
52
54
  // src/utils/utils.ts
53
55
  var utils_exports = {};
54
56
  __export(utils_exports, {
57
+ DestinationError: () => DestinationError,
55
58
  EventPublisherBase: () => EventPublisherBase,
56
- aiClient: () => aiClient,
57
59
  encodeEmail: () => encodeEmail,
58
60
  extractAdCode: () => extractAdCode,
59
61
  extractClickId: () => extractClickId,
@@ -66,35 +68,99 @@ __export(utils_exports, {
66
68
  logEvent: () => logEvent,
67
69
  logException: () => logException,
68
70
  logMessage: () => logMessage,
71
+ logMetric: () => logMetric,
69
72
  logMilestone: () => logMilestone,
70
73
  prepareTestRequestHeaders: () => prepareTestRequestHeaders,
71
74
  removeUndefined: () => removeUndefined
72
75
  });
73
76
  var crypto = __toESM(require("crypto"));
77
+
78
+ // src/utils/appInsightsClient.ts
74
79
  var appInsights = __toESM(require("applicationinsights"));
80
+ var import_applicationinsights = require("applicationinsights");
81
+ var defaultClient2;
82
+ var settings = {
83
+ collectDependencies: false,
84
+ collectExternalLoggers: true,
85
+ collectConsole: false,
86
+ sendLiveMetrics: false,
87
+ collectRequests: false,
88
+ collectPerformance: false,
89
+ collectExtendedMetrics: false,
90
+ useDiskRetryCaching: false
91
+ };
92
+ function configureIndependentClient(client) {
93
+ client.config.enableAutoCollectExceptions ??= true;
94
+ client.config.enableAutoCollectPreAggregatedMetrics ??= true;
95
+ client.config.enableAutoCollectHeartbeat ??= true;
96
+ client.config.enableAutoDependencyCorrelation ??= true;
97
+ client.config.enableWebInstrumentation ??= false;
98
+ client.config.enableAutoCollectIncomingRequestAzureFunctions ??= false;
99
+ client.config.enableAutoCollectDependencies = settings.collectDependencies;
100
+ client.config.enableAutoCollectExternalLoggers = settings.collectExternalLoggers;
101
+ client.config.enableAutoCollectConsole = settings.collectConsole;
102
+ client.config.enableSendLiveMetrics = settings.sendLiveMetrics;
103
+ client.config.enableAutoCollectRequests = settings.collectRequests;
104
+ client.config.enableAutoCollectPerformance = settings.collectPerformance;
105
+ client.config.enableAutoCollectExtendedMetrics = settings.collectExtendedMetrics;
106
+ client.config.enableUseDiskRetryCaching = settings.useDiskRetryCaching;
107
+ client.channel.setUseDiskRetryCaching(settings.useDiskRetryCaching);
108
+ return client;
109
+ }
110
+ function createAppInsightsClient(connectionString) {
111
+ if (connectionString !== void 0) {
112
+ if (!connectionString.trim()) {
113
+ throw new Error("Application Insights connection string is empty");
114
+ }
115
+ return configureIndependentClient(new import_applicationinsights.TelemetryClient(connectionString));
116
+ }
117
+ if (defaultClient2 !== void 0) {
118
+ return defaultClient2;
119
+ }
120
+ if (!process.env.APPLICATIONINSIGHTS_CONNECTION_STRING) {
121
+ defaultClient2 = null;
122
+ return defaultClient2;
123
+ }
124
+ appInsights.setup().setAutoCollectDependencies(settings.collectDependencies).setAutoCollectConsole(
125
+ settings.collectExternalLoggers,
126
+ settings.collectConsole
127
+ ).setSendLiveMetrics(settings.sendLiveMetrics).setAutoCollectRequests(settings.collectRequests).setAutoCollectPerformance(
128
+ settings.collectPerformance,
129
+ settings.collectExtendedMetrics
130
+ ).setUseDiskRetryCaching(settings.useDiskRetryCaching).start();
131
+ defaultClient2 = appInsights.defaultClient;
132
+ return defaultClient2;
133
+ }
75
134
 
76
135
  // src/utils/redisClient.ts
77
136
  var import_redis = require("redis");
78
- var client;
79
- var port = process.env["RedisPort"] ?? "6380";
80
- async function getRedisClient() {
81
- if (!client) {
137
+ async function createRedisClient(url, password) {
138
+ let client;
139
+ if (!url || !password) {
140
+ if (process.env.RedisUrl && process.env.RedisPassword) {
141
+ client = (0, import_redis.createClient)({
142
+ url: `rediss://${process.env.RedisUrl}`,
143
+ password: process.env.RedisPassword,
144
+ socket: { tls: true }
145
+ });
146
+ } else {
147
+ throw new Error(
148
+ "Redis url and password are missing with no fallback available"
149
+ );
150
+ }
151
+ } else {
82
152
  client = (0, import_redis.createClient)({
83
- url: `rediss://${process.env["RedisUrl"]}:${port}`,
84
- password: process.env["RedisPassword"],
153
+ url,
154
+ password,
85
155
  socket: { tls: true }
86
156
  });
87
- await client.connect();
88
157
  }
158
+ await client.connect();
89
159
  return client;
90
160
  }
91
161
 
92
162
  // src/utils/utils.ts
93
- var aiClient = null;
94
- if (process.env.APPLICATIONINSIGHTS_CONNECTION_STRING) {
95
- appInsights.setup().setAutoCollectDependencies(false).setAutoCollectConsole(true, false).setSendLiveMetrics(false).setAutoCollectRequests(false).setAutoCollectPerformance(false, false).setUseDiskRetryCaching(false).start();
96
- aiClient = appInsights.defaultClient;
97
- }
163
+ var aiClient = createAppInsightsClient();
98
164
  var EventPublisherBase = class {
99
165
  config;
100
166
  constructor(config) {
@@ -117,32 +183,66 @@ var EventPublisherBase = class {
117
183
  }
118
184
  };
119
185
  async function logRedisEvent(key) {
120
- const redis = await getRedisClient();
121
- if (!redis) return;
122
- await redis.hIncrBy(key, "count", 1);
123
- await redis.expire(key, 660);
186
+ if (!process.env.RedisUrl || !process.env.RedisPassword) {
187
+ return;
188
+ }
189
+ const redis = await createRedisClient();
190
+ await redis.multi().hIncrBy(key, "count", 1).expire(key, 660).exec();
124
191
  }
125
- function logAggregatedMetric(prefix, name, dimensions) {
192
+ var DestinationError = class _DestinationError extends Error {
193
+ metricType;
194
+ constructor(message, metricType) {
195
+ super(message);
196
+ this.name = "DestinationError";
197
+ this.metricType = metricType;
198
+ }
199
+ static fromResponse(message, status) {
200
+ const metricType = status === 408 || status === 429 || status >= 500 ? "PlatformError" : "RequestError";
201
+ return new _DestinationError(message, metricType);
202
+ }
203
+ static fromNetworkFailure(error) {
204
+ const message = error instanceof Error ? error.message : String(error);
205
+ return new _DestinationError(message, "PlatformError");
206
+ }
207
+ };
208
+ function logAggregatedMetric({ prefix, name, dimensions }, client) {
126
209
  const windowStart = Math.floor(Date.now() / 6e4) * 6e4;
127
- const key = dimensions ? `${prefix}:${windowStart}:${dimensions}:${name}` : `${prefix}:${windowStart}:${name}`;
128
- logRedisEvent(key);
210
+ let key = "tms:";
211
+ key += dimensions ? `${prefix}:${windowStart}:${dimensions}:${name}` : `${prefix}:${windowStart}:${name}`;
212
+ void logRedisEvent(key).catch((error) => {
213
+ const message = error instanceof Error ? error.message : String(error);
214
+ logMessage(3, `Metric log error: ${message}`, void 0, client);
215
+ });
216
+ }
217
+ function logMetric(name, value, properties, client) {
218
+ (client ?? aiClient)?.trackMetric({
219
+ name,
220
+ value,
221
+ count: value,
222
+ properties
223
+ });
129
224
  }
130
- function logMessage(level, message, properties) {
225
+ function logMessage(level, message, properties, client) {
131
226
  console.log(message);
132
- aiClient?.trackTrace({
227
+ (client ?? aiClient)?.trackTrace({
133
228
  message,
134
229
  severity: level,
135
230
  properties
136
231
  });
137
232
  }
138
- function logEvent(publisher2, event, region, status, payload, id) {
139
- if (!process.env["DisableMetrics"]) {
140
- const metricRegion = process.env["DisableMetricRegionLogging"] ? "default" : region;
141
- const name = status >= 200 && status < 400 ? "DispatchSuccess" : "DispatchFailure";
142
- logAggregatedMetric("metrics", name, `${metricRegion}:${publisher2}:${event}`);
233
+ function logEvent(publisher2, event, region, status, payload, id, client) {
234
+ if (process.env.DisableMetrics !== "true" && status >= 200 && status < 400) {
235
+ const metricRegion = process.env.DisableMetricRegionLogging === "true" ? "default" : region;
236
+ logAggregatedMetric(
237
+ {
238
+ prefix: "events",
239
+ dimensions: `${metricRegion}:${publisher2}:${event}`,
240
+ name: "Dispatch"
241
+ },
242
+ client
243
+ );
143
244
  }
144
- ;
145
- if (!process.env["DisableTraces"]) {
245
+ if (process.env.DisableTraces !== "true") {
146
246
  let properties = {
147
247
  publisher: publisher2,
148
248
  event,
@@ -153,23 +253,29 @@ function logEvent(publisher2, event, region, status, payload, id) {
153
253
  };
154
254
  const message = status >= 200 && status < 400 ? "Event dispatched to platform" : "Event dispatch failed";
155
255
  properties = removeUndefined(properties);
156
- logMessage(1, message, properties);
256
+ logMessage(1, message, properties, client);
157
257
  }
158
- ;
159
258
  }
160
- function logException(exception, publisher2) {
161
- if (!process.env["DisableMetrics"]) {
162
- const message = exception.message.split(".")[0]?.substring(0, 100).replace(/:/g, "");
163
- logAggregatedMetric("error", exception.name, `${publisher2 ?? "Other"}:${message}`);
259
+ function logException(exception, publisher2, errorType = "InternalError", client) {
260
+ if (process.env.DisableMetrics !== "true") {
261
+ logAggregatedMetric(
262
+ {
263
+ prefix: "errors",
264
+ dimensions: publisher2 ?? "Other",
265
+ name: errorType
266
+ },
267
+ client
268
+ );
164
269
  }
165
- ;
166
- if (!process.env["DisableTraces"]) {
167
- aiClient?.trackException({ exception });
270
+ if (process.env.DisableTraces !== "true") {
271
+ (client ?? aiClient)?.trackException({
272
+ exception,
273
+ properties: { publisher: publisher2, errorType }
274
+ });
168
275
  }
169
- ;
170
276
  }
171
- function logMilestone(name, value) {
172
- logAggregatedMetric("milestones", String(value), name);
277
+ function logMilestone(name, client) {
278
+ logAggregatedMetric({ prefix: "milestones", name }, client);
173
279
  }
174
280
  function removeUndefined(originalValue) {
175
281
  if (originalValue instanceof Array) {
@@ -310,29 +416,21 @@ async function handlePlatformRequest({
310
416
  // eslint-disable-next-line @typescript-eslint/naming-convention
311
417
  headers: { ...requestOptions.headers }
312
418
  };
313
- let rawPlatformResponse;
314
- try {
315
- rawPlatformResponse = await fetch(fullUrl, fetchRequestOptions);
316
- } catch (e) {
317
- logEvent(
318
- source,
319
- event.event,
320
- event.region,
321
- 0,
322
- requestOptions.method === "POST" ? JSON.stringify(requestOptions.body) : query,
323
- event.id
324
- );
325
- throw e;
419
+ const rawPlatformResponse = await fetch(fullUrl, fetchRequestOptions);
420
+ if (process.env.PUBLISHER_TESTURL) {
421
+ await handleTestRequest({
422
+ fetchRequestOptions,
423
+ fullUrl,
424
+ query,
425
+ rawPlatformResponse
426
+ });
326
427
  }
327
- if (rawPlatformResponse) {
328
- if (process.env.PUBLISHER_TESTURL) {
329
- await handleTestRequest({
330
- fetchRequestOptions,
331
- fullUrl,
332
- query,
333
- rawPlatformResponse
334
- });
335
- }
428
+ if (!rawPlatformResponse.ok) {
429
+ throw DestinationError.fromResponse(
430
+ `HTTP Error code: ${rawPlatformResponse.status}, event: ${event.event}, region: ${event.region}, body: ${await rawPlatformResponse.text()}`,
431
+ rawPlatformResponse.status
432
+ );
433
+ } else {
336
434
  logEvent(
337
435
  source,
338
436
  event.event,
@@ -341,11 +439,6 @@ async function handlePlatformRequest({
341
439
  requestOptions.method === "POST" ? JSON.stringify(requestOptions.body) : query,
342
440
  event.id
343
441
  );
344
- if (!rawPlatformResponse.ok) {
345
- throw new Error(
346
- `HTTP Error code: ${rawPlatformResponse.status}, event: ${event.event}, region: ${event.region}, body: ${await rawPlatformResponse.text()}`
347
- );
348
- }
349
442
  }
350
443
  }
351
444
  async function handleTestRequest(params) {
@@ -373,7 +466,7 @@ function formatError(error) {
373
466
  if (error instanceof Error) {
374
467
  formattedError = error;
375
468
  if (error.cause) {
376
- formattedError.message = `${error.message} Cause: ${error.cause.toString()}`;
469
+ formattedError.message = `${error.message} Cause: ${String(error.cause)}`;
377
470
  } else {
378
471
  formattedError.message = error.message;
379
472
  }
@@ -617,13 +710,14 @@ async function defaultPublisher(azureFunctionContext, serviceBusMessage, source,
617
710
  if (result.status === "rejected") {
618
711
  if (result.reason instanceof Error) {
619
712
  const formattedError = formatError(result.reason);
620
- logException(new Error(formattedError.message), source);
713
+ const errorType = result.reason instanceof DestinationError ? result.reason.metricType : "InternalError";
714
+ logException(formattedError, source, errorType);
621
715
  throw formattedError;
622
716
  } else {
623
717
  const formattedError = formatError(
624
718
  typeof result.reason === "object" ? JSON.stringify(result.reason) : result.reason
625
719
  );
626
- logException(new Error(formattedError.message), source);
720
+ logException(formattedError, source, "InternalError");
627
721
  throw formattedError;
628
722
  }
629
723
  }
@@ -879,17 +973,17 @@ var googleAds = {
879
973
  error = responseJson.error.message;
880
974
  } else {
881
975
  status = 200;
976
+ logEvent(
977
+ this.source,
978
+ event.event,
979
+ event.region,
980
+ status,
981
+ requestOptions.body,
982
+ event.id
983
+ );
882
984
  }
883
- logEvent(
884
- this.source,
885
- event.event,
886
- event.region,
887
- status,
888
- requestOptions.body,
889
- event.id
890
- );
891
985
  if (error) {
892
- throw new Error(error);
986
+ throw DestinationError.fromResponse(error, response.status);
893
987
  }
894
988
  },
895
989
  async getToken(config) {
@@ -920,7 +1014,10 @@ var googleAds = {
920
1014
  }
921
1015
  );
922
1016
  if (!tokenResponse.ok) {
923
- throw new Error("Access token fetch failed");
1017
+ throw DestinationError.fromResponse(
1018
+ "Access token fetch failed",
1019
+ tokenResponse.status
1020
+ );
924
1021
  }
925
1022
  const parsedTokenResponse = await tokenResponse.json();
926
1023
  const createdAt = Date.now();
@@ -1038,17 +1135,17 @@ var microsoftAds = {
1038
1135
  error = message;
1039
1136
  } else {
1040
1137
  status = 200;
1138
+ logEvent(
1139
+ this.source,
1140
+ event.event,
1141
+ event.region,
1142
+ status,
1143
+ requestOptions.body,
1144
+ event.id
1145
+ );
1041
1146
  }
1042
- logEvent(
1043
- this.source,
1044
- event.event,
1045
- event.region,
1046
- status,
1047
- requestOptions.body,
1048
- event.id
1049
- );
1050
1147
  if (error) {
1051
- throw new Error(error);
1148
+ throw DestinationError.fromResponse(error, response.status);
1052
1149
  }
1053
1150
  } else {
1054
1151
  throw new Error("Invalid config for platform " + this.source);
@@ -1079,7 +1176,10 @@ var microsoftAds = {
1079
1176
  }
1080
1177
  );
1081
1178
  if (!tokenResponse.ok) {
1082
- throw new Error("Access token fetch failed");
1179
+ throw DestinationError.fromResponse(
1180
+ "Access token fetch failed",
1181
+ tokenResponse.status
1182
+ );
1083
1183
  }
1084
1184
  const parsedTokenResponse = await tokenResponse.json();
1085
1185
  const createdAt = Date.now();
@@ -1219,6 +1319,8 @@ var publisher = {
1219
1319
  0 && (module.exports = {
1220
1320
  DefaultPublisher,
1221
1321
  broker,
1322
+ createAppInsightsClient,
1323
+ createRedisClient,
1222
1324
  publisher,
1223
1325
  testUtils,
1224
1326
  utils
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhubcloud/tms_core",
3
- "version": "3.8.0-beta.0",
3
+ "version": "3.8.0-beta.10",
4
4
  "description": "Core function for mHub Cloud TMS publishers",
5
5
  "homepage": "https://mhubcloud.com/",
6
6
  "license": "Apache 2.0",